Browse Source

Merge branch 'feature/eta1.5.6_excel' of eta_server/eta_api into master

xyxie 1 year ago
parent
commit
6dbd2a82f3

+ 50 - 84
controllers/data_manage/edb_info.go

@@ -6,11 +6,13 @@ import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/company"
 	"eta/eta_api/models/data_manage"
+	request2 "eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/models/data_manage/request"
 	"eta/eta_api/models/data_manage/response"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
+	excel2 "eta/eta_api/services/data/excel"
 	"eta/eta_api/services/data_stat"
 	"eta/eta_api/services/elastic"
 	etaTrialService "eta/eta_api/services/eta_trial"
@@ -4447,7 +4449,7 @@ func (this *EdbInfoController) AllEdbInfoByEs() {
 		keyWordArr = append(keyWordArr, newKeyWord...)
 
 		// 普通的搜索
-		total, edbInfoList, err = elastic.SearchEdbInfoData(utils.DATA_INDEX_NAME, keyWord, startSize, pageSize, filterSource, source, -1, ``, noPermissionEdbInfoIdList)
+		total, edbInfoList, err = elastic.SearchEdbInfoData(utils.DATA_INDEX_NAME, keyWord, startSize, pageSize, filterSource, source, -1, frequency, noPermissionEdbInfoIdList)
 	} else {
 		var condition string
 		var pars []interface{}
@@ -4602,7 +4604,7 @@ func (this *EdbInfoController) GetEdbDateData() {
 // @Param   Date   query   string  false       "日期"
 // @Param   Num   query   int  false       "前后几期数据"
 // @Success 200 {object} data_manage.EdbInfoList
-// @router /edb_info/date_data/before_after [get]
+// @router /edb_info/date_data/before_after [post]
 func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -4610,9 +4612,17 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		this.ServeJSON()
 	}()
 
-	edbInfoId, _ := this.GetInt("EdbInfoId")
-	date := this.GetString("Date")
-	num, _ := this.GetInt("Num")
+	requestBody := string(this.Ctx.Input.RequestBody)
+	var req request2.DateDataBeforeAfterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	edbInfoId := req.EdbInfoId
+	currDate := req.Date
+	num := req.Num
 
 	// 默认2期数据
 	if num <= 0 {
@@ -4631,100 +4641,56 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		return
 	}
 
-	// 当前日期
-	var currDate string
-	// 是否查找之后的数据
-	isFindAfter := true
-	if date == `` {
-		currDate = edbInfo.EndDate
-		isFindAfter = false
-		if num <= 0 {
-			num = 4 //默认获取前面的几期数据
-		}
-	}
-
 	dataList := make([]*data_manage.EdbDataList, 0)
-
-	startDate := date
-	// 指定日期的类型
-	dateType := "day"
-	//如果填写的是月度日期
-	if strings.Count(date, "-") == 1 {
-		startDate = date + "-01"
-		dateType = "month"
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, _ = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
+	case 1:
+		_, dataList, _, _, _, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+	default:
+		br.Msg = "指标类型异常!"
+		br.ErrMsg = "指标类型异常,Err:" + strconv.Itoa(edbInfo.EdbInfoType)
+		return
 	}
 
-	resp := data_manage.BeforeAndAfterDateDataResp{
-		List: dataList,
-		Date: "",
-	}
-	// 后面的数据
-	afterList := make([]*data_manage.EdbDataList, 0)
-	if isFindAfter {
-		afterList, err = data.GetEdbBeforeAndAfterDateData(edbInfo, startDate, "", 2, num)
+	if currDate == `` {
+		currDate, err = excel2.GetEdbDateByMoveForward(requestBody, dataList)
 		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
+			br.Msg = "日期前移失败"
+			br.ErrMsg = "日期前移失败,Err:" + err.Error()
 			return
 		}
-
-		lenBeforeList := len(afterList)
-		if lenBeforeList <= 0 {
-			br.Ret = 200
-			br.Success = true
-			br.Msg = "所选指标所选日期无值"
-			br.Data = resp
-			return
-		} else {
-			var dateTimeStr string
-			switch dateType {
-			case "month":
-				dateTime, _ := time.ParseInLocation(utils.FormatDate, afterList[0].DataTime, time.Local)
-				dateTimeStr = dateTime.Format(utils.FormatYearMonthDate)
-			case "day":
-				dateTimeStr = afterList[0].DataTime
-			}
-			currDate = afterList[0].DataTime
-			// 如果对应日期找不到,那么就直接返回吧
-			if dateTimeStr != date {
-				br.Ret = 200
-				br.Success = true
-				br.Msg = "所选指标所选日期无值"
-				br.Data = resp
-				return
+	} else {
+		if strings.Count(currDate, "-") == 1 {
+			currDate = currDate + "-01"
+			// 查找这个月早的时间作为起始时间
+			for _, v := range dataList {
+				if v.DataTime >= currDate {
+					currDate = v.DataTime
+					break
+				}
 			}
 		}
 	}
-
-	// 前面的数据
-	beforeList, err := data.GetEdbBeforeAndAfterDateData(edbInfo, "", currDate, 1, num)
+	currDate, err = excel2.HandleMixTableDateChange(currDate, requestBody)
 	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = fmt.Sprint("获取前面的指数据失败,Err:", err.Error())
+		br.Msg = "日期变换失败"
+		br.ErrMsg = "日期变换失败,Err:" + err.Error()
 		return
 	}
+	list := make([]*data_manage.EdbDataList, 5)
 
-	dataList = append(dataList, beforeList...)
-	// 后面的数据
-	if len(afterList) > 0 {
-		if len(beforeList) > 0 {
-			dataList = append(dataList, afterList[1:]...)
-		} else {
-			dataList = append(dataList, afterList...)
-		}
-	}
-
-	// 数据翻转
-	for i, j := 0, len(dataList)-1; i < j; i, j = i+1, j-1 {
-		dataList[i], dataList[j] = dataList[j], dataList[i]
+	list, err = data.GetEdbBeforeAndAfterDateData(currDate, dataList)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
+		return
 	}
-
-	resp.List = dataList
-	// 前端不传入日期的时候,这个J皮不让返回这个字段,要不然他会颜色标记
-	if date != `` {
-		resp.Date = currDate
+	// 这个日期不存在的话直接返回空数组
+	resp := data_manage.BeforeAndAfterDateDataResp{
+		List: list,
+		Date: currDate,
 	}
-
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 169 - 113
controllers/data_manage/excel/excel_classify.go

@@ -9,6 +9,8 @@ import (
 	response2 "eta/eta_api/models/data_manage/excel/response"
 	excel2 "eta/eta_api/services/data/excel"
 	"eta/eta_api/utils"
+	"fmt"
+	"sort"
 	"strconv"
 	"time"
 )
@@ -43,14 +45,15 @@ func (this *ExcelClassifyController) List() {
 		showUserId = this.SysUser.AdminId
 	}
 
-	// 获取一级分类
-	rootList, err := excel.GetExcelClassifyByParentId(0, source)
-	if err != nil && err.Error() != utils.ErrNoRow() {
+	classifyList, err := excel.GetExcelClassifyBySource(source)
+	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()
 		return
 	}
 
+	// 获取二级分类
+	// 获取三级分类
 	// 根据来源获取所有excel表格(无内容)
 	allExcelInfo, err := excel.GetNoContentExcelInfoAll(source, showUserId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
@@ -63,26 +66,49 @@ func (this *ExcelClassifyController) List() {
 	for _, v := range allExcelInfo {
 		ExcelInfoMap[v.ExcelClassifyId] = append(ExcelInfoMap[v.ExcelClassifyId], v)
 	}
-	//rootChildMap := make(map[int][]*data_manage.ExcelClassifyItems)
-	//for _, v := range classifyAll {
-	//	rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
-	//	if existItems, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
-	//		v.Children = existItems
-	//	} else {
-	//		items := make([]*data_manage.ExcelClassifyItems, 0)
-	//		v.Children = items
-	//	}
-	//}
+	classifyMap := make(map[int][]*excel.ExcelClassifyItems)
+	for _, v := range classifyList {
+		if existItems, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
+			v.Children = existItems
+		}
+	}
+
+	for _, v := range classifyList {
+		if v.ParentId > 0 {
+			classifyMap[v.ParentId] = append(classifyMap[v.ParentId], v)
+		}
+	}
+	// todo 整理第三层
+	//组装三级分类
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 3 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第二层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		// 调用sort.Slice函数,传入切片、比较函数作为参数
+		sort.Slice(subList, func(i, j int) bool { return excel.ExcelClassifyItemBySort(subList[i], subList[j]) })
+		if ok && classify.Level == 2 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第一层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		sort.Slice(subList, func(i, j int) bool { return excel.ExcelClassifyItemBySort(subList[i], subList[j]) })
+		if ok && classify.Level == 1 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
 	nodeAll := make([]*excel.ExcelClassifyItems, 0)
-	for _, v := range rootList {
-		var items []*excel.ExcelClassifyItems
-		if tmpItem, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
-			items = tmpItem
-		} else {
-			items = make([]*excel.ExcelClassifyItems, 0)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			sort.Slice(v.Children, func(i, j int) bool { return excel.ExcelClassifyItemBySort(v.Children[i], v.Children[j]) })
+			nodeAll = append(nodeAll, v)
 		}
-		v.Children = items
-		nodeAll = append(nodeAll, v)
 	}
 	resp := response2.ExcelClassifyListResp{
 		AllNodes: nodeAll,
@@ -110,14 +136,51 @@ func (this *ExcelClassifyController) ExcelClassifyItems() {
 	if source <= 0 {
 		source = utils.EXCEL_DEFAULT
 	}
-	rootList, err := excel.GetExcelClassifyByParentId(0, source)
+	classifyList, err := excel.GetExcelClassifyBySource(source)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()
 		return
 	}
+
+	// 获取二级分类
+	// 获取三级分类
+	classifyMap := make(map[int][]*excel.ExcelClassifyItems)
+	for _, v := range classifyList {
+		if v.ParentId > 0 {
+			classifyMap[v.ParentId] = append(classifyMap[v.ParentId], v)
+		}
+	}
+	// todo 整理第三层
+	//组装三级分类
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 3 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第二层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 2 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第一层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 1 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	nodeAll := make([]*excel.ExcelClassifyItems, 0)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			nodeAll = append(nodeAll, v)
+		}
+	}
 	resp := response2.ExcelClassifyListResp{
-		AllNodes: rootList,
+		AllNodes: nodeAll,
 	}
 	br.Ret = 200
 	br.Success = true
@@ -173,8 +236,29 @@ func (this *ExcelClassifyController) AddExcelClassify() {
 		return
 	}
 	//获取该层级下最大的排序数
-	maxSort, err := excel.GetExcelClassifyMaxSort(req.ParentId)
+	maxSort, err := excel2.GetExcelClassifyMaxSort(req.ParentId, req.Source)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "查询排序信息失败,Err:" + err.Error()
+		return
+	}
 
+	// 查询父级分类是否存在
+
+	if req.ParentId > 0 {
+		var parent *excel.ExcelClassify
+		parent, err = excel.GetExcelClassifyById(req.ParentId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "父级分类不存在"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "查询父级分类信息失败,Err:" + err.Error()
+			return
+		}
+		req.Level = parent.Level + 1
+	}
 	// 入库
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	classify := &excel.ExcelClassify{
@@ -184,7 +268,7 @@ func (this *ExcelClassifyController) AddExcelClassify() {
 		Source:            source,
 		SysUserId:         this.SysUser.AdminId,
 		SysUserRealName:   this.SysUser.RealName,
-		Level:             req.Level + 1,
+		Level:             req.Level,
 		UniqueCode:        utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
 		Sort:              maxSort + 1,
 		CreateTime:        time.Now(),
@@ -334,6 +418,33 @@ func (this *ExcelClassifyController) DeleteExcelClassifyCheck() {
 		if count > 0 {
 			deleteStatus = 1
 			tipsMsg = "该分类下关联表格不可删除"
+		} else {
+			childClassify, e := excel.GetChildClassifyById(req.ExcelClassifyId)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+				return
+			}
+			if len(childClassify) > 0 {
+				var classifyIds []int
+				for _, v := range childClassify {
+					classifyIds = append(classifyIds, v.ExcelClassifyId)
+				}
+				condition := fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+				var pars []interface{}
+				pars = append(pars, classifyIds)
+				childCount, err := excel.GetExcelInfoCountByCondition(condition, pars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "删除失败"
+					br.ErrMsg = "查询分类下表格数量失败,Err:" + err.Error()
+					return
+				}
+
+				if childCount > 0 {
+					deleteStatus = 1
+					tipsMsg = "该分类下关联表格不可删除"
+				}
+			}
 		}
 	}
 
@@ -413,8 +524,35 @@ func (this *ExcelClassifyController) DeleteExcelClassify() {
 			br.Msg = "该目录下存在关联ETA表格,不可删除"
 			br.IsSendEmail = false
 			return
-		}
+		} else {
+			childClassify, e := excel.GetChildClassifyById(req.ExcelClassifyId)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+				return
+			}
+			if len(childClassify) > 0 {
+				var classifyIds []int
+				for _, v := range childClassify {
+					classifyIds = append(classifyIds, v.ExcelClassifyId)
+				}
+				condition := fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+				var pars []interface{}
+				pars = append(pars, classifyIds)
+				childCount, err := excel.GetExcelInfoCountByCondition(condition, pars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "删除失败"
+					br.ErrMsg = "查询分类下表格数量失败,Err:" + err.Error()
+					return
+				}
 
+				if childCount > 0 {
+					br.Msg = "该目录下存在关联ETA表格,不可删除"
+					br.IsSendEmail = false
+					return
+				}
+			}
+		}
 		classifyItem, err := excel.GetExcelClassifyById(req.ExcelClassifyId)
 		if err != nil {
 			br.Msg = "删除失败"
@@ -561,101 +699,19 @@ func (this *ExcelClassifyController) ExcelClassifyMove() {
 		return
 	}
 
-	if req.ClassifyId <= 0 {
+	if req.ClassifyId <= 0 && req.ExcelInfoId <= 0 {
 		br.Msg = "参数错误"
-		br.ErrMsg = "分类id小于等于0"
-		br.IsSendEmail = false
+		br.ErrMsg = "请选择拖动目标,分类目录或者指标"
 		return
 	}
 	//判断分类是否存在
-	ExcelClassifyInfo, err := excel.GetExcelClassifyById(req.ClassifyId)
+	err, errMsg := excel2.MoveExcelClassify(req)
 	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
 		return
 	}
-	updateCol := make([]string, 0)
 
-	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
-	if ExcelClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
-		parentExcelClassifyInfo, err := excel.GetExcelClassifyById(req.ParentClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
-			return
-		}
-		ExcelClassifyInfo.ParentId = parentExcelClassifyInfo.ExcelClassifyId
-		ExcelClassifyInfo.Level = parentExcelClassifyInfo.Level + 1
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
-	}
-
-	//如果有传入 上一个兄弟节点分类id
-	if req.PrevClassifyId > 0 {
-		//上一个兄弟节点
-		prevClassify, err := excel.GetExcelClassifyById(req.PrevClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果是移动在两个兄弟节点之间
-		if req.NextClassifyId > 0 {
-			//下一个兄弟节点
-			nextClassify, err := excel.GetExcelClassifyById(req.NextClassifyId)
-			if err != nil {
-				br.Msg = "移动失败"
-				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
-				return
-			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == ExcelClassifyInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = excel.UpdateExcelClassifySortByParentId(prevClassify.ParentId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
-				if nextClassify.Sort-prevClassify.Sort == 1 {
-					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
-					_ = excel.UpdateExcelClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
-				}
-			}
-		}
-
-		ExcelClassifyInfo.Sort = prevClassify.Sort + 1
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-
-	} else {
-		firstClassify, err := excel.GetFirstExcelClassifyByParentId(ExcelClassifyInfo.ParentId)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = excel.UpdateExcelClassifySortByParentId(firstClassify.ParentId, firstClassify.ExcelClassifyId-1, 0, updateSortStr)
-		}
-
-		ExcelClassifyInfo.Sort = 0 //那就是排在第一位
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
-
-	//更新
-	if len(updateCol) > 0 {
-		err = ExcelClassifyInfo.Update(updateCol)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "修改失败,Err:" + err.Error()
-			return
-		}
-	}
 	br.Ret = 200
 	br.Success = true
 	br.IsAddLog = true

+ 158 - 134
controllers/data_manage/excel/excel_info.go

@@ -203,6 +203,14 @@ func (c *ExcelInfoController) Add() {
 		}
 	}
 
