浏览代码

Merge branch 'feature/eta1.8.5' into debug

xyxie 10 月之前
父节点
当前提交
dd05e1c0d5

+ 60 - 0
controllers/data_manage/chart_common.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"encoding/json"
 	"eta/eta_mobile/controllers/data_manage/correlation"
 	"eta/eta_mobile/controllers/data_manage/cross_variety"
 	"eta/eta_mobile/controllers/data_manage/future_good"
@@ -8,7 +9,12 @@ import (
 	"eta/eta_mobile/controllers/data_manage/line_feature"
 	"eta/eta_mobile/models"
 	"eta/eta_mobile/models/data_manage"
+	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/services/data"
+	"eta/eta_mobile/services/data/excel"
 	"eta/eta_mobile/utils"
+	"fmt"
+	"time"
 )
 
 // CommonChartInfoDetailFromUniqueCode
@@ -150,9 +156,63 @@ func (this *ChartInfoController) CommonChartInfoDetailFromUniqueCode() {
 		br.Success = true
 		br.Msg = "获取成功"
 		br.Data = resp
+	case utils.CHART_SOURCE_BALANCE_EXCEL:
+		resp, isOk, msg, errMsg := getBalanceChartInfoDetailFromUniqueCode(chartInfo, isCache, sysUser)
+		if !isOk {
+			br.Msg = msg
+			br.ErrMsg = errMsg
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
 	default:
 		br.Msg = "错误的图表"
 		br.ErrMsg = "错误的图表"
 		return
 	}
 }
+
+func getBalanceChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	resp = new(data_manage.ChartInfoDetailFromUniqueCodeResp)
+	resp, isOk, msg, errMsg = data.CheckBalanceChartCacheAndPermission(chartInfo, isCache, sysUser)
+	if isOk {
+		return
+	}
+	msg = `获取失败`
+	// 相关联指标
+	mappingListTmp, dataListMap, err, errMsg := excel.GetBalanceExcelChartSingle(chartInfo, "")
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	var chartInfoResp *data_manage.ChartInfoDetailResp
+	chartInfoResp, err, errMsg = data.GetBalanceExcelChartDetail(chartInfo, mappingListTmp, sysUser, dataListMap)
+	if err != nil {
+		msg = "查询图表详情失败"
+		errMsg = "查询图表详情失败,Err:" + err.Error()
+		return
+	}
+	resp = &data_manage.ChartInfoDetailFromUniqueCodeResp{
+		ChartInfo:            chartInfoResp.ChartInfo,
+		Status:               true,
+		EdbInfoList:          chartInfoResp.EdbInfoList,
+		XEdbIdValue:          chartInfoResp.XEdbIdValue,
+		YDataList:            chartInfoResp.YDataList,
+		XDataList:            chartInfoResp.XDataList,
+		BarChartInfo:         chartInfoResp.BarChartInfo,
+		CorrelationChartInfo: chartInfoResp.CorrelationChartInfo,
+		DataResp:             chartInfoResp.DataResp,
+	}
+	// 将数据加入缓存
+	if utils.Re == nil {
+		cacheData, _ := json.Marshal(resp)
+		key := data.GetChartInfoDataKey(chartInfo.ChartInfoId)
+		utils.Rc.Put(key, cacheData, 2*time.Hour)
+	}
+	isOk = true
+
+	return
+}

+ 44 - 0
models/data_manage/excel/excel_chart_data.go

@@ -0,0 +1,44 @@
+package excel
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ExcelChartData struct {
+	ExcelChartDataId int `orm:"column(excel_chart_data_id);pk"`
+	ExcelInfoId      int `description:"表格id"`
+	ExcelChartEdbId  int `description:"指标ID"`
+	DataTime         string
+	Value            float64
+	ModifyTime       time.Time `description:"修改时间"`
+	CreateTime       time.Time `description:"创建时间"`
+	DataTimestamp    int64
+}
+
+func (e *ExcelChartData) TableName() string {
+	return "excel_chart_data"
+}
+
+// 新增
+func (e *ExcelChartData) Add() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Insert(e)
+	return
+}
+
+// 修改
+func (e *ExcelChartData) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
+// 删除
+func (e *ExcelChartData) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(e)
+	return
+}
+
+// 查询

+ 333 - 0
models/data_manage/excel/excel_chart_edb.go

