Procházet zdrojové kódy

fix:新增自定义表格

Roc před 1 rokem
rodič
revize
6fc581eecb

+ 37 - 9
controllers/excel_info.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"hongze/hongze_chart_lib/models"
 	"hongze/hongze_chart_lib/models/response"
+	"hongze/hongze_chart_lib/services/data"
 	"hongze/hongze_chart_lib/services/excel"
 	"hongze/hongze_chart_lib/utils"
 	"time"
@@ -64,20 +65,47 @@ func (this *ExcelInfoController) GetTableDetail() {
 		br.ErrMsg = "获取表格表信息失败,Err:" + err.Error()
 		return
 	}
-	luckySheetData, err := excel.GetLuckySheetData(excelInfo.Content)
-	if err != nil {
-		fmt.Println("err:", err)
-		return
-	}
-	tableData, err := luckySheetData.GetTableDataByLuckySheetDataStr()
-	if err != nil {
-		fmt.Println("err:", err)
-		return
+	var tableData excel.TableData
+	if excelInfo.Source == 1 {
+		luckySheetData, err := excel.GetLuckySheetData(excelInfo.Content)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取excel数据失败,Err:" + err.Error()
+			return
+		}
+		tableData, err = luckySheetData.GetTableDataByLuckySheetDataStr()
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "转换成table失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		var tableDataConfig data.TableDataConfig
+		err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
+			return
+		}
+		result, err := data.GetDataByTableDataConfig(tableDataConfig)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取最新的表格数据失败,Err:" + err.Error()
+			return
+		}
+		tableData, err = excel.GetTableDataByCustomData(excelInfo.ExcelType, result)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "转换成table失败,Err:" + err.Error()
+			return
+		}
 	}
 
 	tableData = excel.HandleTableCell(tableData)
 
 	resp.TableInfo = tableData
+	resp.Source = excelInfo.Source
+	resp.ExcelType = excelInfo.ExcelType
 	resp.ExcelName = excelInfo.ExcelName
 	resp.ExcelImage = excelInfo.ExcelImage
 	resp.UniqueCode = excelInfo.UniqueCode

+ 4 - 0
models/excel_info.go