+	//获取该层级下最大的排序数
+	maxSort, err := excel2.GetExcelClassifyMaxSort(req.ExcelClassifyId, req.Source)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "查询排序信息失败,Err:" + err.Error()
+		return
+	}
+
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	excelInfo := &excel3.ExcelInfo{
 		//ExcelInfoId:     0,
@@ -215,7 +223,7 @@ func (c *ExcelInfoController) Add() {
 		SysUserRealName: sysUser.RealName,
 		Content:         content,
 		ExcelImage:      req.ExcelImage,
-		Sort:            0,
+		Sort:            maxSort + 1,
 		IsDelete:        0,
 		ModifyTime:      time.Now(),
 		CreateTime:      time.Now(),
@@ -346,8 +354,24 @@ func (c *ExcelInfoController) List() {
 			br.ErrMsg = "获取信息失败,GetExcelClassify,Err:" + err.Error()
 			return
 		}
-		condition += " AND excel_classify_id = ? "
-		pars = append(pars, excelClassifyId)
+
+		childClassify, e := excel3.GetChildClassifyById(excelClassifyId)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+			return
+		}
+		if len(childClassify) == 0 {
+			condition += " AND excel_classify_id = ? "
+			pars = append(pars, excelClassifyId)
+		} else {
+			classifyIds := []int{excelClassifyId}
+			for _, v := range childClassify {
+				classifyIds = append(classifyIds, v.ExcelClassifyId)
+			}
+			condition += fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+			pars = append(pars, classifyIds)
+		}
 	}
 	if keyword != "" {
 		condition += ` AND  ( excel_name LIKE ? )`
@@ -738,176 +762,176 @@ func (c *ExcelInfoController) Move() {
 		c.Data["json"] = br
 		c.ServeJSON()
 	}()
-
-	sysUser := c.SysUser
-	if sysUser == nil {
-		br.Msg = "请登录"
-		br.ErrMsg = "请登录,SysUser Is Empty"
-		br.Ret = 408
-		return
-	}
-
-	var req request.MoveExcelInfoReq
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
-	if err != nil {
-		br.Msg = "参数解析异常!"
-		br.ErrMsg = "参数解析失败,Err:" + err.Error()
-		return
-	}
-
-	if req.ExcelInfoId <= 0 {
-		br.Msg = "参数错误"
-		br.ErrMsg = "表格id小于等于0"
-		br.IsSendEmail = false
-		return
-	}
-
-	if req.ExcelClassifyId <= 0 {
-		br.Msg = "请选择分类"
-		br.IsSendEmail = false
-		return
-	}
-
-	//判断分类是否存在
-	_, err = excel3.GetExcelClassifyById(req.ExcelClassifyId)
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取分类信息失败" + err.Error()
-
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "分类已被删除,不可移动,请刷新页面"
-			br.ErrMsg = "分类已被删除,不可移动,请刷新页面"
-			br.IsSendEmail = false
+	/*
+		sysUser := c.SysUser
+		if sysUser == nil {
+			br.Msg = "请登录"
+			br.ErrMsg = "请登录,SysUser Is Empty"
+			br.Ret = 408
+			return
 		}
-		return
-	}
 
-	// 获取表格信息
-	excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取表格信息失败,Err:" + err.Error()
-		return
-	}
+		var req request.MoveExcelInfoReq
+		err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+		if err != nil {
+			br.Msg = "参数解析异常!"
+			br.ErrMsg = "参数解析失败,Err:" + err.Error()
+			return
+		}
 
-	//如果改变了分类,那么移动该表格数据
-	if excelInfo.ExcelClassifyId != req.ExcelClassifyId {
-		//查询需要修改的分类下是否存在同一个表格名称
-		tmpExcelInfo, tmpErr := excel3.GetExcelInfoByClassifyIdAndName(req.ExcelClassifyId, excelInfo.ExcelName)
-		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
+		if req.ExcelInfoId <= 0 {
+			br.Msg = "参数错误"
+			br.ErrMsg = "表格id小于等于0"
+			br.IsSendEmail = false
 			return
 		}
-		if tmpExcelInfo != nil {
-			br.Msg = "移动失败,同一个分类下表格名称不允许重复"
-			br.ErrMsg = "移动失败,同一个分类下表格名称不允许重复"
+
+		if req.ExcelClassifyId <= 0 {
+			br.Msg = "请选择分类"
 			br.IsSendEmail = false
 			return
 		}
 
-		// 变更表格的所属分类
-		excelInfo.ExcelClassifyId = req.ExcelClassifyId
-		err = excelInfo.Update([]string{"ExcelClassifyId"})
+		//判断分类是否存在
+		_, err = excel3.GetExcelClassifyById(req.ExcelClassifyId)
 		if err != nil {
 			br.Msg = "移动失败"
-			br.ErrMsg = "移动失败,Err:" + err.Error()
+			br.ErrMsg = "获取分类信息失败" + err.Error()
+
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "分类已被删除,不可移动,请刷新页面"
+				br.ErrMsg = "分类已被删除,不可移动,请刷新页面"
+				br.IsSendEmail = false
+			}
 			return
 		}
-	}
 
-	//移动排序
-	updateCol := make([]string, 0)
-	//如果有传入 上一个兄弟节点分类id
-	if req.PrevExcelInfoId > 0 {
-		prevExcelInfo, err := excel3.GetExcelInfoById(req.PrevExcelInfoId)
+		// 获取表格信息
+		excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
 		if err != nil {
 			br.Msg = "移动失败"
-			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+			br.ErrMsg = "获取表格信息失败,Err:" + err.Error()
 			return
 		}
 
-		//如果是移动在两个兄弟节点之间
-		if req.NextExcelInfoId > 0 {
-			//下一个兄弟节点
-			nextExcelInfo, err := excel3.GetExcelInfoById(req.NextExcelInfoId)
+		//如果改变了分类,那么移动该表格数据
+		if excelInfo.ExcelClassifyId != req.ExcelClassifyId {
+			//查询需要修改的分类下是否存在同一个表格名称
+			tmpExcelInfo, tmpErr := excel3.GetExcelInfoByClassifyIdAndName(req.ExcelClassifyId, excelInfo.ExcelName)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				br.Msg = "移动失败"
+				br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
+				return
+			}
+			if tmpExcelInfo != nil {
+				br.Msg = "移动失败,同一个分类下表格名称不允许重复"
+				br.ErrMsg = "移动失败,同一个分类下表格名称不允许重复"
+				br.IsSendEmail = false
+				return
+			}
+
+			// 变更表格的所属分类
+			excelInfo.ExcelClassifyId = req.ExcelClassifyId
+			err = excelInfo.Update([]string{"ExcelClassifyId"})
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "移动失败,Err:" + err.Error()
+				return
+			}
+		}
+
+		//移动排序
+		updateCol := make([]string, 0)
+		//如果有传入 上一个兄弟节点分类id
+		if req.PrevExcelInfoId > 0 {
+			prevExcelInfo, err := excel3.GetExcelInfoById(req.PrevExcelInfoId)
 			if err != nil {
 				br.Msg = "移动失败"
-				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+				br.ErrMsg = "获取一个兄弟节点分类信息失败,Err:" + err.Error()
 				return
 			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevExcelInfo.Sort == nextExcelInfo.Sort || prevExcelInfo.Sort == excelInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点下一层,那么需要再加一层了
-				if nextExcelInfo.Sort-prevExcelInfo.Sort == 1 {
+
+			//如果是移动在两个兄弟节点之间
+			if req.NextExcelInfoId > 0 {
+				//下一个兄弟节点
+				nextExcelInfo, err := excel3.GetExcelInfoById(req.NextExcelInfoId)
+				if err != nil {
+					br.Msg = "移动失败"
+					br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+					return
+				}
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevExcelInfo.Sort == nextExcelInfo.Sort || prevExcelInfo.Sort == excelInfo.Sort {
 					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
+					updateSortStr := `sort + 2`
 					_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr)
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点下一层,那么需要再加一层了
+					if nextExcelInfo.Sort-prevExcelInfo.Sort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					}
 				}
 			}
-		}
 
-		// 变更表格在当前分类下的排序
-		excelInfo.Sort = prevExcelInfo.Sort + 1
-		excelInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
+			// 变更表格在当前分类下的排序
+			excelInfo.Sort = prevExcelInfo.Sort + 1
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
 
-	} else {
-		firstClassify, err := excel3.GetFirstExcelInfoByClassifyId(req.ExcelClassifyId)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
-			return
-		}
+		} else {
+			firstClassify, err := excel3.GetFirstExcelInfoByClassifyId(req.ExcelClassifyId)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId+1, updateSortStr)
+			}
 
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId+1, updateSortStr)
+			// 变更表格在当前分类下的排序
+			excelInfo.Sort = 0 //那就是排在第一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
 		}
 
-		// 变更表格在当前分类下的排序
-		excelInfo.Sort = 0 //那就是排在第一位
-		excelInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
+		//更新
+		if len(updateCol) > 0 {
+			err = excelInfo.Update(updateCol)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "修改失败,Err:" + err.Error()
+				return
+			}
+		}
 
-	//更新
-	if len(updateCol) > 0 {
-		err = excelInfo.Update(updateCol)
 		if err != nil {
 			br.Msg = "移动失败"
 			br.ErrMsg = "修改失败,Err:" + err.Error()
 			return
 		}
-	}
-
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "修改失败,Err:" + err.Error()
-		return
-	}
-
-	//新增操作日志
-	//{
-	//	ExcelLog := new(data_manage.ExcelInfoLog)
-	//	ExcelLog.ExcelName = ExcelInfo.ExcelName
-	//	ExcelLog.ExcelInfoId = req.ExcelInfoId
-	//	ExcelLog.ExcelClassifyId = ExcelInfo.ExcelClassifyId
-	//	ExcelLog.SysUserId = sysUser.AdminId
-	//	ExcelLog.SysUserRealName = sysUser.RealName
-	//	ExcelLog.UniqueCode = ExcelInfo.UniqueCode
-	//	ExcelLog.CreateTime = time.Now()
-	//	ExcelLog.Content = string(c.Ctx.Input.RequestBody)
-	//	ExcelLog.Status = "移动表格"
-	//	ExcelLog.Method = c.Ctx.Input.URL()
-	//	go data_manage.AddExcelInfoLog(ExcelLog)
-	//}
 
+		//新增操作日志
+		//{
+		//	ExcelLog := new(data_manage.ExcelInfoLog)
+		//	ExcelLog.ExcelName = ExcelInfo.ExcelName
+		//	ExcelLog.ExcelInfoId = req.ExcelInfoId
+		//	ExcelLog.ExcelClassifyId = ExcelInfo.ExcelClassifyId
+		//	ExcelLog.SysUserId = sysUser.AdminId
+		//	ExcelLog.SysUserRealName = sysUser.RealName
+		//	ExcelLog.UniqueCode = ExcelInfo.UniqueCode
+		//	ExcelLog.CreateTime = time.Now()
+		//	ExcelLog.Content = string(c.Ctx.Input.RequestBody)
+		//	ExcelLog.Status = "移动表格"
+		//	ExcelLog.Method = c.Ctx.Input.URL()
+		//	go data_manage.AddExcelInfoLog(ExcelLog)
+		//}
+	*/
 	br.Ret = 200
 	br.Success = true
 	br.IsAddLog = true

+ 227 - 16
controllers/data_manage/excel/mixed_table.go

@@ -7,7 +7,11 @@ import (
 	"eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/services/data"
 	excel2 "eta/eta_api/services/data/excel"
+	"eta/eta_api/utils"
+	"fmt"
 	"strconv"
+	"strings"
+	"time"
 )
 
 // GetSystemDate
@@ -29,7 +33,6 @@ func (c *ExcelInfoController) GetSystemDate() {
 		br.Ret = 408
 		return
 	}
-
 	var req request.MixedTableCellDataReq
 	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -38,7 +41,14 @@ func (c *ExcelInfoController) GetSystemDate() {
 		return
 	}
 
-	date, err, errMsg := excel2.HandleDate(req.DataTimeType, req.Value)
+	var config request.EdbDateConf
+	err = json.Unmarshal([]byte(req.Value), &config)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	date, _, err, errMsg := excel2.HandleDate(req.DataTimeType, req.Value)
 	if err != nil {
 		br.Msg = "获取系统日期失败"
 		if errMsg != `` {
@@ -47,6 +57,46 @@ func (c *ExcelInfoController) GetSystemDate() {
 		br.ErrMsg = "获取系统日期失败,Err:" + err.Error()
 		return
 	}
+	if req.DataTimeType == request.EdbDateDT {
+		edbInfo, err := data_manage.GetEdbInfoById(config.EdbInfoId)
+		if err != nil {
+			br.Msg = "获取指标信息失败!"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+
+		dataList := make([]*data_manage.EdbDataList, 0)
+		switch edbInfo.EdbInfoType {
+		case 0:
+			dataList, _ = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
+		case 1:
+			_, dataList, _, _, _, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+		default:
+			br.Msg = "指标类型异常!"
+			br.ErrMsg = "指标类型异常,Err:" + strconv.Itoa(edbInfo.EdbInfoType)
+			return
+		}
+
+		if req.DataTime == `` { //选择前移几期数
+			date, err = excel2.GetEdbDateByMoveForward(req.Value, dataList)
+			if err != nil {
+				br.Msg = "查询指标前移日期失败!"
+				br.ErrMsg = "查询指标前移日期失败,Err:" + err.Error()
+				return
+			}
+		} else {
+			date = req.DataTime //选择表格中的日期
+		}
+		if date != "" {
+			// 开始做日期变换
+			date, err = excel2.HandleMixTableDateChange(date, req.Value)
+			if err != nil {
+				br.Msg = "日期变换失败!"
+				br.ErrMsg = "日期变换失败,Err:" + err.Error()
+				return
+			}
+		}
+	}
 
 	type resp struct {
 		Date string
@@ -78,7 +128,7 @@ func (c *ExcelInfoController) CalculateData() {
 		br.Ret = 408
 		return
 	}
-
+	requestBody := string(c.Ctx.Input.RequestBody)
 	var req request.CalculateConf
 	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -139,7 +189,8 @@ func (c *ExcelInfoController) CalculateData() {
 	}
 	respItem, tmpErr := data.BaseCalculate(string(reqJson))
 	if tmpErr != nil {
-		err = tmpErr
+		br.Msg = "计算指标失败"
+		br.ErrMsg = tmpErr.Error()
 		return
 	}
 	if respItem.Ret != 200 {
@@ -155,26 +206,57 @@ func (c *ExcelInfoController) CalculateData() {
 		num = lenDate
 	}
 
-	var currDate string // 当前日期
 	dataListResp := make([]*data_manage.EdbDataList, 0)
 
+	var newDate string
+	var showValue string
+	if req.DataTime == `` { //选择前移几期数
+		newDate, err = excel2.GetEdbDateByMoveForwardByDateList(requestBody, respItem.Data.DateList)
+		if err != nil {
+			return
+		}
+	} else {
+		newDate = req.DataTime //选择表格中的日期
+		if strings.Count(newDate, "-") == 1 {
+			newDate = newDate + "-01"
+			// 查找这个月早的时间作为起始时间
+			for _, v := range respItem.Data.DateList {
+				if v >= newDate {
+					newDate = v
+				}
+			}
+		}
+	}
+	// 开始做日期变换
+	newDate, err = excel2.HandleMixTableDateChange(newDate, requestBody)
+	if err != nil {
+		return
+	}
 	if req.DataTime == `` {
-		for i := 1; i <= num; i++ {
+		canAdd := false
+		for i := 1; i <= lenDate; i++ {
 			date := respItem.Data.DateList[lenDate-i]
 			val, ok := respItem.Data.DataMap[date]
 			if !ok {
 				continue
 			}
-
-			dataListResp = append(dataListResp, &data_manage.EdbDataList{
-				Value:    val,
-				DataTime: date,
-			})
+			if date == newDate {
+				showValue = utils.FormatMixTableDataShowValue(val)
+				canAdd = true
+			}
+			if canAdd && len(dataListResp) <= num {
+				dataListResp = append(dataListResp, &data_manage.EdbDataList{
+					Value:    val,
+					DataTime: date,
+				})
+			}
 		}
 	} else {
-		if val, ok := respItem.Data.DataMap[req.DataTime]; ok {
+		// todo 如果选择了表格中的日期应该如何处理
+		if val, ok := respItem.Data.DataMap[newDate]; ok {
+			showValue = utils.FormatMixTableDataShowValue(val)
 			for i, tmpDate := range respItem.Data.DateList {
-				if tmpDate == req.DataTime {
+				if tmpDate == newDate {
 					if i+3 <= lenDate {
 						t1Date := respItem.Data.DateList[i+2]
 						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
@@ -200,7 +282,7 @@ func (c *ExcelInfoController) CalculateData() {
 					// 当前日期
 					dataListResp = append(dataListResp, &data_manage.EdbDataList{
 						Value:    val,
-						DataTime: req.DataTime,
+						DataTime: newDate,
 					})
 					if i >= 1 {
 						t1Date := respItem.Data.DateList[i-1]
@@ -227,11 +309,140 @@ func (c *ExcelInfoController) CalculateData() {
 		}
 	}
 	resp := data_manage.BeforeAndAfterDateDataResp{
-		List: dataListResp,
-		Date: currDate,
+		List:      dataListResp,
+		Date:      newDate,
+		ShowValue: showValue,
 	}
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "计算成功"
 	br.Data = resp
 }
+
+// GetMixDateCalculate
+// @Title 获取混合表格日期计算
+// @Description 获取混合表格日期计算
+// @Param	request	body request.MixedTableCellDataReq true "type json string"
+// @router /excel_info/mixed/date_calculate [post]
+func (c *ExcelInfoController) GetMixDateCalculate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.MixedDateCalculateReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	valMap := make(map[string]int)
+	for _, v := range req.DateList {
+		// 查找单元格数据
+		// 如果不是基础计算单元格,直接返回
+		_, err = time.ParseInLocation(utils.FormatDate, v.Date, time.Local)
+		if err != nil {
+			br.Msg = "日期计算失败!"
+			br.ErrMsg = fmt.Sprintf("%s 的单元格非日期类型, Err: %s", v.Date, err.Error())
+			return
+		}
+		// todo 把日期转换成excel里的天数
+		realDiffDay := utils.GetDaysDiff1900(v.Date)
+
+		valMap[strings.ToUpper(v.Tag)] = realDiffDay
+	}
+
+	// 计算
+	val, errMsg, err := excel2.DateCalculateFormula(valMap, strings.ToUpper(req.Formula))
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	showValue := utils.FormatMixTableDataShowValue(val)
+
+	type resp struct {
+		ShowValue string
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.Data = resp{
+		ShowValue: showValue,
+	}
+}
+
+// GetBaseEdbInfo
+// @Title 获取指标的基本信息
+// @Description 获取指标的基本信息
+// @Param	EdbInfoIds	string  "指标ID用英文逗号分割"
+// @router /excel_info/base_edb_info [get]
+func (c *ExcelInfoController) GetBaseEdbInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	edbInfoIds := c.GetString("EdbInfoIds")
+	if edbInfoIds == "" {
+		br.Msg = "请输入指标ID"
+		return
+	}
+	ids := strings.Split(edbInfoIds, ",")
+	edbIds := make([]int, 0)
+	for _, v := range ids {
+		id, err := strconv.Atoi(v)
+		if err != nil {
+			br.Msg = "指标ID格式错误"
+			return
+		}
+		edbIds = append(edbIds, id)
+	}
+	edbInfoList, err := data_manage.GetEdbInfoByIdList(edbIds)
+	if err != nil {
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	list := make([]*data_manage.BaseEdbNameItem, 0)
+	for _, v := range edbInfoList {
+		tmp := new(data_manage.BaseEdbNameItem)
+
+		tmp.EdbInfoId = v.EdbInfoId
+		tmp.EdbInfoType = v.EdbInfoType
+		tmp.EdbCode = v.EdbCode
+		tmp.EdbName = v.EdbName
+		tmp.Source = v.Source
+		tmp.SourceName = v.SourceName
+		tmp.Frequency = v.Frequency
+		tmp.Unit = v.Unit
+		list = append(list, tmp)
+	}
+	resp := data_manage.BaseEdbInfoResp{
+		List: list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = resp
+}

+ 16 - 6
models/data_manage/edb_info.go

@@ -71,10 +71,19 @@ func AddEdbInfo(item *EdbInfo) (lastId int64, err error) {
 	return
 }
 
-type EdbInfoItem struct {
-	EdbInfoId  int    `description:"指标id"`
-	EdbName    string `description:"指标名称"`
-	ClassifyId int    `description:"指标分类"`
+type BaseEdbNameItem struct {
+	EdbInfoId   int    `description:"指标id"`
+	EdbInfoType int    `description:"指标类型,0:普通指标,1:预测指标"`
+	SourceName  string `description:"来源名称"`
+	Source      int    `description:"来源id"`
+	EdbCode     string `description:"指标编码"`
+	EdbName     string `description:"指标名称"`
+	Frequency   string `description:"频率"`
+	Unit        string `description:"单位"`
+}
+
+type BaseEdbInfoResp struct {
+	List []*BaseEdbNameItem
 }
 
 // GetEdbInfoAll 用于分类展示
@@ -1667,8 +1676,9 @@ type TraceEdbInfoResp struct {
 
 // BeforeAndAfterDateDataResp 前后几期数据
 type BeforeAndAfterDateDataResp struct {
-	List []*EdbDataList `description:"list"`
-	Date string         `description:"实际日期"`
+	List      []*EdbDataList `description:"list"`
+	Date      string         `description:"实际日期"`
+	ShowValue string         `description:"展示值"`
 }
 
 // GetEdbInfoAdminList

+ 25 - 6
models/data_manage/excel/excel_classify.go

@@ -49,6 +49,13 @@ func GetExcelClassifyById(classifyId int) (item *ExcelClassify, err error) {
 	return
 }
 
+func GetChildClassifyById(classifyId int) (items []*ExcelClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM excel_classify WHERE parent_id=? AND is_delete=0 `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
 func GetExcelClassifyByParentId(parentId, source int) (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM excel_classify WHERE parent_id=? AND source = ? AND is_delete=0 order by sort asc,excel_classify_id asc`
@@ -56,6 +63,13 @@ func GetExcelClassifyByParentId(parentId, source int) (items []*ExcelClassifyIte
 	return
 }
 
+func GetExcelClassifyBySource(source int) (items []*ExcelClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM excel_classify WHERE  source = ? AND is_delete=0 order by sort asc,excel_classify_id asc`
+	_, err = o.Raw(sql, source).QueryRows(&items)
+	return
+}
+
 func GetExcelClassifyAll() (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM excel_classify WHERE parent_id<>0 AND is_delete=0 order by sort asc,excel_classify_id asc`
@@ -108,13 +122,13 @@ func GetFirstExcelClassifyByParentId(parentId int) (item *ExcelClassify, err err
 }
 
 // UpdateExcelClassifySortByParentId 根据图表父类id更新排序
-func UpdateExcelClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+func UpdateExcelClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string, source int) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` update excel_classify set sort = ` + updateSort + ` WHERE parent_id=? and sort > ? AND is_delete=0 `
+	sql := ` update excel_classify set sort = ` + updateSort + ` WHERE parent_id=? and source=? and sort > ? AND is_delete=0 `
 	if classifyId > 0 {
 		sql += ` or ( excel_classify_id > ` + fmt.Sprint(classifyId) + ` and sort= ` + fmt.Sprint(nowSort) + `)`
 	}
-	_, err = o.Raw(sql, parentId, nowSort).Exec()
+	_, err = o.Raw(sql, parentId, source, nowSort).Exec()
 	return
 }
 
@@ -126,10 +140,10 @@ func (ExcelClassify *ExcelClassify) Update(cols []string) (err error) {
 }
 
 // GetExcelClassifyMaxSort 获取图表分类下最大的排序数
-func GetExcelClassifyMaxSort(parentId int) (sort int, err error) {
+func GetExcelClassifyMaxSort(parentId int, source int) (sort int, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT Max(sort) AS sort FROM excel_classify WHERE parent_id=? AND is_delete=0 `
-	err = o.Raw(sql, parentId).QueryRow(&sort)
+	sql := `SELECT Max(sort) AS sort FROM excel_classify WHERE parent_id=? AND source = ? AND is_delete=0 `
+	err = o.Raw(sql, parentId, source).QueryRow(&sort)
 	return
 }
 
@@ -145,3 +159,8 @@ func GetExcelClassifyViewById(classifyId int) (item *ExcelClassifyView, err erro
 	err = o.Raw(sql, classifyId).QueryRow(&item)
 	return
 }
+
+// ExcelClassifyItemBySort 自定义比较函数,按年龄从小到大排序
+func ExcelClassifyItemBySort(p1, p2 *ExcelClassifyItems) bool {
+	return p1.Sort < p2.Sort
+}

+ 13 - 4
models/data_manage/excel/excel_info.go

@@ -132,7 +132,7 @@ func GetExcelInfoAll() (items []*ExcelClassifyItems, err error) {
 func GetNoContentExcelInfoAll(source, userId int) (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT excel_info_id,excel_classify_id,excel_name AS excel_classify_name,
-             unique_code,sys_user_id,sys_user_real_name
+             unique_code,sys_user_id,sys_user_real_name,sort
             FROM excel_info where is_delete=0 AND source = ?  `
 
 	pars := []interface{}{source}
@@ -253,14 +253,15 @@ func GetFirstExcelInfoByClassifyId(classifyId int) (item *ExcelInfo, err error)
 }
 
 // UpdateExcelInfoSortByClassifyId 根据表格id更新排序
-func UpdateExcelInfoSortByClassifyId(classifyId, nowSort, prevExcelInfoId int, updateSort string) (err error) {
+func UpdateExcelInfoSortByClassifyId(classifyId, nowSort, prevExcelInfoId int, updateSort string, source int) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` update excel_info set sort = ` + updateSort + ` WHERE excel_classify_id=? AND is_delete=0 AND ( sort > ? `
+	sql := ` update excel_info set sort = ` + updateSort + ` WHERE excel_classify_id=? AND source=? AND is_delete=0 AND ( sort > ? `
+	// todo 前一个兄弟节点后移
 	if prevExcelInfoId > 0 {
 		sql += ` or (excel_info_id < ` + fmt.Sprint(prevExcelInfoId) + ` and sort = ` + fmt.Sprint(nowSort) + `)`
 	}
 	sql += `)`
-	_, err = o.Raw(sql, classifyId, nowSort).Exec()
+	_, err = o.Raw(sql, classifyId, source, nowSort).Exec()
 	return
 }
 
@@ -516,3 +517,11 @@ type BatchRefreshExcelReq struct {
 	ReportChapterId int      `description:"报告章节ID"`
 	Source          string   `description:"来源,枚举值:report、english_report、smart_report"`
 }
+
+// GetExcelMaxSortByClassifyId 获取当前分类下,且排序数最大的excel
+func GetExcelMaxSortByClassifyId(classifyId int, source int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT Max(sort) AS sort FROM excel_info WHERE excel_classify_id=? AND source = ? AND is_delete=0 order by sort desc,excel_info_id desc limit 1`
+	err = o.Raw(sql, classifyId, source).QueryRow(&sort)
+	return
+}

+ 7 - 2
models/data_manage/excel/request/excel_classify.go

@@ -3,7 +3,7 @@ package request
 // AddExcelClassifyReq 添加excel分类请求
 type AddExcelClassifyReq struct {
 	ExcelClassifyName string `description:"分类名称"`
-	ParentId          int    `description:"父级id,第一级传0" json:"-"`
+	ParentId          int    `description:"父级id,第一级传0"`
 	Level             int    `description:"层级,第一级传0,其余传上一级的层级" json:"-"`
 	Source            int    `description:"1:excel插件的表格,2:自定义表格,3:混合表格,默认:1"`
 }
@@ -17,9 +17,14 @@ type EditExcelClassifyReq struct {
 // MoveExcelClassifyReq 移动图表分类请求参数
 type MoveExcelClassifyReq struct {
 	ClassifyId       int `description:"分类id"`
-	ParentClassifyId int `description:"父级分类id" json:"-"`
+	ParentClassifyId int `description:"父级分类id"`
 	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
 	NextClassifyId   int `description:"下一个兄弟节点分类id"`
+
+	ExcelInfoId     int `description:"excel表格ID"`
+	PrevExcelInfoId int `description:"上一个excel表格ID"`
+	NextExcelInfoId int `description:"下一个excel表格ID"`
+	Source          int
 }
 
 type DeleteExcelClassifyReq struct {

+ 69 - 8
models/data_manage/excel/request/mixed_table.go

@@ -9,6 +9,7 @@ const (
 	PopInsertDataDT                     // 5 弹框插值(在表格上选择日期,然后空白单元格选择弹框并选择指标,插入该指标与该日期的值)
 	FormulateCalculateDataDT            // 6 公式计算(A+B这种)
 	InsertEdbCalculateDataDT            // 7 插入指标系统计算公式生成的值
+	DateCalculateDataDT                 // 8 日期计算
 )
 
 // 单元格的日期类型类型
@@ -16,6 +17,7 @@ const (
 	CustomDateT = iota //手动输入日期
 	SystemDateT        // 系统日期
 	EdbDateDT          // 导入指标日期(指标库的最新日期)
+
 )
 
 // 单元格的日期类型类型
@@ -33,14 +35,16 @@ type MixedTableReq struct {
 
 // MixedTableCellDataReq 混合表格单元格参数
 type MixedTableCellDataReq struct {
-	Uid          string `description:"单元格唯一标识"`
-	DataType     int    `description:"数据类型,1:日期,2:指标,3:自定义文本,4:插值"`
-	DataTime     string `description:"所属日期"`
-	DataTimeType int    `description:"日期类型:0:手动输入日期;1:导入系统日期;;3:导入指标日期(指标库的最新日期);"`
-	EdbInfoId    int    `description:"指标id"`
-	ShowValue    string `description:"展示值"`
-	Value        string `description:"实际值"`
-	Extra        string `description:"额外参数"`
+	Uid             string      `description:"单元格唯一标识"`
+	DataType        int         `description:"数据类型,1:日期,2:指标,3:自定义文本,4:插值"`
+	DataTime        string      `description:"所属日期"`
+	DataTimeType    int         `description:"日期类型:0:手动输入日期(固定日期);1:导入系统日期;;3:导入指标日期(指标库的最新日期);"`
+	EdbInfoId       int         `description:"指标id"`
+	ShowValue       string      `description:"展示值"`
+	Value           string      `description:"实际值和配置"`
+	Extra           string      `description:"额外参数"`
+	ShowStyle       string      `description:"展示的样式配置"`
+	ShowFormatValue interface{} `description:"样式处理后的值"`
 }
 
 // CellRelationConf
@@ -74,6 +78,61 @@ type SystemDateConf struct {
 // @Description: 导入指标日期配置
 type EdbDateConf struct {
 	EdbInfoId int `description:"指标id"`
+	EdbDateChangeConf
+}
+
+// EdbDateExtraConf
+// @Description: 导入指标日期前移和日期变换
+type EdbDateChangeConf struct {
+	MoveForward int `description:"前移的期数"`
+	DateChange  []*EdbDateConfDateChange
+}
+
+type EdbDateConfDateChange struct {
+	Year         int
+	Month        int
+	Day          int
+	Frequency    string `description:"频度变换"`
+	FrequencyDay string `description:"频度的固定日期"`
+	ChangeType   int    `description:"日期变换类型1日期位移,2指定频率"`
+}
+
+// MixedDateCalculateReq 混合表格日期计算
+type MixedDateCalculateReq struct {
+	Formula  string                   `description:"计算公式"`
+	DateList []MixDateCalculateTagReq `description:"表格中的单元格"`
+}
+
+// MixDateCalculateConf 混合表格中的日期计算
+type MixDateCalculateConf struct {
+	Formula          string                `description:"计算公式"`
+	RelationCellList []MixDateCalculateTag `description:"表格中的单元格"`
+}
+
+// MixDateCalculateTag 混合表格中的日期计算的关联单元格
+type MixDateCalculateTag struct {
+	Uid string `description:"单元格唯一值"`
+	Tag string `description:"单元格对应标签"`
+}
+
+// MixDateCalculateTagReq 混合表格中的日期计算的关联单元格
+type MixDateCalculateTagReq struct {
+	Date string `description:"日期"`
+	Tag  string `description:"指标对应标签"`
+}
+
+// MixCellShowStyle 混合表格 单元格样式展示计算
+type MixCellShowStyle struct {
+	Pn int    `description:"小数点位数增加或减少,正数表述增加,负数表示减少" json:"pn"`
+	Nt string `description:"变换类型:number 小数点位数改变,percent百分比," json:"nt"`
+}
+
+type DateDataBeforeAfterReq struct {
+	EdbInfoId   int
+	Date        string
+	Num         int
+	MoveForward int `description:"前移的期数"`
+	DateChange  []*EdbDateConfDateChange
 }
 
 // CalculateConf
@@ -87,6 +146,8 @@ type CalculateConf struct {
 	MoveType      int         `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency string      `description:"移动频度"`
 	Source        int         `description:"1:累计值转月;2:累计值转季;3:同比值;4:同差值;5:N数值移动平均数计算;6:环比值;7:环差值;8:升频;9:降频;10:时间移位;11:超季节性;12:年化;13:累计值;14:累计值年初至今;15:指数修匀;16:日均值"`
+
+	EdbDateChangeConf
 }
 
 // BaseCalculateConf

+ 19 - 1
routers/commentsRouter.go

@@ -637,6 +637,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetBaseEdbInfo",
+            Router: `/excel_info/base_edb_info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "Copy",
@@ -718,6 +727,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetMixDateCalculate",
+            Router: `/excel_info/mixed/date_calculate`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "Move",
@@ -2819,7 +2837,7 @@ func init() {
         beego.ControllerComments{
             Method: "GetEdbBeforeAndAfterDateData",
             Router: `/edb_info/date_data/before_after`,
-            AllowHTTPMethods: []string{"get"},
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})

+ 24 - 38
services/data/edb_data.go

@@ -358,49 +358,35 @@ func GetDateData(edbInfo *data_manage.EdbInfo, startDate, endDate string) (item
 }
 
 // GetEdbBeforeAndAfterDateData 获取指标的单个日期的值
-func GetEdbBeforeAndAfterDateData(edbInfo *data_manage.EdbInfo, startDate, endDate string, dataType, num int) (list []*data_manage.EdbDataList, err error) {
-	var dataList []*data_manage.EdbDataList
-	switch edbInfo.EdbInfoType {
-	case 0:
-		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, startDate, endDate)
-	case 1:
-		_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, startDate, endDate, true)
-	default:
-		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
-
-	}
-	if err != nil {
-		return
-	}
-
+func GetEdbBeforeAndAfterDateData(targetDate string, dataList []*data_manage.EdbDataList) (list []*data_manage.EdbDataList, err error) {
 	lenDataList := len(dataList)
 	if lenDataList <= 0 {
 		return
 	}
-
-	switch dataType {
-	case 1: // 取前面的数据
-		if lenDataList <= 1 { // 如果只有一个,那么也返回,因为自己不算
-			return
-		}
-		if lenDataList <= num {
-			num = lenDataList - 1
-		}
-
-		for i := num; i >= 0; i-- {
-			list = append(list, dataList[lenDataList-1-i])
-		}
-
-	case 2: // 取后面的数据
-		num = num + 1
-		if lenDataList < num {
-			num = lenDataList
-		}
-
-		for i := 0; i < num; i++ {
-			list = append(list, dataList[i])
+	// 数组按照日期从小到大排序
+	maxIndex := lenDataList - 1
+	startIndex := 0
+	endIndex := 0
+	for index, v := range dataList {
+		if v.DataTime == targetDate {
+			if index+2 > maxIndex {
+				endIndex = maxIndex
+			} else if index+1 > maxIndex {
+				endIndex = maxIndex
+			} else {
+				endIndex = index + 2
+			}
+			startIndex = endIndex - 4
+			if startIndex < 0 {
+				startIndex = 0
+			}
+			if endIndex == maxIndex {
+				list = dataList[startIndex:]
+			} else {
+				list = dataList[startIndex : endIndex+1]
+			}
+			break
 		}
 	}
-
 	return
 }

+ 429 - 0
services/data/excel/excel_classify.go

@@ -0,0 +1,429 @@
+package excel
+
+import (
+	"errors"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/excel"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/utils"
+	"time"
+)
+
+func GetExcelClassifyMaxSort(parentId int, source int) (maxSort int, err error) {
+	//获取该层级下最大的排序数
+	maxSort, err = excel.GetExcelClassifyMaxSort(parentId, source)
+	if err != nil {
+		return
+	}
+	edbMaxSort, err := excel.GetExcelMaxSortByClassifyId(parentId, source)
+	if err != nil {
+		return
+	}
+	if maxSort < edbMaxSort {
+		maxSort = edbMaxSort
+	}
+	return
+}
+
+// MoveExcelClassify 移动指标分类
+func MoveExcelClassify(req request.MoveExcelClassifyReq) (err error, errMsg string) {
+	classifyId := req.ClassifyId
+	parentClassifyId := req.ParentClassifyId
+	prevClassifyId := req.PrevClassifyId
+	nextClassifyId := req.NextClassifyId
+
+	excelInfoId := req.ExcelInfoId
+	prevExcelInfoId := req.PrevExcelInfoId
+	nextExcelInfoId := req.NextExcelInfoId
+	source := req.Source
+	//首先确定移动的对象是分类还是指标
+	//判断上一个节点是分类还是指标
+	//判断下一个节点是分类还是指标
+	//同时更新分类目录下的分类sort和指标sort
+	//更新当前移动的分类或者指标sort
+
+	var parentExcelClassifyInfo *excel.ExcelClassify
+	if parentClassifyId > 0 {
+		parentExcelClassifyInfo, err = excel.GetExcelClassifyById(parentClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上级分类信息失败,Err:" + err.Error())
+			return
+		}
+	}
+
+	//如果有传入 上一个兄弟节点分类id
+	var (
+		excelClassifyInfo *excel.ExcelClassify
+		prevClassify      *excel.ExcelClassify
+		nextClassify      *excel.ExcelClassify
+
+		excelInfo     *excel.ExcelInfo
+		prevExcelInfo *excel.ExcelInfo
+		nextExcelInfo *excel.ExcelInfo
+		prevSort      int
+		nextSort      int
+	)
+
+	// 移动对象为分类, 判断权限
+	if excelInfoId == 0 {
+		excelClassifyInfo, err = excel.GetExcelClassifyById(classifyId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前分类不存在"
+				err = errors.New("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+
+	} else {
+		excelInfo, err = excel.GetExcelInfoById(excelInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前表格不存在"
+				err = errors.New("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+		if parentClassifyId == 0 {
+			errMsg = "移动失败,表格必须挂在分类下"
+			err = errors.New(errMsg)
+			return
+		}
+	}
+
+	if prevClassifyId > 0 {
+		prevClassify, err = excel.GetExcelClassifyById(prevClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevClassify.Sort
+	} else if prevExcelInfoId > 0 {
+		prevExcelInfo, err = excel.GetExcelInfoById(prevExcelInfoId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevExcelInfo.Sort
+	}
+
+	if nextClassifyId > 0 {
+		//下一个兄弟节点
+		nextClassify, err = excel.GetExcelClassifyById(nextClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextClassify.Sort
+	} else if nextExcelInfoId > 0 {
+		//下一个兄弟节点
+		nextExcelInfo, err = excel.GetExcelInfoById(nextExcelInfoId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextExcelInfo.Sort
+	}
+
+	err, errMsg = moveExcelClassify(parentExcelClassifyInfo, excelClassifyInfo, prevClassify, nextClassify, excelInfo, prevExcelInfo, nextExcelInfo, parentClassifyId, prevSort, nextSort, source)
+	return
+}
+
+// moveExcelClassify 移动表格分类
+func moveExcelClassify(parentExcelClassifyInfo, excelClassifyInfo, prevClassify, nextClassify *excel.ExcelClassify, excelInfo, prevExcelInfo, nextExcelInfo *excel.ExcelInfo, parentClassifyId int, prevSort, nextSort int, source int) (err error, errMsg string) {
+	updateCol := make([]string, 0)
+
+	// 移动对象为分类, 判断分类是否存在
+	if excelClassifyInfo != nil {
+		oldParentId := excelClassifyInfo.ParentId
+		/*oldLevel := excelClassifyInfo.Level
+		var classifyIds []int*/
+		if oldParentId != parentClassifyId {
+			//todo 更新子分类对应的level
+			/*childList, e, m := GetChildClassifyByClassifyId(excelClassifyInfo.ClassifyId)
+			if e != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询子分类失败,Err:" + e.Error() + m)
+				return
+			}
+
+			if len(childList) > 0 {
+				for _, v := range childList {
+					if v.ClassifyId == excelClassifyInfo.ClassifyId {
+						continue
+					}
+					classifyIds = append(classifyIds, v.ClassifyId)
+				}
+			}*/
+		}
+		//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+		if excelClassifyInfo.ParentId != parentClassifyId && parentClassifyId != 0 {
+			if excelClassifyInfo.Level != parentExcelClassifyInfo.Level+1 { //禁止层级调整
+				errMsg = "移动失败"
+				err = errors.New("不支持目录层级变更")
+				return
+			}
+			excelClassifyInfo.ParentId = parentExcelClassifyInfo.ExcelClassifyId
+			excelClassifyInfo.Level = parentExcelClassifyInfo.Level + 1
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+		} else if excelClassifyInfo.ParentId != parentClassifyId && parentClassifyId == 0 {
+			errMsg = "移动失败"
+			err = errors.New("不支持目录层级变更")
+			return
+		}
+
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == excelClassifyInfo.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+					}
+
+					//变更表格
+					if prevExcelInfo != nil {
+						//变更兄弟节点的排序
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+
+						//变更分类
+						if prevClassify != nil {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevSort, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+						}
+
+						//变更表格
+						if prevExcelInfo != nil {
+							//变更兄弟节点的排序
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+						}
+
+					}
+				}
+			}
+
+			excelClassifyInfo.Sort = prevSort + 1
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevExcelInfo == nil && nextExcelInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetExcelClassifyMaxSort(parentClassifyId, source)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			excelClassifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级分类的第一位
+			firstClassify, tmpErr := data_manage.GetFirstEdbClassifyByParentId(parentClassifyId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, firstClassify.ClassifyId-1, 0, updateSortStr, source)
+				//该分类下的所有表格也需要+1
+				_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr, source)
+			} else {
+				//如果该分类下存在表格,且第一个表格的排序等于0,那么需要调整排序
+				firstExcel, tErr := excel.GetFirstExcelInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstExcel != nil && firstExcel.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, firstExcel.ExcelInfoId-1, updateSortStr, source)
+					_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, source)
+				}
+			}
+
+			excelClassifyInfo.Sort = 0 //那就是排在第一位
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = excelClassifyInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+			//更新对应分类的root_id和层级
+			if oldParentId != parentClassifyId {
+				/*if len(classifyIds) > 0 {
+					levelStep := excelClassifyInfo.Level - oldLevel
+					err = data_manage.UpdateEdbClassifyChildByParentClassifyId(classifyIds, excelClassifyInfo.RootId, levelStep)
+					if err != nil {
+						errMsg = "移动失败"
+						err = errors.New("更新子分类失败,Err:" + err.Error())
+						return
+					}
+				}*/
+			}
+		}
+	} else {
+		if excelInfo == nil {
+			errMsg = "当前表格不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		//如果改变了分类,那么移动该表格数据
+		if excelInfo.ExcelClassifyId != parentClassifyId {
+			excelInfo.ExcelClassifyId = parentClassifyId
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ExcelClassifyId", "ModifyTime")
+		}
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == excelInfo.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+					}
+
+					//变更表格
+					if prevExcelInfo != nil {
+						//变更兄弟节点的排序
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						//变更分类
+						if prevClassify != nil {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevSort, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+						}
+
+						//变更表格
+						if prevExcelInfo != nil {
+							//变更兄弟节点的排序
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+						}
+					}
+				}
+			}
+
+			excelInfo.Sort = prevSort + 1
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevExcelInfo == nil && nextExcelInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetExcelClassifyMaxSort(parentClassifyId, source)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			excelInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级分类的第一位
+			firstClassify, tmpErr := excel.GetFirstExcelClassifyByParentId(parentClassifyId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, firstClassify.ExcelClassifyId-1, 0, updateSortStr, source)
+				//该分类下的所有表格也需要+1
+				_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr, source)
+			} else {
+				//如果该分类下存在表格,且第一个表格的排序等于0,那么需要调整排序
+				firstExcel, tErr := excel.GetFirstExcelInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstExcel != nil && firstExcel.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, firstExcel.ExcelInfoId-1, updateSortStr, source)
+					_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, source)
+				}
+			}
+
+			excelInfo.Sort = 0 //那就是排在第一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = excelInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+	return
+}

+ 519 - 67
services/data/excel/mixed_table.go

@@ -73,7 +73,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	// 日度指标数据map
 	edbDayDataListMap := make(map[int]map[string]float64)
 	// 月度指标数据map
-	edbMonthDataListMap := make(map[int]map[string]float64)
+	edbMonthDataListMap := make(map[int]map[string]string)
 	// 日度指标数据map
 	edbDataListMap := make(map[int][]*data_manage.EdbDataList)
 	for _, edbInfo := range edbInfoList {
@@ -90,18 +90,19 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 		}
 
 		dateValMap := make(map[string]float64)
-		monthValMap := make(map[string]float64)
+		monthDateMap := make(map[string]string)
 		for _, tmpData := range dataList {
 			// 日度数据
 			dateValMap[tmpData.DataTime] = tmpData.Value
 			// 月度数据(取该月份的第一个数据)
 			yearMonth := strings.Join(strings.Split(tmpData.DataTime, "-")[0:2], "-")
-			if _, ok := monthValMap[yearMonth]; !ok {
-				monthValMap[yearMonth] = tmpData.Value
+			if _, ok := monthDateMap[yearMonth]; !ok {
+				// 存最早的时间
+				monthDateMap[yearMonth] = tmpData.DataTime
 			}
 		}
 		edbDayDataListMap[edbInfo.EdbInfoId] = dateValMap
-		edbMonthDataListMap[edbInfo.EdbInfoId] = monthValMap
+		edbMonthDataListMap[edbInfo.EdbInfoId] = monthDateMap
 		edbDataListMap[edbInfo.EdbInfoId] = dataList
 	}
 
@@ -119,9 +120,19 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				if err != nil {
 					return
 				}
-				if edbInfo, ok := edbInfoMap[edbDateConfig.EdbInfoId]; ok {
-					cell.ShowValue = edbInfo.EndDate
-					cell.DataTime = edbInfo.EndDate
+				if dataList, ok := edbDataListMap[edbDateConfig.EdbInfoId]; ok {
+					// todo 获取配置信息,根据配置信息进行日期变换, 是否需要更新当前记录,将历史记录逐渐转换成新的记录
+					var newDate string
+					newDate, err = GetEdbDateByMoveForward(config[k][i].Value, dataList)
+					if err != nil {
+						return
+					}
+					newDate, err = HandleMixTableDateChange(newDate, config[k][i].Value)
+					if err != nil {
+						return
+					}
+					cell.ShowValue = newDate
+					cell.DataTime = newDate
 					config[k][i] = cell
 				}
 			}
@@ -133,7 +144,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	}
 
 	// 指标计算的结果map
-	edbSourceDataMap := make(map[string]map[string]float64)
+	edbSourceDataMap := make(map[string]data.BaseCalculateDataResp)
 
 	// 单元格对应的key与他的值(只处理数据类型)
 	cellKeyVal := make(map[string]float64)
@@ -141,6 +152,8 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	// 基础计算单元格的位置信息
 	calculateCellMap := make(map[string]Cell)
 	calculateChainList := make([]string, 0)
+	dateCalculateList := make([]string, 0)
+	showStyleList := make([]string, 0)
 
 	// 处理单元格中的数据类型(除去基础计算,因为这个是依赖于其他)
 	for k, row := range config {
@@ -160,7 +173,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				//cell.Value = ``
 
 				// 日期关系配置不存在,则默认最新数据
-				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok {
+				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok { //表示表格日期
 					if relationConf.RelationDate.Key == `` {
 						// 日期关系配置未绑定
 						continue
@@ -178,11 +191,21 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 					if dateValMap, ok := edbDayDataListMap[cell.EdbInfoId]; ok {
 						tmpDateValMap = dateValMap
 					}
+					// todo 根据配置进行日期变换
+					relationDate := relationCell.DataTime
+					if strings.Contains(cell.Value, "{") {
+						relationDate, err = HandleMixTableDateChange(relationDate, cell.Value)
+						if err != nil {
+							return
+						}
+					} else {
+						cell.Value = ""
+					}
 
-					if val, ok2 := tmpDateValMap[relationCell.DataTime]; ok2 {
+					if val, ok2 := tmpDateValMap[relationDate]; ok2 {
 						//cell.ShowValue = fmt.Sprint(val)
 						cellKeyVal[cell.Uid] = val
-						cell.ShowValue = utils.FormatTableDataShowValue(val)
+						cell.ShowValue = utils.FormatMixTableDataShowValue(val)
 					}
 				} else {
 					// 如果不是取得一个关联的日期,那么就是指定日期
@@ -192,38 +215,67 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 						if dateValList, ok := edbDataListMap[cell.EdbInfoId]; ok {
 							tmpLenData := len(dateValList)
 							if tmpLenData > 0 {
-								cellKeyVal[cell.Uid] = dateValList[tmpLenData-1].Value
-								cell.ShowValue = utils.FormatTableDataShowValue(dateValList[tmpLenData-1].Value)
+								//做期数前移动和日期变换
+								if !strings.Contains(cell.Value, "{") {
+									cell.Value = ""
+								}
+								var newDate string
+								newDate, err = GetEdbDateByMoveForward(cell.Value, dateValList)
+								if err != nil {
+									return
+								}
+								newDate, err = HandleMixTableDateChange(newDate, cell.Value)
+								if err != nil {
+									return
+								}
+								var finalVal string
+								for _, v := range dateValList {
+									if v.DataTime == newDate {
+										finalVal = utils.FormatMixTableDataShowValue(v.Value)
+										cellKeyVal[cell.Uid] = v.Value
+										break
+									}
+								}
+
+								cell.ShowValue = finalVal
 							}
 						}
 					} else {
 						tmpDateList := strings.Split(cell.DataTime, "-")
 						tmpDateValMap := make(map[string]float64)
+						var newDate string
 						if len(tmpDateList) == 2 {
 							//月度数据
-							if dateValMap, ok := edbMonthDataListMap[cell.EdbInfoId]; ok {
-								tmpDateValMap = dateValMap
+							if dateMap, ok1 := edbMonthDataListMap[cell.EdbInfoId]; ok1 {
+								if d, ok2 := dateMap[cell.DataTime]; ok2 {
+									newDate = d
+								}
 							}
 						} else {
 							// 日度数据
-							if dateValMap, ok := edbDayDataListMap[cell.EdbInfoId]; ok {
-								tmpDateValMap = dateValMap
-							}
+							newDate = cell.DataTime
+						}
+						// 日期变换后才能确定最后的时间
+						//做期数前移动和日期变换
+						if !strings.Contains(cell.Value, "{") {
+							cell.Value = ""
+						}
 
+						newDate, err = HandleMixTableDateChange(newDate, cell.Value)
+						if err != nil {
+							return
 						}
-						if val, ok2 := tmpDateValMap[cell.DataTime]; ok2 {
-							//cell.ShowValue = fmt.Sprint(val)
-							cellKeyVal[cell.Uid] = val
-							cell.ShowValue = utils.FormatTableDataShowValue(val)
+
+						if dateValMap, ok3 := edbDayDataListMap[cell.EdbInfoId]; ok3 {
+							tmpDateValMap = dateValMap
+							if val, ok2 := tmpDateValMap[cell.DataTime]; ok2 {
+								//cell.ShowValue = fmt.Sprint(val)
+								cellKeyVal[cell.Uid] = val
+								cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+							}
 						}
 					}
 				}
-
-				calculateCellMap[cell.Uid] = Cell{
-					Column:   k,
-					Row:      i,
-					CellInfo: cell,
-				}
 			case request.CustomTextDT: //自定义文本
 				if cell.Value == `` {
 					continue
@@ -233,27 +285,21 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				if tmpErr == nil {
 					tmpVal, _ := tmpDeci.Float64()
 					cellKeyVal[cell.Uid] = tmpVal
-
-					calculateCellMap[cell.Uid] = Cell{
-						Column:   k,
-						Row:      i,
-						CellInfo: cell,
-					}
 				}
 
 			case request.FormulateCalculateDataDT: // 公式计算(A+B这种)
-				calculateCellMap[cell.Uid] = Cell{
-					Column:   k,
-					Row:      i,
-					CellInfo: cell,
-				}
-
 				calculateChainList = append(calculateChainList, cell.Uid)
 
 			case request.InsertEdbCalculateDataDT: // 插入指标系统计算公式生成的值
+				// 处理value的值
+				if !strings.Contains(cell.Value, "EdbInfoId") && cell.EdbInfoId > 0 {
+					cell.Value, _ = fixCalculateValueConfig(cell.Value, cell.EdbInfoId)
+					row[i] = cell
+				}
 				// 日期
 				var cellDateTime string
 				// 日期关系配置不存在,则默认最新数据
+				// 从绑定的单元格中获取数据的日期
 				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok {
 					if relationConf.RelationDate.Key == `` {
 						// 日期关系配置未绑定
@@ -271,7 +317,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				var tmpDataMap map[string]float64
 
 				key := utils.MD5(cell.Value)
-				tmpDataMap, ok := edbSourceDataMap[key]
+				respItemData, ok := edbSourceDataMap[key]
 				if !ok {
 					// 对应的配置值
 					var tmpConfig request.CalculateConf
@@ -318,22 +364,59 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 						continue
 					}
 
-					tmpDataMap = respItem.Data.DataMap
+					//tmpDataMap = respItem.Data.DataMap
 					// 计算结果存一份,万一存在重复的计算方式,那么省的重新计算一下
-					edbSourceDataMap[key] = tmpDataMap
-
-					lenDataList := len(respItem.Data.DateList)
-					if cellDateTime == `` && lenDataList > 0 {
-						cellDateTime = respItem.Data.DateList[lenDataList-1]
+					edbSourceDataMap[key] = respItem.Data
+					respItemData = respItem.Data
+				}
+				lenDataList := len(respItemData.DateList)
+				tmpDataMap = respItemData.DataMap
+				if cellDateTime == `` && lenDataList > 0 {
+					//判断是否需要做期数前移动
+					cellDateTime = respItemData.DateList[lenDataList-1]
+					cellDateTime, err = GetEdbDateByMoveForwardByDateList(cell.Value, respItemData.DateList)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("日期前移失败,配置信息;%s", cell.Value))
+						continue
 					}
 				}
+				// 进行日期变换
+				cellDateTime, err = HandleMixTableDateChange(cellDateTime, cell.Value)
+				if err != nil {
+					utils.FileLog.Error(fmt.Sprintf("日期变换失败,配置信息;%s, 日期:%s", cell.Value, cellDateTime))
+					continue
+				}
+				val, ok := tmpDataMap[cellDateTime]
+				if ok {
+					cellKeyVal[cell.Uid] = val
+					cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+				} else {
+					cell.ShowValue = ""
+				}
 
-				val := tmpDataMap[cellDateTime]
-				cellKeyVal[cell.Uid] = val
-				cell.ShowValue = utils.FormatTableDataShowValue(val)
+			case request.DateCalculateDataDT: //日期计算
+				dateCalculateList = append(dateCalculateList, cell.Uid)
+				// 遍历数组,根据公式进行计算,并将得到的结果放到对应的单元格中
 			}
+			row[i] = cell
+		}
+		config[k] = row
+	}
 
+	// 处理指定指标的日期
+	for k, row := range config {
+		for i, cell := range row {
+			calculateCellMap[cell.Uid] = Cell{
+				Column:   k,
+				Row:      i,
+				CellInfo: cell,
+			}
+			cell.ShowFormatValue = cell.ShowValue
+			if cell.ShowStyle != `` {
+				showStyleList = append(showStyleList, cell.Uid)
+			}
 			row[i] = cell
+			cellDataRelationMap[cell.Uid] = cell
 		}
 		config[k] = row
 	}
@@ -364,12 +447,24 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 			}
 
 			cellKeyVal[cell.Uid] = val
-			cell.ShowValue = utils.FormatTableDataShowValue(val)
+			cell.ShowValue = utils.FormatMixTableDataShowValue(val)
 			config[cellPosition.Column][cellPosition.Row] = cell
 
 		}
 	}
 
+	// 日期计算
+	config, err, errMsg = handlerDateCalculate(dateCalculateList, calculateCellMap, config)
+	if err != nil {
+		return
+	}
+
+	// 格式化展示
+	config, err, errMsg = handleMixCellShowStyle(showStyleList, calculateCellMap, config)
+	if err != nil {
+		return
+	}
+
 	newMixedTableCellDataList = config
 
 	return
@@ -475,11 +570,15 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 				if err != nil {
 					return
 				}
-				edbInfoIdList = append(edbInfoIdList, config.EdbInfoId)
+				if config.EdbInfoId == 0 && cell.EdbInfoId > 0 {
+					edbInfoIdList = append(edbInfoIdList, cell.EdbInfoId)
+				} else {
+					edbInfoIdList = append(edbInfoIdList, config.EdbInfoId)
+				}
 				dataEdbInfoIdList = append(dataEdbInfoIdList, cell.EdbInfoId)
 
 			case request.DateDT: // 日期类型
-				date, tmpErr, tmpErrMsg := handleDate(cell.DataTimeType, cell.Value)
+				date, newVal, tmpErr, tmpErrMsg := handleDate(cell.DataTimeType, cell.Value)
 				if tmpErr != nil {
 					err = tmpErr
 					errMsg = tmpErrMsg
@@ -487,6 +586,7 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 				}
 				rowList[rk].DataTime = date
 				rowList[rk].ShowValue = date
+				rowList[rk].Value = newVal //兼容原有的历史数据中系统导入日期
 
 				// 指标日期类型的单元格需要额外将指标id取出来
 				if cell.DataTimeType == request.EdbDateDT {
@@ -516,7 +616,7 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 // @return date string
 // @return err error
 // @return errMsg string
-func HandleDate(dataTimeType int, val string) (date string, err error, errMsg string) {
+func HandleDate(dataTimeType int, val string) (date string, newVal string, err error, errMsg string) {
 	return handleDate(dataTimeType, val)
 }
 
@@ -529,17 +629,39 @@ func HandleDate(dataTimeType int, val string) (date string, err error, errMsg st
 // @return date string
 // @return err error
 // @return errMsg string
-func handleDate(dataTimeType int, val string) (date string, err error, errMsg string) {
+func handleDate(dataTimeType int, val string) (date string, newVal string, err error, errMsg string) {
+	newVal = val
 	if val == `` {
 		errMsg = "错误的日期数据"
 		err = errors.New(errMsg)
 		return
 	}
+
 	switch dataTimeType {
 	case request.CustomDateT: //手动输入日期
+		/*if !strings.Contains(val, "{") {
+			newVal, err, errMsg = handleOldCustomerDateT(val)
+			if err != nil {
+				return
+			}
+		}
+		date, err = HandleMixTableDateChange("", newVal)
+		if err != nil {
+			return
+		}*/
 		date = val
+		return
 	case request.SystemDateT: // 系统日期
-		date, err, errMsg = handleSystemDateT(val)
+		date = time.Now().Format(utils.FormatDate)
+		newVal, err, errMsg = handleOldSystemDateT(val)
+		if err != nil {
+			return
+		}
+		date, err = HandleMixTableDateChange(date, newVal)
+		if err != nil {
+			return
+		}
+
 	case request.EdbDateDT: // 导入指标日期(指标库的最新日期)
 	default:
 		errMsg = "错误的日期类型"
@@ -550,30 +672,134 @@ func handleDate(dataTimeType int, val string) (date string, err error, errMsg st
 	return
 }
 
-// handleSystemDateT
-// @Description: 处理导入系统日期
+func GetEdbDateByMoveForward(conf string, edbDataList []*data_manage.EdbDataList) (date string, err error) {
+	dateList := make([]string, 0)
+	for _, v := range edbDataList {
+		dateList = append(dateList, v.DataTime)
+	}
+
+	date, err = GetEdbDateByMoveForwardByDateList(conf, dateList)
+	return
+}
+
+func GetEdbDateByMoveForwardByDateList(conf string, dateList []string) (date string, err error) {
+	moveForward := 0
+	if conf != "" {
+		var edbDateConf request.EdbDateChangeConf
+		err = json.Unmarshal([]byte(conf), &edbDateConf)
+		if err != nil {
+			err = fmt.Errorf("日期变换配置json解析失败失败: %s", err.Error())
+			return
+		}
+		moveForward = edbDateConf.MoveForward
+	}
+	// 根据日期进行排序
+	index := len(dateList) - 1 - moveForward
+	for k, v := range dateList {
+		if k == index {
+			date = v
+			return
+		}
+	}
+	return
+}
+
+// HandleMixTableDateChange 处理表格中的日期变换
+func HandleMixTableDateChange(date, conf string) (newDate string, err error) {
+	newDate = date
+	if conf == "" {
+		return
+	}
+	var edbDateConf request.EdbDateConf
+	err = json.Unmarshal([]byte(conf), &edbDateConf)
+	if err != nil {
+		err = fmt.Errorf("日期变换配置json解析失败失败: %s, Err:%s", conf, err.Error())
+		return
+	}
+
+	if newDate != "" {
+		if len(edbDateConf.DateChange) > 0 {
+			var dateTime time.Time
+			dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+			if err != nil {
+				err = fmt.Errorf("日期解析失败: %s", err.Error())
+				return
+			}
+			for _, v := range edbDateConf.DateChange {
+				if v.ChangeType == 1 {
+					dateTime = dateTime.AddDate(v.Year, v.Month, v.Day)
+					newDate = dateTime.Format(utils.FormatDate)
+				} else if v.ChangeType == 2 {
+					newDate, err, _ = handleSystemAppointDateT(dateTime, v.FrequencyDay, v.Frequency)
+					if err != nil {
+						return
+					}
+					dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+					if err != nil {
+						err = fmt.Errorf("日期解析失败: %s", err.Error())
+						return
+					}
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// handleOldSystemDateT
+// @Description: 历史数据中的导入系统日期
 // @author: Roc
 // @datetime2023-10-27 09:36:21
 // @param confStr string
 // @return date string
 // @return err error
 // @return errMsg string
-func handleSystemDateT(confStr string) (date string, err error, errMsg string) {
+func handleOldSystemDateT(confStr string) (newConf string, err error, errMsg string) {
+	newConf = confStr
 	var config request.SystemDateConf
 	err = json.Unmarshal([]byte(confStr), &config)
 	if err != nil {
 		return
 	}
+
+	newConfig := new(request.EdbDateConf)
+	dateChange := new(request.EdbDateConfDateChange)
+
+	dateChangeList := make([]*request.EdbDateConfDateChange, 0)
+
 	switch config.Source {
 	case request.SystemCurrDateT:
-		date = time.Now().Format(utils.FormatDate)
+		return
 	case request.SystemCalculateDateT:
-		date, err, errMsg = handleSystemCalculateDateT(config.CalculateNum, config.CalculateFrequency)
+		// todo 是否直接更新该excel记录,
+		dateChange.Day = config.CalculateNum
+		dateChange.ChangeType = 1
+		dateChangeList = append(dateChangeList, dateChange)
+		newConfig.DateChange = dateChangeList
+		newConfByte, e := json.Marshal(newConfig)
+		if e != nil {
+			err = fmt.Errorf("日期计算额外配置,json序列化失败: %s", e.Error())
+			return
+		}
+		newConf = string(newConfByte)
+		return
 	case request.SystemFrequencyDateT: // 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
-		date, err, errMsg = handleSystemAppointDateT(config.Day, config.Frequency)
+		dateChange.FrequencyDay = config.Day
+		dateChange.Frequency = config.Frequency
+		dateChange.ChangeType = 1
+		dateChangeList = append(dateChangeList, dateChange)
+		newConfig.DateChange = dateChangeList
+		newConfByte, e := json.Marshal(newConfig)
+		if e != nil {
+			err = fmt.Errorf("日期计算额外配置,json序列化失败: %s", e.Error())
+			return
+		}
+		newConf = string(newConfByte)
+		return
 	default:
-		errMsg = "错误的日期日期导入方式"
-		err = errors.New(fmt.Sprint("错误的日期日期导入方式:", config.Source))
+		//errMsg = "错误的日期日期导入方式"
+		//err = errors.New(fmt.Sprint("错误的日期日期导入方式:", config.Source))
 		return
 	}
 
@@ -615,8 +841,8 @@ func handleSystemCalculateDateT(num int, frequency string) (date string, err err
 // @return date string
 // @return err error
 // @return errMsg string
-func handleSystemAppointDateT(appointDay, frequency string) (date string, err error, errMsg string) {
-	currDate := time.Now()
+func handleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) {
+	//currDate := time.Now()
 	switch frequency {
 	case "本周":
 		day := int(currDate.Weekday())
@@ -813,3 +1039,229 @@ func calculateByCellList(calculateFormula string, tagList []utils.CellPosition)
 
 	return
 }
+
+// handlerDateCalculate 处理日期计算
+func handlerDateCalculate(dateCalculateList []string, calculateCellMap map[string]Cell, oldConfig [][]request.MixedTableCellDataReq) (config [][]request.MixedTableCellDataReq, err error, errMsg string) {
+	config = oldConfig
+	if len(dateCalculateList) == 0 {
+		return
+	}
+	if len(dateCalculateList) > 0 {
+		for _, cellKey := range dateCalculateList {
+			// 查找这个单元格的位置,直接map找了,而不是遍历整个单元格
+			cellPosition, ok := calculateCellMap[cellKey]
+			if !ok {
+				utils.FileLog.Error("找不到单元格位置:", cellKey)
+				continue
+			}
+
+			cell := config[cellPosition.Column][cellPosition.Row]
+			if cell.DataType != request.DateCalculateDataDT { // 判断公式计算(A+B这种)类型,不是的话也过滤了
+				continue
+			}
+
+			val, tmpErr, tmpErrMsg := DateCalculatePrepare(calculateCellMap, cell.Value)
+			if tmpErr != nil {
+				errMsg = tmpErrMsg
+				err = tmpErr
+				return
+			}
+
+			cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+			config[cellPosition.Column][cellPosition.Row] = cell
+		}
+	}
+	return
+}
+
+// DateCalculatePrepare 单个单元格的日期计算
+func DateCalculatePrepare(calculateCellMap map[string]Cell, config string) (val float64, err error, errMsg string) {
+	var edbDateConf request.MixDateCalculateConf
+	err = json.Unmarshal([]byte(config), &edbDateConf)
+	if err != nil {
+		err = fmt.Errorf("日期计算配置json解析失败失败: %s, Err:%s", config, err.Error())
+		return
+	}
+	if len(edbDateConf.RelationCellList) == 0 {
+		err = fmt.Errorf("日期计算 未配置日期单元格失败: %s", config)
+		return
+	}
+	valMap := make(map[string]int)
+	for _, v := range edbDateConf.RelationCellList {
+		// 查找单元格数据
+		cell, ok := calculateCellMap[v.Uid]
+		if !ok {
+			err = fmt.Errorf("查找单元格:%s 的数据失败", v.Uid)
+			return
+		}
+		colData := cell.CellInfo
+
+		// 如果不是基础计算单元格,直接返回
+		_, err = time.ParseInLocation(utils.FormatDate, colData.ShowValue, time.Local)
+		if err != nil {
+			err = fmt.Errorf("%s 的单元格非日期类型, Err: %s", colData.ShowValue, err.Error())
+			return
+		}
+		// todo 把日期转换成excel里的天数
+		realDiffDay := utils.GetDaysDiff1900(colData.ShowValue)
+
+		valMap[strings.ToUpper(v.Tag)] = realDiffDay
+	}
+
+	// 计算
+	val, errMsg, err = DateCalculateFormula(valMap, strings.ToUpper(edbDateConf.Formula))
+	if err != nil {
+		return
+	}
+	return
+}
+
+func DateCalculateFormula(valTagMap map[string]int, calculateFormula string) (calVal float64, 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.ReplaceFormulaByTagMap(valTagMap, calculateFormula)
+
+	if formulaFormStr == `` {
+		errMsg = "公式异常"
+		err = errors.New(errMsg)
+		return
+	}
+	fmt.Println("公式:" + formulaFormStr)
+	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, err = calResult.Float64()
+	if err != nil {
+		return
+	}
+
+	// 转Decimal然后四舍五入
+	calVal, _ = decimal.NewFromFloat(calVal).Round(4).Float64()
+
+	return
+}
+
+// handleMixCellShowStyle 处理混合表格中,显示计算的逻辑
+func handleMixCellShowStyle(showStyleList []string, calculateCellMap map[string]Cell, oldConfig [][]request.MixedTableCellDataReq) (config [][]request.MixedTableCellDataReq, err error, errMsg string) {
+	config = oldConfig
+	if len(showStyleList) == 0 {
+		return
+	}
+	if len(showStyleList) > 0 {
+		for _, cellKey := range showStyleList {
+			// 查找这个单元格的位置,直接map找了,而不是遍历整个单元格
+			cellPosition, ok := calculateCellMap[cellKey]
+			if !ok {
+				utils.FileLog.Error("找不到单元格位置:", cellKey)
+				continue
+			}
+
+			cell := config[cellPosition.Column][cellPosition.Row]
+			val := cell.ShowValue
+			isPercent := false
+			if strings.Contains(val, "%") {
+				isPercent = true
+				val = strings.Trim(val, "%")
+			}
+			_, e := strconv.ParseFloat(val, 64) // 将字符串转换成float类型
+			if e != nil {                       // 如果没有错误发生则返回true,说明该字符串是一个合法的数字
+				continue
+			}
+			var styleConf request.MixCellShowStyle
+			err = json.Unmarshal([]byte(cell.ShowStyle), &styleConf)
+			if err != nil {
+				err = fmt.Errorf("日期计算配置json解析失败失败: %s, Err:%s", config, err.Error())
+				return
+			}
+			if styleConf.Pn != 0 || styleConf.Nt != "" {
+				val = changePointDecimalPlaces(val, styleConf.Pn, styleConf.Nt, isPercent)
+				cell.ShowFormatValue = val
+			} else {
+				cell.ShowFormatValue = cell.ShowValue
+			}
+			config[cellPosition.Column][cellPosition.Row] = cell
+		}
+	}
+	return
+}
+
+// changePointDecimalPlaces 小数点位数加减和百分比格式
+func changePointDecimalPlaces(str string, changeNum int, numberType string, isPercent bool) (newStr string) {
+	newStr = str
+	// 把字符串转成浮点数
+	val, _ := strconv.ParseFloat(str, 64)
+	if isPercent {
+		if numberType == "number" { //百分数转成小数
+			val = val / 100
+			isPercent = false
+		}
+	} else {
+		if numberType == "percent" {
+			val = val * 100
+		}
+	}
+	newStr = fmt.Sprintf("%v", val)
+	var decimalPlaces int                  // 计算小数位数
+	dotIndex := strings.Index(newStr, ".") // 查找小数点的位置
+	if dotIndex == -1 {
+		decimalPlaces = 0
+	} else {
+		decimalPlaces = len(newStr) - dotIndex - 1
+	}
+	decimalPlaces += changeNum
+
+	if decimalPlaces < 0 {
+		decimalPlaces = 0
+	}
+	val, _ = decimal.NewFromFloat(val).Round(int32(decimalPlaces)).Float64()
+	newStr = strconv.FormatFloat(val, 'f', decimalPlaces, 64)
+	if numberType == "percent" || isPercent {
+		newStr += "%"
+	}
+	return
+}
+
+func fixCalculateValueConfig(conf string, edbInfoId int) (newConf string, err error) {
+	newConf = conf
+	if edbInfoId == 0 {
+		return
+	}
+	var tmpConfig request.CalculateConf
+	err = json.Unmarshal([]byte(conf), &tmpConfig)
+	if err != nil {
+		return
+	}
+	if tmpConfig.EdbInfoId == 0 {
+		tmpConfig.EdbInfoId = edbInfoId
+		newConfByte, _ := json.Marshal(tmpConfig)
+		newConf = string(newConfByte)
+		return
+	}
+	return
+}

+ 18 - 0
utils/calculate.go

@@ -221,6 +221,24 @@ func ReplaceFormulaByCellList(cellList []CellPosition, formulaStr string) string
 	return formulaStr
 }
 
+func ReplaceFormulaByTagMap(valTagMap map[string]int, formulaStr string) string {
+	funMap := getFormulaMap()
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, k, v, -1)
+	}
+
+	replaceCount := 0
+	for tag, val := range valTagMap {
+		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"] = "[@@]"

+ 27 - 0
utils/common.go

@@ -637,6 +637,27 @@ func ConvertToFormatDay(excelDaysString string) string {
 	return resultTime
 }
 
+// GetDaysDiff1900 计算日期距离1900-01-01的天数
+func GetDaysDiff1900(date string) int {
+	// 将字符串转换为时间类型
+	//从1899年12月30日开始是因为Excel的日期计算是基于1900年1月1日的,而1900年并不是闰年,因此Excel日期计算存在一个错误。为了修正这个错误,
+	//我们将时间回溯到1899年12月30日,这样在进行日期计算时可以正确地处理Excel日期。
+	tStart, err := time.ParseInLocation(FormatDate, "1899-12-30", time.Local)
+	if err != nil {
+		return 0
+	}
+	tEnd, err := time.ParseInLocation(FormatDate, date, time.Local)
+	if err != nil {
+		return 0
+	}
+
+	// 计算两个日期之间的天数差值
+	duration := tEnd.Sub(tStart).Hours() / 24
+	days := int(duration)
+
+	return days
+}
+
 func CheckPwd(pwd string) bool {
 	compile := `([0-9a-z]+){6,12}|(a-z0-9]+){6,12}`
 	reg := regexp.MustCompile(compile)
@@ -2072,6 +2093,12 @@ func GetPredictEdbDayListByNum(startDate time.Time, num int, frequency string) (
 	return
 }
 
+// FormatMixTableDataShowValue 格式化自定表格显示数据
+func FormatMixTableDataShowValue(x float64) (res string) {
+	res = fmt.Sprint(x)
+	return
+}
+
 // FormatTableDataShowValue 格式化自定表格显示数据
 func FormatTableDataShowValue(x float64) (res string) {
 	if x > 1 || x < -1 {