@@ -0,0 +1,333 @@
+package excel
+
+import (
+	"eta/eta_mobile/models/data_manage"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type ExcelChartEdb struct {
+	ExcelChartEdbId int       `orm:"column(excel_chart_edb_id);pk"`
+	ExcelInfoId     int       `description:"表格id"`
+	ChartInfoId     int       `description:"图表id"`
+	EdbCode         string    `description:"指标编码"`
+	EdbName         string    `description:"指标名称"`
+	DateSequence    string    `description:"日期序列选区"`
+	DataSequence    string    `description:"数据序列选区"`
+	SysUserId       int       `description:"创建人"`
+	SysUserRealName string    `description:"创建人姓名"`
+	MaxData         float64   `description:"上限"`
+	MinData         float64   `description:"下限"`
+	IsOrder         bool      `description:"true:正序,false:逆序"`
+	IsAxis          int       `description:"true:左轴,false:右轴"`
+	EdbInfoType     int       `description:"true:标准指标,false:领先指标"`
+	LeadValue       int       `description:"领先值"`
+	LeadUnit        string    `description:"领先单位"`
+	FromTag         string    `description:"标签"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+	ChartWidth      float64   `description:"线条大小"`
+}
+
+type ExcelChartEdbView struct {
+	ExcelChartEdbId int
+	ExcelInfoId     int    `description:"表格id"`
+	ChartInfoId     int    `description:"图表id"`
+	EdbCode         string `description:"指标编码"`
+	EdbName         string `description:"指标名称"`
+	DateSequenceStr string `description:"日期序列选区"`
+	DataSequenceStr string `description:"数据序列选区"`
+	/*MaxData         float64 `description:"上限"`
+	MinData         float64 `description:"下限"`
+	IsOrder         bool    `description:"true:正序,false:逆序"`
+	IsAxis          int     `description:"true:左轴,false:右轴"`
+	EdbInfoType     int     `description:"true:标准指标,false:领先指标"`
+	LeadValue       int     `description:"领先值"`
+	LeadUnit        string  `description:"领先单位"`*/
+	FromTag string `description:"标签"`
+}
+
+type BalanceTableChart struct {
+	ChartInfoId       int    `description:"图表id,新增时传0"`
+	ChartName         string `description:"图表名称"`
+	ChartType         int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图"`
+	Calendar          string `description:"公历/农历"`
+	LeftMin           string `description:"图表左侧最小值"`
+	LeftMax           string `description:"图表左侧最大值"`
+	RightMin          string `description:"图表右侧最小值"`
+	RightMax          string `description:"图表右侧最大值"`
+	Right2Min         string `description:"图表右侧2最小值"`
+	Right2Max         string `description:"图表右侧2最大值"`
+	MinMaxSave        int    `description:"是否手动保存过上下限:0-否;1-是"`
+	ExtraConfig       string `description:"图表额外配置信息,json字符串"`
+	ChartImage        string `description:"封面图" json:"-"`
+	SeasonExtraConfig string `description:"季节性图表中的配置,json数据"`
+	SourcesFrom       string `description:"图表来源"`
+	//	ChartEdbInfoList  []ExcelChartEdbView
+}
+
+func (e *ExcelChartEdb) TableName() string {
+	return "excel_chart_edb"
+}
+
+// 新增
+func (e *ExcelChartEdb) Add() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Insert(e)
+	return
+}
+
+// 修改
+func (e *ExcelChartEdb) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
+// 删除
+func (e *ExcelChartEdb) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(e)
+	return
+}
+
+type AddChartEdbAndDataItem struct {
+	ChartEdb *ExcelChartEdb
+	DateList []string  `description:"日期列表"`
+	ValList  []float64 `description:"数据列表"`
+}
+
+// 同时添加指标和指标数据
+func (e *ExcelChartEdb) AddChartEdbAndData(list []*AddChartEdbAndDataItem, chartInfo *data_manage.ChartInfo, deleteEdbIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+
+	// 先删除原先的绑定的指标
+	if len(deleteEdbIds) > 0 && chartInfo.ChartInfoId > 0 {
+		sql := `DELETE FROM excel_chart_edb WHERE excel_chart_info_id = ? AND excel_chart_edb_id in (` + utils.GetOrmInReplace(len(deleteEdbIds)) + `)`
+		_, err = o.Raw(sql, chartInfo.ChartInfoId, deleteEdbIds).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除原先的指标失败:%v", err)
+			return
+		}
+	}
+	// 图表指标信息入库
+	updateIds := make([]int, 0)
+	var edbInfoIdArrStr []string
+	for _, item := range list {
+		err = addChartEdbAndData(o, item.ChartEdb, item.DateList, item.ValList)
+		if err != nil {
+			return
+		}
+		updateIds = append(updateIds, item.ChartEdb.ExcelChartEdbId)
+		edbInfoIdArrStr = append(edbInfoIdArrStr, strconv.Itoa(item.ChartEdb.ExcelChartEdbId))
+	}
+
+	//新增图表
+	chartInfoId := chartInfo.ChartInfoId
+	if chartInfo.ChartInfoId <= 0 {
+		lastId, e := o.Insert(chartInfo)
+		if e != nil {
+			err = fmt.Errorf("新增图表失败,AddChartEdbAndData: %v", e)
+			return
+		}
+		chartInfoId = int(lastId)
+	} else {
+		_, err = o.Update(chartInfo)
+		if err != nil {
+			err = fmt.Errorf("更新图表失败,AddChartEdbAndData: %v", e)
+			return
+		}
+	}
+
+	//更新图表id
+	sql := `update excel_chart_edb set chart_info_id = ? where excel_chart_edb_id in (` + utils.GetOrmInReplace(len(updateIds)) + `)`
+	_, err = o.Raw(sql, chartInfoId, updateIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("更新图表id失败,AddChartEdbAndData: %v", err)
+		return
+	}
+
+	if len(edbInfoIdArrStr) > 0 {
+		edbInfoIdStr := strings.Join(edbInfoIdArrStr, ",")
+		//更新图表关联的指标id
+		sql = `update chart_info set edb_info_ids = ? where chart_info_id = ?`
+		_, err = o.Raw(sql, edbInfoIdStr, chartInfoId).Exec()
+	}
+	return
+}
+
+func addChartEdbAndData(o orm.TxOrmer, chartEdb *ExcelChartEdb, dateList []string, valList []float64) (err error) {
+	// 图表指标信息入库
+	excelChartEdbId := chartEdb.ExcelChartEdbId
+	if chartEdb.ExcelChartEdbId <= 0 {
+		lastId, e := o.Insert(chartEdb)
+		if e != nil {
+			err = fmt.Errorf("新增指标失败,addChartEdbAndData: %v", e)
+			return
+		}
+		excelChartEdbId = int(lastId)
+	} else {
+		_, e := o.Update(chartEdb)
+		if e != nil {
+			err = fmt.Errorf("更新指标失败,addChartEdbAndData: %v", e)
+			return
+		}
+		//如果有数据则删除所有的数据
+		sql := `delete from excel_chart_data where excel_chart_edb_id = ?`
+		_, err = o.Raw(sql, excelChartEdbId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	chartEdb.ExcelChartEdbId = excelChartEdbId
+
+	// 图表指标数据入库
+	addList := make([]*ExcelChartData, 0)
+	if len(dateList) > 0 && len(valList) > 0 {
+		for k, v := range dateList {
+			chartData := &ExcelChartData{
+				ExcelInfoId:     chartEdb.ExcelInfoId,
+				ExcelChartEdbId: chartEdb.ExcelChartEdbId,
+				DataTime:        v,
+				Value:           valList[k],
+				ModifyTime:      time.Now(),
+				CreateTime:      time.Now(),
+			}
+			//时间戳
+			currentDate, er := time.Parse(utils.FormatDate, v)
+			if er != nil {
+				err = fmt.Errorf("时间格式化失败 err:%v", er)
+				return
+			}
+			timestamp := currentDate.UnixNano() / 1e6
+			chartData.DataTimestamp = timestamp
+			addList = append(addList, chartData)
+			// data信息入库
+			if len(addList) > 1000 {
+				_, err = o.InsertMulti(len(addList), len(addList))
+				if err != nil {
+					return
+				}
+				addList = addList[:0]
+			}
+		}
+	}
+
+	// data信息入库
+	if len(addList) > 0 {
+		_, err = o.InsertMulti(len(addList), len(addList))
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func GetExcelChartEdbMappingByExcelInfoId(excelInfoId int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE excel_info_id=? 
+             ORDER BY excel_chart_edb_id ASC `
+	_, err = o.Raw(sql, excelInfoId).QueryRows(&list)
+	return
+}
+
+func GetExcelChartEdbMappingByExcelInfoIds(excelInfoIds []int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).QueryRows(&list)
+	return
+}
+
+func GetExcelChartEdbById(id int) (item *ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM excel_chart_edb WHERE excel_chart_edb_id=? `
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetExcelChartEdbMappingByChartInfoId(chartInfoId int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE chart_info_id=? 
+             ORDER BY excel_chart_edb_id ASC `
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&list)
+	return
+}
+
+func GetExcelInfoByChartInfoId(chartInfoId int) (item *ExcelInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT i.*
+             FROM excel_chart_edb e left join excel_info i on e.excel_info_id=i.excel_info_id
+			 WHERE e.chart_info_id=? limit 1`
+	err = o.Raw(sql, chartInfoId).QueryRow(&item)
+	return
+}
+
+// 同时删除指标和指标数据
+func DeleteExcelChartEdbAndData(excelInfoIds []int, chartInfoIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+	// 把对应的表格状态改成删除状态
+	//更新图表id
+	sql := `update excel_info set is_delete = 1, modify_time = ? where excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, time.Now(), excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("更新图表id失败,AddChartEdbAndData: %v", err)
+		return
+	}
+	// 把删除图表状态
+	if len(chartInfoIds) > 0 {
+		sql := `DELETE FROM chart_info WHERE  chart_info_id in (` + utils.GetOrmInReplace(len(chartInfoIds)) + `)`
+		_, err = o.Raw(sql, chartInfoIds).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除原先的指标失败:%v", err)
+			return
+		}
+
+		// todo 如果加入到我的图库中,则删除我的图库中的数据
+	}
+	// 删除原先的绑定的指标
+	sql = `DELETE FROM excel_chart_edb WHERE  excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除原先的指标失败:%v", err)
+		return
+	}
+	// 删除指标数据
+	sql = `DELETE FROM excel_chart_data WHERE  excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除原先的指标失败:%v", err)
+		return
+	}
+	return
+}

+ 22 - 16
models/data_manage/excel/excel_info.go

@@ -9,22 +9,28 @@ import (
 
 // ExcelInfo excel表格详情表
 type ExcelInfo struct {
-	ExcelInfoId      int       `orm:"column(excel_info_id);pk"`
-	Source           int       `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
-	ExcelType        int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
-	ExcelName        string    `description:"表格名称"`
-	UniqueCode       string    `description:"表格唯一编码"`
-	ExcelClassifyId  int       `description:"表格分类id"`
-	SysUserId        int       `description:"操作人id"`
-	SysUserRealName  string    `description:"操作人真实姓名"`
-	Content          string    `description:"表格内容"`
-	ExcelImage       string    `description:"表格图片"`
-	FileUrl          string    `description:"表格下载地址"`
-	Sort             int       `description:"排序字段,数字越小越排前面"`
-	IsDelete         int       `description:"是否删除,0:未删除,1:已删除"`
-	ModifyTime       time.Time `description:"最近修改日期"`
-	CreateTime       time.Time `description:"创建日期"`
-	IsJoinPermission int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	ExcelInfoId        int       `orm:"column(excel_info_id);pk"`
+	Source             int       `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
+	ExcelType          int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName          string    `description:"表格名称"`
+	UniqueCode         string    `description:"表格唯一编码"`
+	ExcelClassifyId    int       `description:"表格分类id"`
+	SysUserId          int       `description:"操作人id"`
+	SysUserRealName    string    `description:"操作人真实姓名"`
+	Content            string    `description:"表格内容"`
+	ExcelImage         string    `description:"表格图片"`
+	FileUrl            string    `description:"表格下载地址"`
+	Sort               int       `description:"排序字段,数字越小越排前面"`
+	IsDelete           int       `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime         time.Time `description:"最近修改日期"`
+	CreateTime         time.Time `description:"创建日期"`
+	IsJoinPermission   int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	ParentId           int       `description:"表格的父级id"`
+	BalanceType        int       `description:"平衡表类型:0 动态表,1静态表"`
+	UpdateUserId       int       `description:"更新人id"`
+	UpdateUserRealName string    `description:"更新人真实姓名"`
+	RelExcelInfoId     int       `description:"平衡表里静态表关联的动态表excel id"`
+	VersionName        string    `description:"静态表版本名称"`
 }
 
 // Update 更新 excel表格基础信息

+ 111 - 0
services/data/chart_info.go

@@ -3081,3 +3081,114 @@ func getEdbConvertDataMapList(chartInfoId, chartType int, calendar, startDate, e
 
 	return
 }
+
+// GetChartEdbDataV2 获取图表的指标数据
+func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, extraConfigStr string, seasonExtraConfig string, chartInfoData ChartInfoDataShow) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, yDataList []data_manage.YData, dataResp interface{}, err error, errMsg string) {
+	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
+	xEdbIdValue = make([]int, 0)
+	yDataList = make([]data_manage.YData, 0)
+
+	var extraConfig interface{}
+	switch chartType {
+	case 7: // 柱形图
+		var barConfig data_manage.BarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "柱方图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "柱方图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	case 10: // 截面散点图
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		extraConfig = tmpExtraConfig
+	case utils.CHART_TYPE_RADAR:
+		var barConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	default:
+		xEdbIdValue = make([]int, 0)
+		yDataList = make([]data_manage.YData, 0)
+	}
+
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err := chartInfoData.GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig)
+	if err != nil {
+		return
+	}
+
+	// 特殊图形数据处理
+	switch chartType {
+	case 7: // 柱形图
+		barChartConf := extraConfig.(data_manage.BarChartInfoReq)
+		xEdbIdValue, yDataList, err = BarChartData(mappingList, edbDataListMap, barChartConf.DateList, barChartConf.Sort)
+
+		for k := range yDataList {
+			yDataList[k].Unit = barChartConf.Unit
+			yDataList[k].UnitEn = barChartConf.UnitEn
+		}
+
+		for _, v := range edbList {
+			// 指标别名
+			if barChartConf.EdbInfoIdList != nil && len(barChartConf.EdbInfoIdList) > 0 {
+				for _, reqEdb := range barChartConf.EdbInfoIdList {
+					if v.EdbInfoId == reqEdb.EdbInfoId {
+						v.EdbAliasName = reqEdb.Name
+					}
+				}
+			}
+		}
+	case 10: // 截面散点图
+		sectionScatterConf := extraConfig.(data_manage.SectionScatterReq)
+		xEdbIdValue, dataResp, err = GetSectionScatterChartData(chartInfoId, mappingList, edbDataListMap, sectionScatterConf)
+
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 这个数据没有必要返回给前端
+		for _, v := range edbList {
+			v.DataList = nil
+		}
+	case utils.CHART_TYPE_RADAR: //雷达图
+		radarConf := extraConfig.(data_manage.RadarChartInfoReq)
+		xEdbIdValue, dataResp, err = RadarChartData(mappingList, edbDataListMap, radarConf)
+	}
+	return
+}

+ 654 - 0
services/data/chart_info_excel_balance.go

@@ -0,0 +1,654 @@
+package data
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_mobile/models/data_manage"
+	excelModel "eta/eta_mobile/models/data_manage/excel"
+	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/services/data/data_manage_permission"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"math"
+	"strings"
+	"time"
+)
+
+func GetBalanceExcelChartDetail(chartInfo *data_manage.ChartInfoView, mappingListTmp []*excelModel.ExcelChartEdb, sysUser *system.Admin, dataListMap map[int][]*data_manage.EdbDataList) (resp *data_manage.ChartInfoDetailResp, err error, errMsg string) {
+	// 图表数据权限
+	{
+		// 已授权分类id
+		permissionChartIdList, permissionClassifyIdList, e := data_manage_permission.GetUserChartAndClassifyPermissionList(sysUser.AdminId, chartInfo.ChartInfoId, chartInfo.ChartClassifyId)
+		if e != nil {
+			errMsg = "获取失败"
+			err = fmt.Errorf("获取已授权分类id数据失败,Err:" + err.Error())
+			return
+		}
+		chartInfo.HaveOperaAuth = data_manage_permission.CheckChartPermissionByPermissionIdList(chartInfo.IsJoinPermission, 0, chartInfo.ChartInfoId, chartInfo.ChartClassifyId, permissionChartIdList, permissionClassifyIdList)
+	}
+
+	chartInfoId := chartInfo.ChartInfoId
+	resp = new(data_manage.ChartInfoDetailResp)
+
+	// 获取主题样式
+	chartTheme, err := GetChartThemeConfig(chartInfo.ChartThemeId, 1, chartInfo.ChartType)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取主题信息失败 Err:%s", err.Error())
+		return
+	}
+	chartInfo.ChartThemeStyle = chartTheme.Config
+	chartInfo.ChartThemeId = chartTheme.ChartThemeId
+
+	dateType := chartInfo.DateType
+	fmt.Println("dateType:", dateType)
+
+	chartType := chartInfo.ChartType
+	startDate := chartInfo.StartDate
+	endDate := chartInfo.EndDate
+	seasonStartDate := chartInfo.SeasonStartDate
+	seasonEndDate := chartInfo.SeasonEndDate
+	startYear := chartInfo.StartYear
+
+	calendar := chartInfo.Calendar
+
+	if calendar == "" {
+		calendar = "公历"
+	}
+
+	mappingList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	//循环组装映射关系
+	for _, v := range mappingListTmp {
+		dataList := make([]*data_manage.EdbDataList, 0)
+		dataListTmp, ok := dataListMap[v.ExcelChartEdbId]
+		if ok {
+			dataList = dataListTmp
+		} else {
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.ExcelChartEdbId))
+			return
+		}
+		startDateStr, endDateStr, _, endVal, maxValue, minValue := getBalanceDataListStartDateAndValue(dataList)
+		mapping := &data_manage.ChartEdbInfoMapping{
+			EdbInfoId:         v.ExcelChartEdbId,
+			SourceName:        "",
+			Source:            0,
+			SubSource:         0,
+			EdbCode:           v.EdbCode,
+			EdbName:           v.EdbName,
+			EdbAliasName:      v.EdbName,
+			EdbNameEn:         "",
+			EdbAliasNameEn:    "",
+			EdbType:           0,
+			Frequency:         "",
+			FrequencyEn:       "",
+			Unit:              "",
+			UnitEn:            "",
+			StartDate:         startDateStr,
+			EndDate:           endDateStr,
+			ModifyTime:        v.ModifyTime.Format(utils.FormatDateTime),
+			ChartEdbMappingId: v.ExcelChartEdbId,
+			ChartInfoId:       chartInfoId,
+			MaxData:           v.MaxData,
+			MinData:           v.MinData,
+			IsOrder:           v.IsOrder,
+			IsAxis:            v.IsAxis,
+			//EdbInfoType:         0,
+			//EdbInfoCategoryType: 0,
+			LeadValue:         v.LeadValue,
+			LeadUnit:          v.LeadUnit,
+			LeadUnitEn:        "",
+			ChartStyle:        "",
+			ChartColor:        "",
+			PredictChartColor: "",
+			ChartWidth:        v.ChartWidth,
+			ChartType:         chartType,
+			LatestDate:        endDateStr,
+			LatestValue:       endVal,
+			MoveLatestDate:    "",
+			UniqueCode:        "",
+			MinValue:          minValue,
+			MaxValue:          maxValue,
+			DataList:          nil,
+			IsNullData:        false,
+			MappingSource:     0,
+			RegionType:        "",
+			ClassifyId:        0,
+			IsConvert:         0,
+			ConvertType:       0,
+			ConvertValue:      0,
+			ConvertUnit:       "",
+			ConvertEnUnit:     "",
+			IsJoinPermission:  0,
+			HaveOperaAuth:     true,
+		}
+		mappingList = append(mappingList, mapping)
+	}
+	if chartType == 2 {
+		startDate = seasonStartDate
+		endDate = seasonEndDate
+		if dateType <= 0 {
+			if startDate != "" {
+				dateType = 5
+			} else {
+				dateType = utils.DateTypeNYears
+			}
+		}
+	} else {
+		if dateType <= 0 {
+			dateType = 3
+		}
+	}
+	yearMax := 0
+	if dateType == utils.DateTypeNYears {
+		for _, v := range mappingList {
+			if v.LatestDate != "" {
+				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
+				if tErr != nil {
+					errMsg = "获取失败"
+					err = fmt.Errorf("获取图表日期信息失败,Err:" + tErr.Error())
+					return
+				}
+				if lastDateT.Year() > yearMax {
+					yearMax = lastDateT.Year()
+				}
+			}
+		}
+	}
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+
+	if chartInfo.ChartType == 2 {
+		chartInfo.StartDate = startDate
+		chartInfo.EndDate = endDate
+	}
+	// 图表额外数据参数
+	extraConfigStr := chartInfo.ExtraConfig
+	// 柱方图的一些配置
+	var barConfig data_manage.BarChartInfoReq
+	if chartInfo != nil && chartInfo.ChartType == 7 {
+		if chartInfo.BarConfig == `` {
+			err = fmt.Errorf("柱方图未配置")
+			errMsg = "柱方图未配置"
+			return
+		}
+		err = json.Unmarshal([]byte(chartInfo.BarConfig), &barConfig)
+		if err != nil {
+			err = fmt.Errorf("柱方图配置异常 json.Unmarshal Err:%s", err.Error())
+			errMsg = "柱方图配置异常"
+			return
+		}
+		extraConfigStr = chartInfo.BarConfig
+	}
+	// 获取表格数据
+
+	excelChartInfoDataShow := new(ExcelChartInfoDataShow)
+	excelChartInfoDataShow.DataListMap = dataListMap
+
+	if chartInfo.HaveOperaAuth {
+		// 获取图表中的指标数据
+		edbList, xEdbIdValue, yDataList, dataResp, e, msg := GetChartEdbDataV2(chartInfoId, chartType, calendar, startDate, endDate, mappingList, extraConfigStr, chartInfo.SeasonExtraConfig, excelChartInfoDataShow)
+		if e != nil {
+			err = fmt.Errorf("获取图表,指标数据失败,Err:%s", e.Error())
+			errMsg = msg
+			return
+		}
+		// 单位
+		if chartType == utils.CHART_TYPE_BAR && len(yDataList) > 0 {
+			chartInfo.Unit = yDataList[0].Unit
+			chartInfo.UnitEn = yDataList[0].UnitEn
+		}
+		warnEdbList := make([]string, 0)
+		for _, v := range edbList {
+			if v.IsNullData {
+				warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")
+			}
+		}
+		if len(warnEdbList) > 0 {
+			chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
+		}
+		if chartInfoId > 0 && chartInfo != nil {
+			//判断是否加入我的图库
+			{
+				var myChartCondition string
+				var myChartPars []interface{}
+				myChartCondition += ` AND a.admin_id=? `
+				myChartPars = append(myChartPars, sysUser.AdminId)
+				myChartCondition += ` AND a.chart_info_id=? `
+				myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+				myChartList, e := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+				if e != nil && e.Error() != utils.ErrNoRow() {
+					errMsg = "获取失败"
+					err = fmt.Errorf("获取我的图表信息失败,GetMyChartByCondition,Err:" + e.Error())
+					return
+				}
+				if myChartList != nil && len(myChartList) > 0 {
+					chartInfo.IsAdd = true
+					chartInfo.MyChartId = myChartList[0].MyChartId
+					chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+				}
+			}
+		}
+		//判断是否需要展示英文标识
+		chartInfo.IsEnChart = CheckIsEnChart(chartInfo.ChartNameEn, edbList, chartInfo.Source, chartInfo.ChartType)
+
+		// 图表的指标来源
+		sourceNameList, sourceNameEnList := GetEdbSourceByEdbInfoIdList(edbList)
+
+		chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+		chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+		// todo 指标权限
+		{
+			for _, item := range edbList {
+				// 数据权限
+				item.HaveOperaAuth = true
+			}
+		}
+
+		resp.EdbInfoList = edbList
+		resp.XEdbIdValue = xEdbIdValue
+		resp.YDataList = yDataList
+		resp.DataResp = dataResp
+	} else {
+		resp.EdbInfoList = mappingList
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = CheckOpChartPermission(sysUser, chartInfo.SysUserId, chartInfo.HaveOperaAuth)
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp.ChartInfo = chartInfo
+	resp.BarChartInfo = barConfig
+	return
+}
+
+// GetBalanceExcelEdbDataMapList 获取指标最后的基础数据
+func GetBalanceExcelEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string, dataListMap map[int][]*data_manage.EdbDataList) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
+
+	for _, v := range mappingList {
+		//fmt.Println("v:", v.EdbInfoId)
+		item := new(data_manage.ChartEdbInfoMapping)
+		item.EdbInfoId = v.EdbInfoId
+		item.SourceName = v.SourceName
+		item.Source = v.Source
+		item.EdbCode = v.EdbCode
+		item.EdbName = v.EdbName
+		item.EdbNameEn = v.EdbNameEn
+		item.Frequency = v.Frequency
+		item.EdbType = v.EdbType
+		item.FrequencyEn = GetFrequencyEn(v.Frequency)
+		if v.Unit != `无` {
+			item.Unit = v.Unit
+		}
+		item.UnitEn = v.UnitEn
+		item.StartDate = v.StartDate
+		item.EndDate = v.EndDate
+		item.ModifyTime = v.ModifyTime
+		item.EdbInfoCategoryType = v.EdbInfoCategoryType
+		item.PredictChartColor = v.PredictChartColor
+		item.ClassifyId = v.ClassifyId
+		if chartInfoId <= 0 {
+			item.IsAxis = 1
+			item.LeadValue = 0
+			item.LeadUnit = ""
+			item.ChartEdbMappingId = 0
+			item.ChartInfoId = 0
+			item.IsOrder = false
+			item.EdbInfoType = 1
+			item.ChartStyle = ""
+			item.ChartColor = ""
+			item.ChartWidth = 0
+			item.MaxData = v.MaxValue
+			item.MinData = v.MinValue
+		} else {
+			item.IsAxis = v.IsAxis
+			item.EdbInfoType = v.EdbInfoType
+			item.LeadValue = v.LeadValue
+			item.LeadUnit = v.LeadUnit
+			item.LeadUnitEn = GetLeadUnitEn(v.LeadUnit)
+			item.ChartEdbMappingId = v.ChartEdbMappingId
+			item.ChartInfoId = v.ChartInfoId
+			item.ChartStyle = v.ChartStyle
+			item.ChartColor = v.ChartColor
+			item.ChartWidth = v.ChartWidth
+			item.IsOrder = v.IsOrder
+			item.MaxData = v.MaxData
+			item.MinData = v.MinData
+		}
+		item.LatestValue = v.LatestValue
+		item.LatestDate = v.LatestDate
+		item.UniqueCode = v.UniqueCode
+		item.MoveLatestDate = v.LatestDate
+		item.EdbAliasName = v.EdbAliasName
+		item.IsConvert = v.IsConvert
+		item.ConvertType = v.ConvertType
+		item.ConvertValue = v.ConvertValue
+		item.ConvertUnit = v.ConvertUnit
+		item.ConvertEnUnit = v.ConvertEnUnit
+		item.IsJoinPermission = v.IsJoinPermission
+
+		var startDateReal string
+		var diffSeconds int64
+		if chartType == 2 { //季节性图
+			startDateReal = startDate
+		} else {
+			if v.EdbInfoType == 0 && v.LeadUnit != "" && v.LeadValue > 0 { //领先指标
+				var startTimeRealTemp time.Time
+				startDateParse, _ := time.Parse(utils.FormatDate, startDate)
+				switch v.LeadUnit {
+				case "天":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -v.LeadValue)
+				case "月":
+					startTimeRealTemp = startDateParse.AddDate(0, -v.LeadValue, 0)
+				case "季":
+					startTimeRealTemp = startDateParse.AddDate(0, -3*v.LeadValue, 0)
+				case "周":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -7*v.LeadValue)
+				case "年":
+					startTimeRealTemp = startDateParse.AddDate(-v.LeadValue, 0, 0)
+				}
+				if startTimeRealTemp.Before(startDateParse) {
+					startDateReal = startTimeRealTemp.Format(utils.FormatDate)
+					diffSeconds = (int64(startTimeRealTemp.UnixNano()) - int64(startDateParse.UnixNano())) / 1e6
+				} else {
+					startDateReal = startDate
+					diffSeconds = 0
+				}
+
+				// 预测指标的开始日期也要偏移
+				{
+					day, tmpErr := utils.GetDaysBetween2Date(utils.FormatDate, startDate, startDateReal)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					moveLatestDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, item.MoveLatestDate, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					item.MoveLatestDate = moveLatestDateTime.AddDate(0, 0, day).Format(utils.FormatDate)
+				}
+			} else {
+				startDateReal = startDate
+			}
+		}
+		//fmt.Println("line 1011 chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
+		calendarPreYear := 0
+		if calendar == "农历" {
+			newStartDateReal, e := time.Parse(utils.FormatDate, startDateReal)
+			if e != nil {
+				err = fmt.Errorf("时间解析 time.Parse(%s, %s) error: %v", utils.FormatDate, startDateReal, e)
+				return
+			}
+			calendarPreYear = newStartDateReal.Year() - 1
+			newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
+			startDateReal = newStartDateReal.Format(utils.FormatDate)
+		}
+		dataList := make([]*data_manage.EdbDataList, 0)
+		dataListTmp, ok := dataListMap[v.EdbInfoId]
+		if ok {
+			dataList = dataListTmp
+		} else {
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.EdbInfoId))
+			return
+		}
+		if v.IsConvert == 1 {
+			switch v.ConvertType {
+			case 1:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value * v.ConvertValue
+				}
+				//item.MaxData = item.MaxData * v.ConvertValue
+				//item.MinData = item.MinData * v.ConvertValue
+			case 2:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value / v.ConvertValue
+				}
+				//item.MaxData = item.MaxData / v.ConvertValue
+				//item.MinData = item.MinData / v.ConvertValue
+			case 3:
+				for i, data := range dataList {
+					if data.Value <= 0 {
+						err = errors.New("数据中含有负数或0,无法对数运算")
+						return
+					}
+					dataList[i].Value = math.Log(data.Value) / math.Log(v.ConvertValue)
+				}
+				//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+				//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+			}
+		}
+
+		edbDataListMap[v.EdbInfoId] = dataList
+
+		if diffSeconds != 0 && v.EdbInfoType == 0 {
+			dataListLen := len(dataList)
+			for i := 0; i < dataListLen; i++ {
+				dataList[i].DataTimestamp = dataList[i].DataTimestamp - diffSeconds
+			}
+		}
+
+		if chartType == 2 {
+			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
+			if tmpErr != nil {
+				//item.DataList = dataList
+				item.IsNullData = true
+				edbList = append(edbList, item)
+				continue
+			}
+
+			if calendar == "农历" {
+				if len(dataList) <= 0 {
+					result := new(data_manage.EdbDataResult)
+					item.DataList = result
+				} else {
+					result, tmpErr := data_manage.AddCalculateQuarterV6(dataList)
+					if tmpErr != nil {
+						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
+						return
+					}
+					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					if tErr != nil {
+						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+						return
+					}
+					item.DataList = quarterDataList
+				}
+
+			} else {
+				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				if tErr != nil {
+					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+					return
+				}
+				item.DataList = quarterDataList
+			}
+
+		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
+			//item.DataList = dataList
+		} else {
+			item.DataList = dataList
+		}
+		edbList = append(edbList, item)
+	}
+
+	return
+}
+
+func CheckBalanceChartCacheAndPermission(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	//判断是否存在缓存,如果存在缓存,那么直接从缓存中获取
+	adminId := sysUser.AdminId
+	// todo 图表数据权限
+	// 已授权分类id
+	permissionChartIdList, permissionClassifyIdList, err := data_manage_permission.GetUserChartAndClassifyPermissionList(adminId, chartInfo.ChartInfoId, chartInfo.ChartClassifyId)
+	if err != nil {
+		errMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+		return
+	}
+
+	defer func() {
+		if isOk {
+			// 图表权限校验
+			{
+				resp.ChartInfo.HaveOperaAuth = data_manage_permission.CheckChartPermissionByPermissionIdList(chartInfo.IsJoinPermission, 0, chartInfo.ChartInfoId, chartInfo.ChartClassifyId, permissionChartIdList, permissionClassifyIdList)
+
+				//图表操作权限
+				chartInfo.IsEdit = CheckOpChartPermission(sysUser, chartInfo.SysUserId, resp.ChartInfo.HaveOperaAuth)
+				chartInfo.Button = data_manage.ChartViewButton{
+					IsEdit:    chartInfo.IsEdit,
+					IsEnChart: chartInfo.IsEnChart,
+					IsAdd:     chartInfo.IsAdd,
+					IsCopy:    true,
+					IsSetName: chartInfo.IsSetName,
+				}
+
+				//if !resp.ChartInfo.HaveOperaAuth {
+				//	for _, v := range resp.EdbInfoList {
+				//		v.DataList = nil
+				//	}
+				//	resp.DataResp = nil
+				//	resp.XEdbIdValue = []int{}
+				//	resp.YDataList = []data_manage.YData{}
+				//}
+			}
+
+			// todo 是否需要返回平衡表指标权限即判断平衡表的表格数据权限
+			{
+				// 查询图表关联的表格ID
+				excelInfo, e := excelModel.GetExcelInfoByChartInfoId(chartInfo.ChartInfoId)
+				if e != nil {
+					errMsg = "获取图表关联的表格ID失败,Err:" + e.Error()
+					err = e
+					return
+				}
+				checkExcelInfo := excelInfo
+				if excelInfo.Source == utils.BALANCE_TABLE {
+					checkExcelInfoId := excelInfo.ExcelInfoId
+					if excelInfo.BalanceType == 1 {
+						checkExcelInfoId = excelInfo.RelExcelInfoId
+					} else {
+						if excelInfo.ParentId > 0 {
+							checkExcelInfoId = excelInfo.ParentId
+						}
+					}
+					if checkExcelInfoId != excelInfo.ExcelInfoId {
+						checkExcelInfo, err = excelModel.GetExcelInfoById(checkExcelInfoId)
+						if err != nil {
+							errMsg = "获取平衡表格信息失败"
+							err = errors.New("获取平衡表格信息失败,Err:" + err.Error())
+							return
+						}
+					}
+				}
+
+				haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, adminId)
+				if e != nil {
+					errMsg = "获取平衡表格数据权限失败"
+					err = errors.New("获取表格权限信息失败,Err" + e.Error())
+					return
+				}
+				// 数据权限
+				for _, v := range resp.EdbInfoList {
+					v.HaveOperaAuth = haveOperaAuth
+				}
+			}
+		}
+	}()
+	key := GetChartInfoDataKey(chartInfo.ChartInfoId)
+	if utils.Re == nil && isCache {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if redisData, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err := json.Unmarshal(redisData, &resp)
+				if err != nil || resp == nil {
+					return
+				}
+				// 这里跟当前用户相关的信息重新查询写入resp, 不使用缓存中的
+				var myCond string
+				var myPars []interface{}
+				myCond += ` AND a.admin_id=? `
+				myPars = append(myPars, adminId)
+				myCond += ` AND a.chart_info_id=? `
+				myPars = append(myPars, chartInfo.ChartInfoId)
+				myList, err := data_manage.GetMyChartByCondition(myCond, myPars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					msg = "获取失败"
+					errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+					return
+				}
+				resp.ChartInfo.IsAdd = false
+				resp.ChartInfo.MyChartId = 0
+				resp.ChartInfo.MyChartClassifyId = ""
+				if myList != nil && len(myList) > 0 {
+					resp.ChartInfo.IsAdd = true
+					resp.ChartInfo.MyChartId = myList[0].MyChartId
+					resp.ChartInfo.MyChartClassifyId = myList[0].MyChartClassifyId
+				}
+
+				//判断是否加入我的图库
+				{
+					var myChartCondition string
+					var myChartPars []interface{}
+					myChartCondition += ` AND a.admin_id=? `
+					myChartPars = append(myChartPars, adminId)
+					myChartCondition += ` AND a.chart_info_id=? `
+					myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+					myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+					if err != nil && err.Error() != utils.ErrNoRow() {
+						msg = "获取失败"
+						errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+						return
+					}
+					if myChartList != nil && len(myChartList) > 0 {
+						chartInfo.IsAdd = true
+						chartInfo.MyChartId = myChartList[0].MyChartId
+						chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+					}
+				}
+
+				isOk = true
+				fmt.Println("source redis")
+				return
+			}
+		}
+	}
+	return
+}
+
+func getBalanceDataListStartDateAndValue(dataList []*data_manage.EdbDataList) (startDate, endDate string, startVal, endVal, maxVal, minVal float64) {
+	if len(dataList) == 0 {
+		return
+	}
+	startDate = dataList[0].DataTime
+	startVal = dataList[0].Value
+	maxVal = dataList[0].Value
+	minVal = dataList[0].Value
+	endDate = dataList[len(dataList)-1].DataTime
+	endVal = dataList[len(dataList)-1].Value
+	for _, v := range dataList {
+		if v.DataTime < startDate {
+			startDate = v.DataTime
+			startVal = v.Value
+		}
+		if v.DataTime > endDate {
+			endDate = v.DataTime
+			endVal = v.Value
+		}
+		if v.Value > maxVal {
+			maxVal = v.Value
+		}
+		if v.Value < minVal {
+			minVal = v.Value
+		}
+	}
+	return
+}