@@ -10,6 +10,8 @@ import (
 // ExcelInfo excel表格详情表
 type ExcelInfo struct {
 	ExcelInfoId     int       `orm:"column(excel_info_id);pk"`
+	Source          int       `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType       int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
 	ExcelName       string    `description:"表格名称"`
 	UniqueCode      string    `description:"表格唯一编码"`
 	ExcelClassifyId int       `description:"表格分类id"`
@@ -155,6 +157,8 @@ func UpdateExcelInfoSortByClassifyId(classifyId, nowSort, prevExcelInfoId int, u
 
 type ExcelInfoView struct {
 	ExcelInfoId     int       `orm:"column(excel_info_id);pk"`
+	Source          int       `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType       int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
 	ExcelName       string    `description:"表格名称"`
 	UniqueCode      string    `description:"表格唯一编码"`
 	ExcelClassifyId int       `description:"表格分类id"`

+ 32 - 0
models/request/excel_info.go

@@ -0,0 +1,32 @@
+package request
+
+type TableDataReq struct {
+	EdbInfoIdList []int             `description:"指标id列表,从左至右,从上到下的顺序"`
+	Sort          int               `description:"日期排序,1:倒序,2:正序"`
+	Data          []EdbInfoData     `description:"数据列表"`
+	TextRowData   [][]ManualDataReq `description:"文本列表"`
+}
+
+type EdbInfoData struct {
+	EdbInfoId    int             `description:"指标ID"`
+	Tag          string          `description:"标签"`
+	EdbName      string          `description:"指标名称"`
+	EdbAliasName string          `description:"指标别名"`
+	Frequency    string          `description:"频度"`
+	Unit         string          `description:"单位"`
+	Data         []ManualDataReq `description:"单元格数据列表"`
+}
+
+type ManualDataReq struct {
+	DataType            int               `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算"`
+	DataTime            string            `description:"所属日期"`
+	DataTimeType        int               `description:"日期类型,1:实际日期;2:未来日期"`
+	ShowValue           string            `description:"展示值"`
+	Value               string            `description:"实际值(计算公式)"`
+	RelationEdbInfoList []RelationEdbInfo `description:"关联指标(计算公式中关联的指标,用于计算的时候去匹配)"`
+}
+
+type RelationEdbInfo struct {
+	Tag string `description:"指标标签"`
+	Row string `description:"第几行"`
+}

+ 47 - 1
models/response/excel_info.go

@@ -1,12 +1,58 @@
 package response
 
-import "hongze/hongze_chart_lib/services/excel"
+import (
+	"hongze/hongze_chart_lib/models"
+	"hongze/hongze_chart_lib/models/request"
+	"hongze/hongze_chart_lib/services/excel"
+	"time"
+)
 
 // ExcelTableDetailResp  excel表格详情
 type ExcelTableDetailResp struct {
 	//ChartInfo   *ChartInfo
 	UniqueCode string `description:"表格唯一code"`
+	Source     int    `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType  int    `description:"表格类型,1:指标列,2:日期列,默认:1"`
 	ExcelImage string `description:"表格截图"`
 	ExcelName  string `description:"表格名称"`
 	TableInfo  excel.TableData
 }
+
+// TableCellResp 单元格
+type TableCellResp struct {
+	DataType  int    `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算"`
+	DataTime  string `description:"所属日期"`
+	ShowValue string `description:"展示的值"`
+	Value     string `description:"实际值(计算公式)"`
+}
+
+type TableDataItem struct {
+	EdbInfoId int                     `description:"指标id"`
+	Data      []request.ManualDataReq `description:"数据列表"`
+}
+
+// TableDetailResp  excel表格详情
+type TableDetailResp struct {
+	ExcelInfo models.ExcelInfo     `description:"表格基础信息"`
+	TableData request.TableDataReq `description:"表格内容"`
+}
+
+// ExcelInfoDetail excel表格详情(前端使用)
+type ExcelInfoDetail struct {
+	ExcelInfoId     int                  `orm:"column(excel_info_id);pk"`
+	Source          int                  `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType       int                  `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName       string               `description:"表格名称"`
+	UniqueCode      string               `description:"表格唯一编码"`
+	ExcelClassifyId int                  `description:"表格分类id"`
+	SysUserId       int                  `description:"操作人id"`
+	SysUserRealName string               `description:"操作人真实姓名"`
+	Content         string               `description:"表格内容"`
+	ExcelImage      string               `description:"表格图片"`
+	FileUrl         string               `description:"表格下载地址"`
+	Sort            int                  `description:"排序字段,数字越小越排前面"`
+	IsDelete        int                  `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime      time.Time            `description:"最近修改日期"`
+	CreateTime      time.Time            `description:"创建日期"`
+	TableData       request.TableDataReq `description:"表格内容"`
+}

+ 1046 - 0
services/data/excel_info.go

@@ -0,0 +1,1046 @@
+package data
+
+import (
+	"errors"
+	"fmt"
+	"github.com/shopspring/decimal"
+	"github.com/yidane/formula"
+	"hongze/hongze_chart_lib/models"
+	"hongze/hongze_chart_lib/models/data_manage"
+	"hongze/hongze_chart_lib/models/request"
+	"hongze/hongze_chart_lib/utils"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// GetFirstEdbDataList 获取第一列的数据
+func GetFirstEdbDataList(edbInfo *data_manage.EdbInfo, num int) (resultDataList []request.ManualDataReq, err error) {
+	var dataList []*models.EdbDataList
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, err = models.GetEdbDataList(edbInfo.Source, edbInfo.EdbInfoId, ``, ``)
+	case 1:
+		_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
+
+		return
+	}
+
+	// 获取需要的期数
+	lenData := len(dataList)
+	if num > lenData {
+		num = lenData
+	}
+
+	for i := 1; i <= num; i++ {
+		resultDataList = append(resultDataList, request.ManualDataReq{
+			DataType:     1,
+			DataTime:     dataList[lenData-i].DataTime,
+			ShowValue:    fmt.Sprint(dataList[lenData-i].Value),
+			Value:        fmt.Sprint(dataList[lenData-i].Value),
+			DataTimeType: 1,
+		})
+	}
+
+	return
+}
+
+// GetOtherEdbDataList 获取其他列的数据
+func GetOtherEdbDataList(edbInfo *data_manage.EdbInfo, dateList []string) (resultDataList []request.ManualDataReq, err error) {
+	lenDate := len(dateList)
+	if lenDate <= 0 {
+		return
+	}
+	sortDateList := dateList
+	baseDateList := utils.StrArr{}
+	baseDateList = append(baseDateList, sortDateList...)
+	sort.Sort(baseDateList)
+	sortDateList = append([]string{}, baseDateList...)
+
+	endDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[0], time.Local)
+	if err != nil {
+		return
+	}
+
+	firstDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[lenDate-1], time.Local)
+	if err != nil {
+		return
+	}
+
+	var dataList []*models.EdbDataList
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, err = models.GetEdbDataList(edbInfo.Source, edbInfo.EdbInfoId, ``, ``)
+	case 1:
+		_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
+
+		return
+	}
+
+	// 获取日期内的数据(包含开始日期前一个日期,以及 结束日期后一个日期,目的为了做空日期时的 插值法兼容)
+	baseDataList := make([]*models.EdbDataList, 0)
+	var lastData *models.EdbDataList
+	var isInsert bool
+	for _, data := range dataList {
+		tmpDate := data.DataTime
+		tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if tmpDateTime.Before(firstDateTime) {
+			lastData = data
+			continue
+		}
+
+		// 如果是第一次写入数据
+		if !isInsert && lastData != nil {
+			baseDataList = append(baseDataList, lastData)
+		}
+
+		if tmpDateTime.After(endDateTime) {
+			baseDataList = append(baseDataList, data)
+			break
+		}
+		baseDataList = append(baseDataList, data)
+		isInsert = true
+	}
+
+	// 实际数据的日期map
+	realValMap := make(map[string]string)
+	for _, v := range baseDataList {
+		realValMap[v.DataTime] = v.DataTime
+	}
+
+	// 插值法处理
+	handleDataMap := make(map[string]float64)
+	err = HandleDataByLinearRegression(baseDataList, handleDataMap)
+	if err != nil {
+		return
+	}
+	// 对于不存在的数据做补充
+	for _, date := range sortDateList {
+		dataType := 1
+		if _, ok := realValMap[date]; !ok {
+			dataType = 2
+		}
+		var value, showValue string
+		if tmpVal, ok := handleDataMap[date]; ok {
+			value = fmt.Sprint(tmpVal)
+			showValue = value
+		} else {
+			dataType = 3
+		}
+		resultDataList = append(resultDataList, request.ManualDataReq{
+			DataType:  dataType,
+			DataTime:  date,
+			ShowValue: showValue,
+			Value:     value,
+		})
+	}
+
+	return
+}
+
+// GetFirstHistoryEdbDataList 获取指标的历史的数据
+func GetFirstHistoryEdbDataList(edbInfo *data_manage.EdbInfo, num int, endDate string) (resultDataList []request.ManualDataReq, err error) {
+	endDateTime, err := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+	if err != nil {
+		return
+	}
+
+	var dataList []*models.EdbDataList
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, err = models.GetEdbDataList(edbInfo.Source, edbInfo.EdbInfoId, ``, endDate)
+	case 1:
+		_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, endDate, true)
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
+
+		return
+	}
+
+	// 获取需要的期数
+	lenData := len(dataList)
+	if lenData <= 0 {
+		return
+	}
+	lastData := dataList[lenData-1]
+	lastDataDateTime, err := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local)
+	if err != nil {
+		return
+	}
+	if endDateTime.Equal(lastDataDateTime) || lastDataDateTime.After(endDateTime) {
+		dataList = dataList[:lenData-1]
+		lenData = len(dataList)
+	}
+	if num > lenData {
+		num = lenData
+	}
+
+	for i := 1; i <= num; i++ {
+		resultDataList = append(resultDataList, request.ManualDataReq{
+			DataType:  1,
+			DataTime:  dataList[lenData-i].DataTime,
+			ShowValue: fmt.Sprint(dataList[lenData-i].Value),
+			Value:     fmt.Sprint(dataList[lenData-i].Value),
+		})
+	}
+
+	return
+}
+
+type TableDataConfig struct {
+	EdbInfoIdList    []int                     `description:"指标id列表,从左至右,从上到下的顺序"`
+	Sort             int                       `description:"日期排序,0:倒序,1:正序"`
+	Data             []ManualData              `description:"数据列表"`
+	Num              int                       `description:"实际数据需要列出来的期数"`
+	RemoveDate       []string                  `description:"不展示的日期"`
+	ManualDate       []string                  `description:"手动配置的日期(未来的日期)"`
+	TableEdbInfoList []TableEdbInfo            `description:"表格内指标信息"`
+	TextRowData      [][]request.ManualDataReq `description:"文本列表"`
+}
+
+type TableEdbInfo struct {
+	EdbInfoId    int    `description:"指标ID"`
+	Tag          string `description:"标签"`
+	EdbName      string `description:"指标名称"`
+	EdbAliasName string `description:"指标别名"`
+	Frequency    string `description:"频度"`
+	Unit         string `description:"单位"`
+}
+
+type ManualData struct {
+	DataType            int                       `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算"`
+	DataTime            string                    `description:"所属日期"`
+	DataTimeType        int                       `description:"日期类型,1:实际日期;2:未来日期"`
+	ShowValue           string                    `description:"展示值"`
+	Value               string                    `description:"实际值(计算公式)"`
+	EdbInfoId           int                       `description:"指标id"`
+	Tag                 string                    `description:"下标"`
+	RelationEdbInfoList []request.RelationEdbInfo `description:"关联指标(计算公式中关联的指标,用于计算的时候去匹配)"`
+}
+
+func GetTableDataConfig(reqData request.TableDataReq) (tableDataConfig TableDataConfig, err error) {
+	// 指标数据
+	tableDataConfig.EdbInfoIdList = reqData.EdbInfoIdList
+	tableDataConfig.Sort = reqData.Sort
+
+	// 开始日期
+	var startDate string
+	// A列的指标id
+	var firstEdbInfoId int
+	// 手工操作的数据列
+	manualDataList := make([]ManualData, 0)
+	// 指标配置列表
+	tableEdbInfoList := make([]TableEdbInfo, 0)
+
+	// 第一列的日期map
+	firstDateMap := make(map[string]string)
+	manualDateMap := make(map[string]string)
+
+	for _, v := range reqData.Data {
+		// 指标信息
+		tmpTableEdbInfo := TableEdbInfo{
+			EdbInfoId:    v.EdbInfoId,
+			Tag:          v.Tag,
+			EdbName:      v.EdbName,
+			EdbAliasName: v.EdbAliasName,
+			Frequency:    v.Frequency,
+			Unit:         v.Unit,
+		}
+		tableEdbInfoList = append(tableEdbInfoList, tmpTableEdbInfo)
+
+		// 确定数据A列
+		if v.Tag == "A" {
+			firstEdbInfoId = v.EdbInfoId
+			lenData := len(v.Data)
+			if lenData <= 0 {
+				err = errors.New("A列不能为空")
+				return
+			}
+			index := 0
+			if reqData.Sort == 1 {
+				// 倒序
+				index = lenData - 1
+			}
+
+			startDate = v.Data[index].DataTime
+
+			// 存在的日期列表
+			for _, data := range v.Data {
+				firstDateMap[data.DataTime] = data.DataTime
+
+				if data.DataTimeType == 2 {
+					manualDateMap[data.DataTime] = data.DataTime
+				}
+			}
+		}
+
+		for _, data := range v.Data {
+			if data.DataType == 3 || data.DataType == 4 {
+				tmpManualData := ManualData{
+					DataType:            data.DataType,
+					DataTime:            data.DataTime,
+					DataTimeType:        data.DataTimeType,
+					ShowValue:           data.ShowValue,
+					Value:               data.Value,
+					EdbInfoId:           v.EdbInfoId,
+					Tag:                 v.Tag,
+					RelationEdbInfoList: data.RelationEdbInfoList,
+				}
+				if data.DataType == 4 {
+					tmpManualData.ShowValue = ``
+				}
+				manualDataList = append(manualDataList, tmpManualData)
+			}
+		}
+	}
+
+	// 实际期数
+	var num int
+	removeDate := make([]string, 0)
+
+	// 获取期数
+	{
+		firstDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		edbInfo, tmpErr := data_manage.GetEdbInfoById(firstEdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		var firstDataList []*models.EdbDataList
+		switch edbInfo.EdbInfoType {
+		case 0:
+			firstDataList, err = models.GetEdbDataList(edbInfo.Source, edbInfo.EdbInfoId, ``, ``)
+		case 1:
+			_, firstDataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+		default:
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
+			return
+		}
+
+		// 获取日期内的数据(包含开始日期前一个日期,以及 结束日期后一个日期,目的为了做空日期时的 插值法兼容)
+		baseDataList := make([]*models.EdbDataList, 0)
+		for _, data := range firstDataList {
+			tmpDate := data.DataTime
+			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			if tmpDateTime.Before(firstDateTime) {
+				continue
+			}
+			baseDataList = append(baseDataList, data)
+		}
+
+		// 开始日期到现在的实际期数
+		num = len(baseDataList)
+
+		// 筛选出需要删除的日期
+		for _, tmpData := range baseDataList {
+			//firstDateMap{}
+			if _, ok := firstDateMap[tmpData.DataTime]; !ok {
+				removeDate = append(removeDate, tmpData.DataTime)
+			}
+		}
+	}
+
+	tableDataConfig.Num = num
+	tableDataConfig.RemoveDate = removeDate
+	tableDataConfig.Data = manualDataList
+	tableDataConfig.TableEdbInfoList = tableEdbInfoList
+	tableDataConfig.TextRowData = reqData.TextRowData
+
+	return
+}
+
+func GetDataByTableDataConfig(tableDataConfig TableDataConfig) (resultResp request.TableDataReq, err error) {
+	// 没有选择指标的情况下,直接返回吧
+	if len(tableDataConfig.EdbInfoIdList) <= 0 {
+		return
+	}
+
+	// 实际期数没有的情况下,直接返回吧
+	if tableDataConfig.Num <= 0 {
+		return
+	}
+
+	// 获取所有的指标信息
+	edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	edbInfoIdList := make([]int, 0)
+	// 标签与指标id的map
+	tagEdbInfoIdMap := make(map[string]int)
+	{
+		for _, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
+			edbInfoIdList = append(edbInfoIdList, tableEdbInfo.EdbInfoId)
+			tagEdbInfoIdMap[tableEdbInfo.Tag] = tableEdbInfo.EdbInfoId
+		}
+		edbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdList)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range edbInfoList {
+			edbInfoMap[v.EdbInfoId] = v
+		}
+	}
+
+	// 寻找A列的数据列表
+	firstEdbInfo, ok := edbInfoMap[tableDataConfig.EdbInfoIdList[0]]
+	if !ok {
+		err = errors.New("找不到A列指标")
+		return
+	}
+	baseFirstEdbInfoDataList, err := GetFirstEdbDataList(firstEdbInfo, tableDataConfig.Num)
+	if err != nil {
+		return
+	}
+	// A列找不到数据,那么就直接返回吧
+	if len(baseFirstEdbInfoDataList) <= 0 {
+		return
+	}
+
+	firstEdbInfoDataList := make([]request.ManualDataReq, 0)
+	if tableDataConfig.RemoveDate != nil && len(tableDataConfig.RemoveDate) > 0 {
+		for _, v := range baseFirstEdbInfoDataList {
+			if utils.InArrayByStr(tableDataConfig.RemoveDate, v.DataTime) {
+				continue
+			}
+			firstEdbInfoDataList = append(firstEdbInfoDataList, v)
+		}
+	} else {
+		firstEdbInfoDataList = baseFirstEdbInfoDataList
+	}
+	if len(firstEdbInfoDataList) <= 0 {
+		return
+	}
+	// 实际数据的最后一天
+	lastRealDateTime, err := time.ParseInLocation(utils.FormatDate, firstEdbInfoDataList[0].DataTime, time.Local)
+	if err != nil {
+		return
+	}
+
+	dateMap := make(map[string]string)
+	dateList := make([]string, 0)
+	edbInfoIdDateDataMap := make(map[int]map[string]request.ManualDataReq)
+	firstDateDataMap := make(map[string]request.ManualDataReq)
+	for _, v := range firstEdbInfoDataList {
+		dateList = append(dateList, v.DataTime)
+		dateMap[v.DataTime] = v.DataTime
+		firstDateDataMap[v.DataTime] = v
+	}
+
+	// 将手工数据的日期填补进去(未来的日期,过去的就不管了)
+	for _, manualData := range tableDataConfig.Data {
+		if !utils.InArrayByStr(dateList, manualData.DataTime) {
+			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, manualData.DataTime, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			if tmpDateTime.After(lastRealDateTime) {
+				dateList = append(dateList, manualData.DataTime)
+			}
+		}
+	}
+
+	edbInfoIdDateDataMap[firstEdbInfo.EdbInfoId] = firstDateDataMap
+
+	for k, edbInfoId := range tableDataConfig.EdbInfoIdList {
+		if k == 0 {
+			continue
+		}
+
+		tmpEdbInfo, ok := edbInfoMap[edbInfoId]
+		if !ok {
+			err = errors.New("找不到A列指标")
+			return
+		}
+		otherDataList, tmpErr := GetOtherEdbDataList(tmpEdbInfo, dateList)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		tmpDateDataMap := make(map[string]request.ManualDataReq)
+		for _, v := range otherDataList {
+			tmpDateDataMap[v.DataTime] = v
+		}
+		edbInfoIdDateDataMap[tmpEdbInfo.EdbInfoId] = tmpDateDataMap
+	}
+
+	for _, v := range tableDataConfig.Data {
+		tmpDate := v.DataTime
+		if _, ok := dateMap[tmpDate]; !ok {
+			dateMap[v.DataTime] = tmpDate
+		}
+
+		edbInfoIdDateData, ok := edbInfoIdDateDataMap[v.EdbInfoId]
+		if !ok {
+			edbInfoIdDateData = make(map[string]request.ManualDataReq)
+		}
+
+		// 判断是否存在该日期的数据(不存在,那么插入数据吧,存在就不管了)
+		if _, ok = edbInfoIdDateData[tmpDate]; !ok {
+			edbInfoIdDateData[tmpDate] = request.ManualDataReq{
+				DataType:  v.DataType,
+				DataTime:  v.DataTime,
+				ShowValue: v.ShowValue,
+				Value:     v.Value,
+			}
+		}
+		edbInfoIdDateDataMap[v.EdbInfoId] = edbInfoIdDateData
+	}
+
+	// 获取数据的日期排序
+	sortDateTimeList := make([]time.Time, 0)
+	{
+		sortDateList := dateList
+		if tableDataConfig.Sort == 1 {
+			baseDateList := utils.StrArr{}
+			baseDateList = append(baseDateList, sortDateList...)
+			sort.Sort(baseDateList)
+			sortDateList = append([]string{}, baseDateList...)
+		} else {
+			sort.Strings(sortDateList)
+		}
+		for _, v := range sortDateList {
+			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, v, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			sortDateTimeList = append(sortDateTimeList, tmpDateTime)
+		}
+	}
+
+	tableDataMap, textRowListDataResp := handleTable(tagEdbInfoIdMap, lastRealDateTime, sortDateTimeList, edbInfoIdDateDataMap, tableDataConfig.Data, tableDataConfig.TextRowData)
+
+	data := make([]request.EdbInfoData, 0)
+	for _, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
+		tagEdbInfoIdMap[tableEdbInfo.Tag] = tableEdbInfo.EdbInfoId
+
+		manualDataReqList := make([]request.ManualDataReq, 0)
+		tmpEdbInfoData := request.EdbInfoData{
+			EdbInfoId:    tableEdbInfo.EdbInfoId,
+			Tag:          tableEdbInfo.Tag,
+			EdbName:      tableEdbInfo.EdbName,
+			EdbAliasName: tableEdbInfo.EdbAliasName,
+			Frequency:    tableEdbInfo.Frequency,
+			Unit:         tableEdbInfo.Unit,
+			Data:         manualDataReqList,
+		}
+
+		edbInfo, ok := edbInfoMap[tableEdbInfo.EdbInfoId]
+		if ok {
+			tmpEdbInfoData.EdbName = edbInfo.EdbName
+			tmpEdbInfoData.Frequency = edbInfo.Frequency
+			tmpEdbInfoData.Unit = edbInfo.Unit
+		}
+
+		for index, dateTime := range sortDateTimeList {
+			dataTimeType := 1
+			if dateTime.After(lastRealDateTime) {
+				dataTimeType = 2
+			}
+			tmpDateTimeStr := dateTime.Format(utils.FormatDate)
+
+			rowData, ok := tableDataMap[index+1]
+			if !ok {
+				manualDataReqList = append(manualDataReqList, request.ManualDataReq{
+					DataType:            3,
+					DataTime:            tmpDateTimeStr,
+					DataTimeType:        dataTimeType,
+					ShowValue:           "",
+					Value:               "",
+					RelationEdbInfoList: nil,
+				})
+				continue
+			}
+
+			tmpData, ok := rowData[tableEdbInfo.Tag]
+			if !ok {
+				manualDataReqList = append(manualDataReqList, request.ManualDataReq{
+					DataType:            3,
+					DataTime:            tmpDateTimeStr,
+					DataTimeType:        dataTimeType,
+					ShowValue:           "",
+					Value:               "",
+					RelationEdbInfoList: nil,
+				})
+				continue
+			}
+
+			tmpData.DataTimeType = dataTimeType
+			manualDataReqList = append(manualDataReqList, tmpData)
+		}
+
+		tmpEdbInfoData.Data = manualDataReqList
+
+		data = append(data, tmpEdbInfoData)
+	}
+
+	resultResp = request.TableDataReq{
+		EdbInfoIdList: edbInfoIdList,
+		Sort:          tableDataConfig.Sort,
+		TextRowData:   textRowListDataResp,
+		Data:          data,
+	}
+
+	return
+}
+
+func handleTable(tagEdbInfoIdMap map[string]int, lastRealDateTime time.Time, sortDateTimeList []time.Time, edbInfoIdDateDataMap map[int]map[string]request.ManualDataReq, manualDataList []ManualData, textRowData [][]request.ManualDataReq) (tableDataMap map[int]map[string]request.ManualDataReq, textRowListDataResp [][]request.ManualDataReq) {
+	tagList := make([]string, 0)
+	for tag := range tagEdbInfoIdMap {
+		tagList = append(tagList, tag)
+	}
+	sort.Strings(tagList)
+
+	tableDataMap = make(map[int]map[string]request.ManualDataReq) //行、列数据
+
+	// 日期与行的关系
+	dateIndexMap := make(map[string]int)
+
+	for k, dateTime := range sortDateTimeList {
+		rowDataMap := make(map[string]request.ManualDataReq)
+
+		dataTimeType := 1
+		if dateTime.After(lastRealDateTime) {
+			dataTimeType = 2
+		}
+
+		tmpDateTimeStr := dateTime.Format(utils.FormatDate)
+		dateIndexMap[tmpDateTimeStr] = k + 1
+
+		for _, tag := range tagList {
+			edbInfoId, ok := tagEdbInfoIdMap[tag]
+			if !ok { // 没有找到该指标的映射关系,那么就用空串填补
+				rowDataMap[tag] = request.ManualDataReq{
+					DataType:            3,
+					DataTime:            tmpDateTimeStr,
+					DataTimeType:        dataTimeType,
+					ShowValue:           "",
+					Value:               "",
+					RelationEdbInfoList: nil,
+				}
+				continue
+			}
+
+			// 获取指标的数据map
+			dateDataMap, ok := edbInfoIdDateDataMap[edbInfoId]
+			if !ok { // 没有找到该指标的数据,那么就用空串填补
+				rowDataMap[tag] = request.ManualDataReq{
+					DataType:            3,
+					DataTime:            tmpDateTimeStr,
+					DataTimeType:        dataTimeType,
+					ShowValue:           "",
+					Value:               "",
+					RelationEdbInfoList: nil,
+				}
+				continue
+			}
+
+			// 获取指标该日期的数据
+			tmpData, ok := dateDataMap[tmpDateTimeStr]
+			if !ok { // 该指标没有找到对应日期的数据,那么就用空串填补
+				rowDataMap[tag] = request.ManualDataReq{
+					DataType:            3,
+					DataTime:            tmpDateTimeStr,
+					DataTimeType:        dataTimeType,
+					ShowValue:           "",
+					Value:               "",
+					RelationEdbInfoList: nil,
+				}
+				continue
+			}
+			tmpData.DataTimeType = dataTimeType
+			rowDataMap[tag] = tmpData
+		}
+		tableDataMap[k+1] = rowDataMap
+	}
+
+	// 替换手工设置的数据
+	for _, manualData := range manualDataList {
+		// 找不到该日期,说明这日期过期了,不处理
+		index, ok := dateIndexMap[manualData.DataTime]
+		if !ok {
+			continue
+		}
+
+		// 获取对应行的数据
+		rowDataMap, ok := tableDataMap[index]
+		if !ok {
+			continue
+		}
+
+		// 找到对应的单元格
+		tmpData, ok := rowDataMap[manualData.Tag]
+		if !ok {
+			continue
+		}
+
+		// 如果该单元格实际有数据,或者插值法补充了数据的话,那么就不用手动填入的数据
+		if tmpData.DataType == 1 || tmpData.DataType == 2 {
+			continue
+		}
+
+		// 手工填写的数字
+		if tmpData.DataType == 3 {
+			tmpData.ShowValue = manualData.ShowValue
+			tmpData.Value = manualData.Value
+			tableDataMap[index][manualData.Tag] = tmpData
+
+			//edbInfoIdDateDataMap[manualData.EdbInfoId][manualData.DataTime] = tmpData
+			continue
+		}
+
+		// 公式
+		tmpData.DataType = manualData.DataType
+		tmpData.ShowValue = ``
+		tmpData.Value = manualData.Value
+		tmpData.RelationEdbInfoList = manualData.RelationEdbInfoList
+		tableDataMap[index][manualData.Tag] = tmpData
+
+	}
+
+	// 文本行的列表插入
+	lenTableData := len(tableDataMap)
+
+	// 文本行第一列的数据列表(可能多行)
+	firstColTextRowList := make([]request.ManualDataReq, 0)
+	// 参与计算的文本行列表数据
+	tmpTextRowList := make([][]request.ManualDataReq, 0)
+	for k, textRowList := range textRowData {
+		// 判断列数是否匹配,不匹配的话那么过滤
+		if len(tagList)+1 != len(textRowList) {
+			continue
+		}
+		rowDataMap := make(map[string]request.ManualDataReq)
+		tmpTextRow := make([]request.ManualDataReq, 0)
+		for index, textRow := range textRowList {
+			// 移除第一列,因为第一列是日期列
+			if index == 0 {
+				firstColTextRowList = append(firstColTextRowList, textRow)
+				continue
+			}
+			rowDataMap[tagList[index-1]] = textRow
+			tmpTextRow = append(tmpTextRow, textRow)
+		}
+
+		tableDataMap[lenTableData+k+1] = rowDataMap
+		tmpTextRowList = append(tmpTextRowList, tmpTextRow)
+	}
+
+	// 参与计算的单元格
+	calculateCellMap := make(map[string]string)
+
+	// 计算手工填写的单元格
+	for _, manualData := range manualDataList {
+		// 找不到该日期,说明这日期过期了,不处理
+		index, ok := dateIndexMap[manualData.DataTime]
+		if !ok {
+			continue
+		}
+
+		// 获取对应行的数据
+		rowDataMap, ok := tableDataMap[index]
+		if !ok {
+			continue
+		}
+
+		// 找到对应的单元格
+		colData, ok := rowDataMap[manualData.Tag]
+		if !ok {
+			continue
+		}
+
+		// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
+		if colData.DataType != 4 {
+			continue
+		}
+
+		tagMap := make(map[string]float64)
+		lenRelation := len(colData.RelationEdbInfoList)
+		replaceNum := 0
+		for _, relation := range colData.RelationEdbInfoList {
+			relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
+			valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
+			if tmpErr != nil {
+				continue
+			}
+			tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
+			if tmpErr != nil {
+				continue
+			}
+			tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
+			replaceNum++
+		}
+
+		// 如果替换的数据与关联的不一致,那么就退出当前循环
+		if lenRelation != replaceNum {
+			continue
+		}
+
+		// 计算
+		val, _, err := calculate(colData.Value, tagMap)
+		// 计算失败,退出循环
+		if err != nil {
+			continue
+		}
+		// 重新赋值
+		colData.ShowValue = val
+		tableDataMap[index][manualData.Tag] = colData
+
+	}
+
+	// 计算文本行的单元格
+	for k, textRow := range tmpTextRowList {
+		// 获取对应行的数据
+		index := lenTableData + k + 1
+		rowDataMap, ok := tableDataMap[index]
+		if !ok {
+			continue
+		}
+
+		for colIndex := range textRow {
+			currTag := tagList[colIndex]
+			// 找到对应的单元格
+			colData, ok := rowDataMap[currTag]
+			if !ok {
+				continue
+			}
+
+			// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
+			if colData.DataType != 4 {
+				continue
+			}
+
+			tagMap := make(map[string]float64)
+			lenRelation := len(colData.RelationEdbInfoList)
+			replaceNum := 0
+			for _, relation := range colData.RelationEdbInfoList {
+				relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
+				valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
+				if tmpErr != nil {
+					continue
+				}
+				tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
+				if tmpErr != nil {
+					continue
+				}
+				tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
+				replaceNum++
+			}
+
+			// 如果替换的数据与关联的不一致,那么就退出当前循环
+			if lenRelation != replaceNum {
+				continue
+			}
+
+			// 计算
+			val, _, err := calculate(colData.Value, tagMap)
+			// 计算失败,退出循环
+			if err != nil {
+				continue
+			}
+			// 重新赋值
+			colData.ShowValue = val
+			tableDataMap[index][currTag] = colData
+		}
+
+	}
+
+	// 计算文本行第一列的数据值(多行)
+	for k, colData := range firstColTextRowList {
+		// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
+		if colData.DataType != 4 {
+			continue
+		}
+
+		tagMap := make(map[string]float64)
+		lenRelation := len(colData.RelationEdbInfoList)
+		replaceNum := 0
+		for _, relation := range colData.RelationEdbInfoList {
+			relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
+			valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
+			if tmpErr != nil {
+				continue
+			}
+			tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
+			if tmpErr != nil {
+				continue
+			}
+			tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
+			replaceNum++
+		}
+
+		// 如果替换的数据与关联的不一致,那么就退出当前循环
+		if lenRelation != replaceNum {
+			continue
+		}
+
+		// 计算
+		val, _, err := calculate(colData.Value, tagMap)
+		// 计算失败,退出循环
+		if err != nil {
+			continue
+		}
+		// 重新赋值
+		colData.ShowValue = val
+		firstColTextRowList[k] = colData
+	}
+
+	{
+		// 文本行的数据处理返回
+		textRowListDataResp = make([][]request.ManualDataReq, 0)
+		newLenTableDataMap := len(tableDataMap)
+		// 文本行的第一行所在的位置
+		firstTextRow := lenTableData + 1
+		for i := firstTextRow; i <= newLenTableDataMap; i++ {
+			textRowDataResp := make([]request.ManualDataReq, 0)
+
+			textRowDataResp = append(textRowDataResp, firstColTextRowList[i-firstTextRow])
+			for _, tmpTag := range tagList {
+				textRowDataResp = append(textRowDataResp, tableDataMap[i][tmpTag])
+			}
+			textRowListDataResp = append(textRowListDataResp, textRowDataResp)
+		}
+
+	}
+	return
+}
+
+// getCalculateValue 获取公式计算的结果
+func getCalculateValue(tableDataMap map[int]map[string]request.ManualDataReq, tag, row string, calculateCellMap map[string]string) (val string, err error) {
+	rowInt, err := strconv.Atoi(row)
+	if err != nil {
+		return
+	}
+
+	// 单元格的标签名
+	cellTagName := strings.ToUpper(tag) + row
+	val, ok := calculateCellMap[cellTagName]
+	if ok {
+		return
+	}
+
+	// 查找行数据
+	rowData, ok := tableDataMap[rowInt]
+	if !ok {
+		err = errors.New("查找" + row + "行的数据失败")
+		return
+	}
+
+	// 查找单元格数据
+	colData, ok := rowData[tag]
+	if !ok {
+		err = errors.New("查找单元格" + tag + row + "的数据失败")
+		return
+	}
+
+	// 如果不是计算单元格
+	if colData.DataType != 4 {
+		val = colData.ShowValue
+		return
+	}
+
+	// 如果是计算单元格
+	calculateCellMap[cellTagName] = ``
+
+	tagMap := make(map[string]float64)
+	for _, relation := range colData.RelationEdbInfoList {
+		relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
+		valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
+	}
+
+	// 计算
+	val, _, err = calculate(colData.Value, tagMap)
+	if err != nil {
+		return
+	}
+	// 重新赋值
+	colData.ShowValue = val
+	tableDataMap[rowInt][tag] = colData
+	calculateCellMap[cellTagName] = val
+
+	return
+}
+
+// calculate 公式计算
+func calculate(calculateFormula string, TagMap map[string]float64) (calVal, errMsg string, err error) {
+	if calculateFormula == "" {
+		errMsg = "公式异常"
+		err = errors.New(errMsg)
+		return
+	}
+	calculateFormula = strings.TrimPrefix(calculateFormula, "=")
+	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
+	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
+	calculateFormula = strings.Replace(calculateFormula, ",", ",", -1)
+	calculateFormula = strings.Replace(calculateFormula, "。", ".", -1)
+	calculateFormula = strings.Replace(calculateFormula, "%", "*0.01", -1)
+
+	formulaFormStr := utils.ReplaceFormula(TagMap, calculateFormula)
+	//计算公式异常,那么就移除该指标
+	if formulaFormStr == `` {
+		errMsg = "公式异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	expression := formula.NewExpression(formulaFormStr)
+	calResult, err := expression.Evaluate()
+	if err != nil {
+		errMsg = "计算失败"
+		err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
+		// 分母为0的报错
+		if strings.Contains(err.Error(), "divide by zero") {
+			errMsg = "分母不能为0"
+			err = errors.New("分母不能为空,计算公式:" + formulaFormStr)
+		}
+		return
+	}
+	// 如果计算结果是NAN,那么就提示报错
+	if calResult.IsNan() {
+		errMsg = "计算失败"
+		err = errors.New("计算失败:计算结果是:NAN;formulaStr:" + formulaFormStr)
+		return
+	}
+	calVal = calResult.String()
+
+	// 转Decimal然后四舍五入
+	valDecimal, err := decimal.NewFromString(calVal)
+	if err != nil {
+		errMsg = "计算失败"
+		err = errors.New("计算失败,结果转 Decimal 失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
+		return
+	}
+	calVal = valDecimal.Round(4).String()
+
+	return
+}

+ 200 - 0
services/excel/lucky_sheet.go

@@ -3,6 +3,7 @@ package excel
 import (
 	"encoding/json"
 	"fmt"
+	"hongze/hongze_chart_lib/models/request"
 	"hongze/hongze_chart_lib/utils"
 	"reflect"
 	"sort"
@@ -921,3 +922,202 @@ func (item *LuckySheetData) GetTableDataByLuckySheetDataStrBak() (selfTableData
 
 	return
 }
+
+// GetTableDataByCustomData 通过自定义表格数据获取表格数据
+func GetTableDataByCustomData(excelType int, data request.TableDataReq) (selfTableData TableData, err error) {
+	tableDataList := make([][]LuckySheetDataValue, 0)
+
+	// 指标数
+	lenEdb := len(data.Data)
+	if lenEdb <= 0 {
+		return
+	}
+
+	// 日期数
+	lenCol := len(data.Data[0].Data)
+	if lenCol <= 0 {
+		return
+	}
+	// 指标列:1;指标行:2
+	if excelType == 1 {
+		// 第一行
+		{
+			firstCol := make([]LuckySheetDataValue, 0)
+			firstCol = append(firstCol, LuckySheetDataValue{
+				Value:   "日期",
+				Monitor: "日期",
+				MergeCell: LuckySheetDataConfigMerge{
+					Row:    0, //行数
+					Column: 0, //列数
+					Rs:     2, //合并的行数
+					Cs:     1, //合并的列数
+				},
+			})
+
+			for _, v := range data.Data {
+				edbName := v.EdbName
+				if v.EdbAliasName != `` {
+					edbName = v.EdbAliasName
+				}
+				firstCol = append(firstCol, LuckySheetDataValue{
+					Value:     edbName,
+					Monitor:   edbName,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			tableDataList = append(tableDataList, firstCol)
+		}
+
+		// 第二行
+		{
+			secondCol := make([]LuckySheetDataValue, 0)
+			//secondCol = append(secondCol, LuckySheetDataValue{})
+
+			for _, v := range data.Data {
+				name := v.Unit + " / " + v.Frequency
+				secondCol = append(secondCol, LuckySheetDataValue{
+					Value:     name,
+					Monitor:   name,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			tableDataList = append(tableDataList, secondCol)
+		}
+
+		// 开始数据了
+		{
+			for i := 0; i < lenCol; i++ {
+				dataCol := make([]LuckySheetDataValue, 0)
+
+				// 日期
+				dataCol = append(dataCol, LuckySheetDataValue{
+					Value:     data.Data[0].Data[i].DataTime,
+					Monitor:   data.Data[0].Data[i].DataTime,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+
+				// 数据值
+				for _, v := range data.Data {
+					dataCol = append(dataCol, LuckySheetDataValue{
+						Value:     v.Data[i].Value,
+						Monitor:   v.Data[i].ShowValue,
+						MergeCell: LuckySheetDataConfigMerge{},
+					})
+				}
+
+				tableDataList = append(tableDataList, dataCol)
+			}
+		}
+
+		// 开始文本行了
+		{
+			for _, textColList := range data.TextRowData {
+				dataCol := make([]LuckySheetDataValue, 0)
+				for _, v := range textColList {
+					dataCol = append(dataCol, LuckySheetDataValue{
+						Value:     v.Value,
+						Monitor:   v.ShowValue,
+						MergeCell: LuckySheetDataConfigMerge{},
+					})
+				}
+				tableDataList = append(tableDataList, dataCol)
+			}
+		}
+	} else {
+		// 指标行
+
+		// 第一行
+		{
+			firstCol := make([]LuckySheetDataValue, 0)
+			firstCol = append(firstCol, LuckySheetDataValue{
+				Value:   "日期",
+				Monitor: "日期",
+				MergeCell: LuckySheetDataConfigMerge{
+					Row:    0, //行数
+					Column: 0, //列数
+					Rs:     1, //合并的行数
+					Cs:     2, //合并的列数
+				},
+			})
+
+			// 日期列
+			for _, v := range data.Data[0].Data {
+				firstCol = append(firstCol, LuckySheetDataValue{
+					Value:     v.DataTime,
+					Monitor:   v.DataTime,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			// 文本列
+			for _, textColList := range data.TextRowData {
+				firstCol = append(firstCol, LuckySheetDataValue{
+					Value:     textColList[0].Value,
+					Monitor:   textColList[0].ShowValue,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			tableDataList = append(tableDataList, firstCol)
+		}
+
+		// 日期列+文本列+两列表头(日期这个文案表头)
+		//colLen := lenCol+2+len(data.TextRowData)
+		for i := 0; i < lenEdb; i++ {
+			dataCol := make([]LuckySheetDataValue, 0)
+
+			// 指标信息
+			tmpEdbInfo := data.Data[i]
+
+			// 指标名称
+			{
+				edbName := tmpEdbInfo.EdbName
+				if tmpEdbInfo.EdbAliasName != `` {
+					edbName = tmpEdbInfo.EdbAliasName
+				}
+				dataCol = append(dataCol, LuckySheetDataValue{
+					Value:     edbName,
+					Monitor:   edbName,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			// 指标单位、频度
+			{
+				name := tmpEdbInfo.Unit + " / " + tmpEdbInfo.Frequency
+				dataCol = append(dataCol, LuckySheetDataValue{
+					Value:     name,
+					Monitor:   name,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			// 指标数据列
+			for _, tmpData := range tmpEdbInfo.Data {
+				dataCol = append(dataCol, LuckySheetDataValue{
+					Value:     tmpData.Value,
+					Monitor:   tmpData.ShowValue,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			// 文本列
+			for _, textColList := range data.TextRowData {
+				dataCol = append(dataCol, LuckySheetDataValue{
+					Value:     textColList[i+1].Value,
+					Monitor:   textColList[i+1].ShowValue,
+					MergeCell: LuckySheetDataConfigMerge{},
+				})
+			}
+
+			tableDataList = append(tableDataList, dataCol)
+		}
+
+	}
+
+	selfTableData.TableDataList = tableDataList
+
+	return
+}

+ 34 - 0
utils/calculate.go

@@ -1,9 +1,11 @@
 package utils
 
 import (
+	"fmt"
 	"github.com/gonum/stat"
 	"github.com/shopspring/decimal"
 	"math"
+	"strings"
 )
 
 // Series is a container for a series of data
@@ -167,3 +169,35 @@ func CalculationDecisive(sList []Coordinate) (r2 float64) {
 func CalculateStandardDeviation(data []float64) float64 {
 	return stat.StdDev(data, nil)
 }
+
+func ReplaceFormula(valArr map[string]float64, formulaStr string) string {
+	funMap := getFormulaMap()
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, k, v, -1)
+	}
+
+	replaceCount := 0
+	for tag, val := range valArr {
+		dvStr := fmt.Sprintf("%v", val)
+		formulaStr = strings.Replace(formulaStr, tag, dvStr, -1)
+		replaceCount++
+	}
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, v, k, -1)
+	}
+	return formulaStr
+}
+
+func getFormulaMap() map[string]string {
+	funMap := make(map[string]string)
+	funMap["MAX"] = "[@@]"
+	funMap["MIN"] = "[@!]"
+	funMap["ABS"] = "[@#]"
+	funMap["CEIL"] = "[@$]"
+	funMap["COS"] = "[@%]"
+	funMap["FLOOR"] = "[@^]"
+	funMap["MOD"] = "[@&]"
+	funMap["POW"] = "[@*]"
+	funMap["ROUND"] = "[@(]"
+	return funMap
+}

+ 15 - 0
utils/sort.go

@@ -0,0 +1,15 @@
+package utils
+
+type StrArr []string
+
+func (a StrArr) Len() int {
+	return len(a)
+}
+
+func (a StrArr) Less(i, j int) bool {
+	return a[i] > a[j] // 降序
+}
+
+func (a StrArr) Swap(i, j int) {
+	a[i], a[j] = a[j], a[i]
+}