+ 28 - 0
services/data/chart_info_interface.go

@@ -0,0 +1,28 @@
+package data
+
+import "eta/eta_mobile/models/data_manage"
+
+type ChartInfoDataShow interface {
+	GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error)
+}
+
+type BaseChartInfoDataShow struct {
+}
+
+// GetEdbDataMapList 获取指标最后的基础数据
+func (e *BaseChartInfoDataShow) GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err = GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig)
+	return
+}
+
+type ExcelChartInfoDataShow struct {
+	DataListMap map[int][]*data_manage.EdbDataList
+}
+
+// GetEdbDataMapList 获取指标最后的基础数据
+func (e *ExcelChartInfoDataShow) GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err = GetBalanceExcelEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig, e.DataListMap)
+	return
+}

+ 362 - 0
services/data/excel/balance_table.go

@@ -0,0 +1,362 @@
+package excel
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_mobile/models/data_manage"
+	excelModel "eta/eta_mobile/models/data_manage/excel"
+	"eta/eta_mobile/models/data_manage/excel/request"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"github.com/xuri/excelize/v2"
+	"strconv"
+	"time"
+)
+
+// 将表格信息转化成指标数据
+func GetBalanceExcelData(excelDetail *excelModel.ExcelInfo, lang string) (newDataMap map[int]map[int]request.MixedTableCellDataReq, allRows, allCols int, err error, errMsg string) {
+	var result request.MixedTableReq
+	err = json.Unmarshal([]byte(excelDetail.Content), &result)
+	if err != nil {
+		err = errors.New("表格json转结构体失败,Err:" + err.Error())
+		return
+	}
+	newData, tmpErr, tmpErrMsg := GetMixedTableCellData(result, lang)
+	if tmpErr != nil {
+		errMsg = "获取失败"
+		if tmpErrMsg != `` {
+			errMsg = tmpErrMsg
+		}
+		err = errors.New("获取最新的数据失败,Err:" + tmpErr.Error())
+		return
+	}
+
+	allRows = len(newData)
+	allCols = 0
+	newDataMap = make(map[int]map[int]request.MixedTableCellDataReq)
+	for r, row := range newData {
+		tmp := len(row)
+		if tmp > allCols {
+			allCols = tmp
+		}
+		colMap := make(map[int]request.MixedTableCellDataReq)
+		for c, col := range row {
+			colMap[c] = col
+		}
+		newDataMap[r] = colMap
+	}
+	return
+}
+
+// 将表格信息转化成指标数据
+func GetBalanceExcelEdbData(excelEdbMappingItem *excelModel.ExcelChartEdb, newMixedTableCellDataListMap map[int]map[int]request.MixedTableCellDataReq, dataListMap map[int][]*data_manage.EdbDataList, allRows, allCols int) (err error, errMsg string) {
+	var dateList, dataList []string
+	// 日期序列
+	{
+		_, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(excelEdbMappingItem.DateSequence)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		startNum = startNum - 1
+		endNum = endNum - 1
+		// 选择行的数据
+		if isRow {
+			// 因为是选择一行的数据,所以开始行和结束行时一样的
+			//endNum = startNum - 1
+
+			// 开始列名、结束列
+			var startColumn, endColumn int
+			if isAll {
+				// 结束列(其实也就是整列的个数)
+				endColumn = allCols - 1
+			} else {
+				tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + startColumnName
+					err = errors.New(errMsg)
+					return
+				}
+
+				tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + endColumnName
+					err = errors.New(errMsg)
+					return
+				}
+				startColumn = tmpStartColumn - 1
+				endColumn = tmpEndColumn - 1
+			}
+
+			// 最大列数,如果设置的超过了最大列数,那么结束列就是最大列数
+			maxCol := allCols
+			if endColumn > maxCol {
+				endColumn = maxCol - 1
+			}
+
+			// 长度固定,避免一直申请内存空间
+			dateList = make([]string, endColumn-startColumn+1)
+
+			i := 0
+			for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
+				currCell, ok := newMixedTableCellDataListMap[startNum][currColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currColumn, startNum)
+					err = errors.New(errMsg)
+					return
+				}
+				dateList[i] = currCell.ShowValue
+				i++
+			}
+
+		} else if isColumn { // 选择列的数据
+			if isAll {
+				// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
+				endNum = allRows - 1
+			}
+
+			startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+			if tmpErr != nil {
+				errMsg = "列名异常:" + startColumnName
+				err = errors.New(errMsg)
+				return
+			}
+			startColumn = startColumn - 1
+
+			// 最大行数,如果设置的超过了最大行数,那么结束行就是最大行数
+			maxRow := allRows
+			if endNum > maxRow {
+				endNum = maxRow - 1
+			}
+			// 长度固定,避免一直申请内存空间
+			dateList = make([]string, endNum-startNum+1)
+			i := 0
+			for currRow := startNum; currRow <= endNum; currRow++ {
+				currCell, ok := newMixedTableCellDataListMap[currRow][startColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currRow, startColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dateList = append(dateList, currCell.Value)
+				dateList[i] = currCell.ShowValue
+				i++
+			}
+		}
+
+	}
+
+	// 数据序列
+	{
+		_, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(excelEdbMappingItem.DataSequence)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		startNum = startNum - 1
+		endNum = endNum - 1
+		// 选择行的数据
+		if isRow {
+			// 开始列名、结束列
+			var startColumn, endColumn int
+			if isAll {
+				// 结束列(其实也就是整列的个数)
+				endColumn = allCols - 1
+			} else {
+
+				tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + startColumnName
+					err = errors.New(errMsg)
+					return
+				}
+
+				tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + endColumnName
+					err = errors.New(errMsg)
+					return
+				}
+				startColumn = tmpStartColumn - 1
+				endColumn = tmpEndColumn - 1
+			}
+
+			// 最大列数,如果设置的超过了最大列数,那么结束列就是最大列数
+			maxCol := allCols
+			if endColumn > maxCol {
+				endColumn = maxCol - 1
+			}
+			// 长度固定,避免一直申请内存空间
+			dataList = make([]string, endColumn-startColumn+1)
+			i := 0
+			for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
+				currCell, ok := newMixedTableCellDataListMap[startNum][currColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, currColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dataList = append(dataList, currCell.Value)
+				dataList[i] = currCell.ShowValue
+				i++
+			}
+
+		} else if isColumn { // 选择列的数据
+			if isAll {
+				// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
+				endNum = allRows - 1
+			}
+
+			startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+			if tmpErr != nil {
+				errMsg = "列名异常:" + startColumnName
+				err = errors.New(errMsg)
+				return
+			}
+			startColumn = startColumn - 1
+
+			// 最大行数,如果设置的超过了最大行数,那么结束行就是最大行数
+			maxRow := allRows
+			if endNum > maxRow {
+				endNum = maxRow - 1
+			}
+
+			// 长度固定,避免一直申请内存空间
+			dataList = make([]string, endNum-startNum+1)
+			i := 0
+			for currRow := startNum; currRow <= endNum; currRow++ {
+				currCell, ok := newMixedTableCellDataListMap[currRow][startColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currRow, startColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dataList = append(dataList, currCell.Value)
+				dataList[i] = currCell.ShowValue
+				i++
+			}
+		}
+	}
+
+	//fmt.Println(dateList, dataList)
+	//fmt.Println("日期序列结束")
+
+	// 将excel中的日期、数据系列处理
+	//newDateList, newDataList, err, errMsg := excel2.HandleEdbSequenceVal(dateList, dataList)
+	newDateList, newDataList := dateList, dataList
+	if err != nil {
+		err = fmt.Errorf(" 处理日期和数据系列失败 %s", err.Error())
+		return
+	}
+	newDataMap := make(map[int]float64, len(newDataList))
+	for i, v := range newDataList {
+		val, e := strconv.ParseFloat(v, 64)
+		if e != nil {
+			err = fmt.Errorf(" 处理日期和数据系列失败 %s", e.Error())
+			return
+		}
+		newDataMap[i] = val
+	}
+	//组装成excelEdbData
+	list := make([]*data_manage.EdbDataList, 0)
+
+	for i, v := range newDateList {
+		// todo 处理DataTimestamp
+		dataTime, e := time.ParseInLocation(utils.FormatDate, v, time.Local)
+		if e != nil {
+			err = errors.New("time.Parse Err:" + err.Error())
+			return
+		}
+		timestamp := dataTime.UnixNano() / 1e6
+		tmp := &data_manage.EdbDataList{
+			EdbDataId:     i,
+			EdbInfoId:     excelEdbMappingItem.ExcelChartEdbId,
+			DataTime:      v,
+			DataTimestamp: timestamp,
+			Value:         newDataMap[i],
+		}
+		list = append(list, tmp)
+	}
+	dataListMap[excelEdbMappingItem.ExcelChartEdbId] = list
+	return
+}
+
+// 获取平衡表指标绑定详情
+func GetBalanceExcelChartSimple(excelInfo *excelModel.ExcelInfo, chartInfoId int, lang string) (list []*data_manage.ChartInfoView, mappingListMap map[int][]*excelModel.ExcelChartEdb, dataListMap map[int][]*data_manage.EdbDataList, err error, errMsg string) {
+	mappingListTmp, err := excelModel.GetExcelChartEdbMappingByChartInfoId(chartInfoId)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	mappingList := make([]*excelModel.ExcelChartEdbView, 0)
+	for _, v := range mappingListTmp {
+		tmp :=
+			&excelModel.ExcelChartEdbView{
+				ExcelChartEdbId: v.ExcelChartEdbId,
+				ExcelInfoId:     v.ExcelInfoId,
+				ChartInfoId:     v.ChartInfoId,
+				EdbCode:         v.EdbCode,
+				EdbName:         v.EdbName,
+				DateSequenceStr: v.DateSequence,
+				DataSequenceStr: v.DataSequence,
+				/*MaxData:         v.MaxData,
+				MinData:         v.MinData,
+				IsOrder:         v.IsOrder,
+				IsAxis:          v.IsAxis,
+				EdbInfoType:     v.EdbInfoType,
+				LeadValue:       v.LeadValue,
+				LeadUnit:        v.LeadUnit,*/
+				FromTag: v.FromTag,
+			}
+		mappingList = append(mappingList, tmp)
+	}
+
+	return
+}
+
+// 获取单个图表信息
+func GetBalanceExcelChartSingle(chartInfo *data_manage.ChartInfoView, lang string) (mappingListTmp []*excelModel.ExcelChartEdb, dataListMap map[int][]*data_manage.EdbDataList, err error, errMsg string) {
+	// 相关联指标
+	mappingListTmp, err = excelModel.GetExcelChartEdbMappingByChartInfoId(chartInfo.ChartInfoId)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	if len(mappingListTmp) <= 0 {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	excelInfoId := mappingListTmp[0].ExcelInfoId
+	// 查询所有子表
+	excelInfo, err := excelModel.GetExcelInfoById(excelInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "表格不存在"
+			err = fmt.Errorf(errMsg)
+			return
+		}
+		errMsg = "查询子表失败"
+		err = fmt.Errorf(" 查询子表失败图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	// 获取图表详情
+	newExcelDataMap, excelAllRows, excelAllCols, err, errMsg := GetBalanceExcelData(excelInfo, lang)
+	if err != nil {
+		return
+	}
+	dataListMap = make(map[int][]*data_manage.EdbDataList)
+
+	for _, mapping := range mappingListTmp {
+		err, errMsg = GetBalanceExcelEdbData(mapping, newExcelDataMap, dataListMap, excelAllRows, excelAllCols)
+		if err != nil {
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+			return
+		}
+	}
+	return
+}

+ 2 - 0
utils/constants.go

@@ -319,6 +319,7 @@ const (
 	CHART_SOURCE_LINE_FEATURE_PERCENTILE         = 8  // 统计特征-百分位图表
 	CHART_SOURCE_LINE_FEATURE_FREQUENCY          = 9  // 统计特征-频率分布图表
 	CHART_SOURCE_CROSS_HEDGING                   = 10 // 跨品种分析图表
+	CHART_SOURCE_BALANCE_EXCEL                   = 11 // 平衡表图表
 )
 
 // 批量配置图表的位置来源
@@ -341,6 +342,7 @@ const (
 	TIME_TABLE            = 2 // 时间序列表格
 	MIXED_TABLE           = 3 // 混合表格
 	CUSTOM_ANALYSIS_TABLE = 4 // 自定义分析表格
+	BALANCE_TABLE         = 5 // 平衡表
 )
 
 // 图表样式类型