package excel

import (
	"encoding/json"
	"errors"
	"eta/eta_mobile/models"
	"eta/eta_mobile/models/data_manage"
	"eta/eta_mobile/models/data_manage/excel"
	"eta/eta_mobile/models/data_manage/excel/request"
	"eta/eta_mobile/models/data_manage/excel/response"
	"eta/eta_mobile/models/system"
	"eta/eta_mobile/services/data"
	"eta/eta_mobile/services/data/data_manage_permission"
	"eta/eta_mobile/utils"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/yidane/formula"
	"sort"
	"strconv"
	"strings"
	"time"
)

// GetExcelDetailInfoByExcelInfoId 根据表格id获取表格详情
func GetExcelDetailInfoByExcelInfoId(excelInfoId, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) {
	errMsg = `获取失败`
	//获取eta表格信息
	excelInfo, err := excel.GetExcelInfoById(excelInfoId)
	if err != nil {
		err = errors.New("获取ETA表格信息失败,Err:" + err.Error())
		if err.Error() == utils.ErrNoRow() {
			errMsg = "ETA表格被删除,请刷新页面"
			err = errors.New("ETA表格被删除,请刷新页面,Err:" + err.Error())
		}
		return
	}

	return formatExcelInfo2Detail(excelInfo, sysUserId, lang)
}

// GetExcelDetailInfoByUnicode 根据表格编码获取表格详情
func GetExcelDetailInfoByUnicode(unicode string, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) {
	errMsg = `获取失败`
	// 获取eta表格信息
	excelInfo, err := excel.GetExcelInfoByUnicode(unicode)
	if err != nil {
		err = errors.New("获取ETA表格信息失败,Err:" + err.Error())
		if err.Error() == utils.ErrNoRow() {
			errMsg = "ETA表格被删除,请刷新页面"
			err = errors.New("ETA表格被删除,请刷新页面,Err:" + err.Error())
		}
		return
	}

	return formatExcelInfo2Detail(excelInfo, sysUserId, lang)
}

func formatExcelInfo2Detail(excelInfo *excel.ExcelInfo, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) {
	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 = excel.GetExcelInfoById(checkExcelInfoId)
			if err != nil {
				errMsg = "获取平衡表格信息失败"
				err = errors.New("获取平衡表格信息失败,Err:" + err.Error())
				return
			}
		}
	}
	// 数据权限
	haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUserId)
	if err != nil {
		err = errors.New("获取表格权限信息失败,Err" + err.Error())
		return
	}

	excelDetail = response.ExcelInfoDetail{
		ExcelInfoId:     excelInfo.ExcelInfoId,
		Source:          excelInfo.Source,
		ExcelType:       excelInfo.ExcelType,
		ExcelName:       excelInfo.ExcelName,
		UniqueCode:      excelInfo.UniqueCode,
		ExcelClassifyId: excelInfo.ExcelClassifyId,
		SysUserId:       excelInfo.SysUserId,
		SysUserRealName: excelInfo.SysUserRealName,
		Content:         excelInfo.Content,
		ExcelImage:      excelInfo.ExcelImage,
		FileUrl:         excelInfo.FileUrl,
		Sort:            excelInfo.Sort,
		IsDelete:        excelInfo.IsDelete,
		ModifyTime:      excelInfo.ModifyTime,
		CreateTime:      excelInfo.CreateTime,
		TableData:       nil,
		HaveOperaAuth:   haveOperaAuth,
		SourcesFrom:     excelInfo.SourcesFrom,
	}

	// 无权限,不需要返回数据
	if !haveOperaAuth {
		return
	}

	switch excelInfo.Source {
	case utils.TIME_TABLE: // 时间序列表格
		var tableDataConfig TableDataConfig
		err = json.Unmarshal([]byte(excelDetail.Content), &tableDataConfig)
		if err != nil {
			err = errors.New("表格json转结构体失败,Err:" + err.Error())
			return
		}
		result, tmpErr := GetDataByTableDataConfig(tableDataConfig)
		if tmpErr != nil {
			err = errors.New("获取最新的表格数据失败,Err:" + tmpErr.Error())
			return
		}

		if len(result.EdbInfoIdList) > 0 {
			classifyIdList := make([]int, 0)
			for _, v := range result.Data {
				classifyIdList = append(classifyIdList, v.ClassifyId)
			}

			classifyMap := make(map[int]*data_manage.EdbClassify)

			classifyList, tmpErr := data_manage.GetEdbClassifyByIdList(classifyIdList)
			if tmpErr != nil {
				err = errors.New("获取分类列表失败,Err:" + tmpErr.Error())
				return
			}

			for _, v := range classifyList {
				classifyMap[v.ClassifyId] = v
			}

			// 获取所有有权限的指标和分类
			permissionEdbIdList, permissionClassifyIdList, tmpErr := data_manage_permission.GetUserEdbAndClassifyPermissionList(sysUserId, 0, 0)
			if err != nil {
				err = errors.New("获取所有有权限的指标和分类失败,Err:" + tmpErr.Error())
				return
			}

			for i, v := range result.Data {
				if currClassify, ok := classifyMap[v.ClassifyId]; ok {
					result.Data[i].HaveOperaAuth = data_manage_permission.CheckEdbPermissionByPermissionIdList(v.IsJoinPermission, currClassify.IsJoinPermission, v.EdbInfoId, v.ClassifyId, permissionEdbIdList, permissionClassifyIdList)
				}
			}
		}
		sourceNameList, sourceNameEnList, e := GetEdbSourceByEdbInfoIdList(result.EdbInfoIdList)
		if e != nil {
			err = errors.New("自定义表格数据获取失败,Err:" + e.Error())
			return
		}
		excelDetail.ExcelSource = strings.Join(sourceNameList, ",")
		excelDetail.ExcelSourceEn = strings.Join(sourceNameEnList, ",")
		excelDetail.TableData = result
	case utils.MIXED_TABLE: // 混合表格
		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
		}
		result.Data = newData
		excelDetail.TableData = result

		edbInfoIds := make([]int, 0)
		edbInfoIdExist := make(map[int]bool)
		if len(result.Data) > 0 {
			for _, t := range result.Data {
				for _, v := range t {
					if v.EdbInfoId > 0 && !edbInfoIdExist[v.EdbInfoId] {
						edbInfoIdExist[v.EdbInfoId] = true
						edbInfoIds = append(edbInfoIds, v.EdbInfoId)
					}
				}
			}
		}
		sourceNameList, sourceNameEnList, e := GetEdbSourceByEdbInfoIdList(edbInfoIds)
		if e != nil {
			err = errors.New("自定义表格数据获取失败,Err:" + e.Error())
			return
		}
		excelDetail.ExcelSource = strings.Join(sourceNameList, ",")
		excelDetail.ExcelSourceEn = strings.Join(sourceNameEnList, ",")
	}
	if excelDetail.Source == utils.BALANCE_TABLE {
		excelDetail.Button = GetBalanceExcelInfoOpButton(sysUserId, checkExcelInfo.SysUserId, excelDetail.HaveOperaAuth, checkExcelInfo.ExcelInfoId)
	}
	return
}

// GetExcelInfoOpButton 获取ETA表格的操作权限
func GetExcelInfoOpButton(sysUser *system.Admin, belongUserId, source int, haveOperaAuth bool) (button excel.ExcelInfoDetailButton) {
	// 如果没有数据权限,那么直接返回
	if !haveOperaAuth {
		return
	}
	//非管理员角色查看其他用户创建的表格,可刷新、另存为、下载表格;
	button.RefreshButton = true
	button.CopyButton = true
	button.DownloadButton = true

	// 1、本用户创建的表格,可编辑、刷新、另存为、下载、删除,删除需二次确认;
	// 2、管理员角色对所有表格有如上权限;
	// 3、在线excel所有人都能编辑
	if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN || sysUser.AdminId == belongUserId || source == utils.EXCEL_DEFAULT {
		button.OpButton = true
		button.DeleteButton = true
	}

	// 自定义分析
	if source == utils.CUSTOM_ANALYSIS_TABLE {
		if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN || sysUser.AdminId == belongUserId {
			button.OpEdbButton = true      // 生成、查看指标按钮
			button.RefreshEdbButton = true // 刷新指标按钮
		}
	}

	return
}

// GetFirstEdbDataList 获取第一列的数据
func GetFirstEdbDataList(edbInfo *data_manage.EdbInfo, num int, manualDateList []string) (resultDataList []request.ManualDataReq, err error) {
	var dataList []*data_manage.EdbDataList
	switch edbInfo.EdbInfoType {
	case 0:
		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
	case 1:
		_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
	default:
		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
	}
	if err != nil {
		return
	}

	// 获取需要的期数
	lenData := len(dataList)
	if lenData <= 0 {
		return
	}

	tmpManualDateNum := 0 // 手工数据的期数
	lenManualDate := len(manualDateList)
	if lenManualDate > 0 {
		sortDateList := manualDateList
		baseDateList := utils.StrArr{}
		baseDateList = append(baseDateList, sortDateList...)
		sort.Sort(baseDateList)
		sortDateList = append([]string{}, baseDateList...)

		lastData := dataList[lenData-1]
		lastDataDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		// 遍历倒序后的日期,然后匹配在实际数据之后日期的个数
		for _, tmpDateStr := range sortDateList {
			tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			if tmpDate.After(lastDataDate) {
				tmpManualDateNum++
				continue
			}

			break
		}

	}

	// 需要的期数减去手工数据的期数,这才是A列指标需要的数据
	num = num - tmpManualDateNum
	if num > lenData {
		num = lenData
	}

	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local)
	for i := 1; i <= num; i++ {
		dataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[lenData-i].DataTime, time.Local)
		dataType := 1
		// 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值
		if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) {
			dataType = 5
		}

		resultDataList = append(resultDataList, request.ManualDataReq{
			DataType:     dataType,
			DataTime:     dataList[lenData-i].DataTime,
			ShowValue:    fmt.Sprint(dataList[lenData-i].Value),
			Value:        fmt.Sprint(dataList[lenData-i].Value),
			DataTimeType: 1,
		})
	}

	return
}

// GetOtherEdbDataList 获取其他列的数据
func GetOtherEdbDataList(edbInfo *data_manage.EdbInfo, dateList []string) (resultDataList []request.ManualDataReq, err error) {
	lenDate := len(dateList)
	if lenDate <= 0 {
		return
	}
	sortDateList := dateList
	baseDateList := utils.StrArr{}
	baseDateList = append(baseDateList, sortDateList...)
	sort.Sort(baseDateList)
	sortDateList = append([]string{}, baseDateList...)

	endDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[0], time.Local)
	if err != nil {
		return
	}

	firstDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[lenDate-1], time.Local)
	if err != nil {
		return
	}

	var dataList []*data_manage.EdbDataList
	switch edbInfo.EdbInfoType {
	case 0:
		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
	case 1:
		_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
	default:
		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
	}
	if err != nil {
		return
	}

	// 获取日期内的数据(包含开始日期前一个日期,以及 结束日期后一个日期,目的为了做空日期时的 插值法兼容)
	baseDataList := make([]*data_manage.EdbDataList, 0)
	var lastData *data_manage.EdbDataList
	var isInsert bool
	for _, data := range dataList {
		tmpDate := data.DataTime
		tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if tmpDateTime.Before(firstDateTime) {
			lastData = data
			continue
		}

		// 如果是第一次写入数据
		if !isInsert && lastData != nil {
			baseDataList = append(baseDataList, lastData)
		}

		if tmpDateTime.After(endDateTime) {
			baseDataList = append(baseDataList, data)
			break
		}
		baseDataList = append(baseDataList, data)
		isInsert = true
	}

	// 实际数据的日期map
	realValMap := make(map[string]string)
	for _, v := range baseDataList {
		realValMap[v.DataTime] = v.DataTime
	}

	// 插值法处理
	handleDataMap := make(map[string]float64)
	err = data.HandleDataByLinearRegression(baseDataList, handleDataMap)
	if err != nil {
		return
	}

	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local)

	// 对于不存在的数据做补充
	for _, date := range sortDateList {
		dataType := 1
		if _, ok := realValMap[date]; !ok {
			dataType = 2
		} else {
			dataTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
			// 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值
			if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) {
				dataType = 5
			}
		}
		var value, showValue string
		if tmpVal, ok := handleDataMap[date]; ok {
			value = fmt.Sprint(tmpVal)
			showValue = value
		} else {
			dataType = 3
		}
		resultDataList = append(resultDataList, request.ManualDataReq{
			DataType:  dataType,
			DataTime:  date,
			ShowValue: showValue,
			Value:     value,
		})
	}

	return
}

// GetFirstHistoryEdbDataList 获取指标的历史的数据
func GetFirstHistoryEdbDataList(edbInfo *data_manage.EdbInfo, num int, endDate string) (resultDataList []request.ManualDataReq, err error) {
	endDateTime, err := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
	if err != nil {
		return
	}

	var dataList []*data_manage.EdbDataList
	switch edbInfo.EdbInfoType {
	case 0:
		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, endDate)
	case 1:
		_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, endDate, true)
	default:
		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
	}
	if err != nil {
		return
	}

	// 获取需要的期数
	lenData := len(dataList)
	if lenData <= 0 {
		return
	}
	lastData := dataList[lenData-1]
	lastDataDateTime, err := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local)
	if err != nil {
		return
	}
	if endDateTime.Equal(lastDataDateTime) || lastDataDateTime.After(endDateTime) {
		dataList = dataList[:lenData-1]
		lenData = len(dataList)
	}
	if num > lenData {
		num = lenData
	}

	latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local)
	for i := 1; i <= num; i++ {
		dataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[lenData-i].DataTime, time.Local)
		dataType := 1
		// 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值
		if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) {
			dataType = 5
		}

		resultDataList = append(resultDataList, request.ManualDataReq{
			DataType:  dataType,
			DataTime:  dataList[lenData-i].DataTime,
			ShowValue: fmt.Sprint(dataList[lenData-i].Value),
			Value:     fmt.Sprint(dataList[lenData-i].Value),
		})
	}

	return
}

type TableDataConfig struct {
	EdbInfoIdList    []int                     `description:"指标id列表,从左至右,从上到下的顺序"`
	Sort             int                       `description:"日期排序,0:倒序,1:正序"`
	Data             []ManualData              `description:"数据列表"`
	Num              int                       `description:"实际数据需要列出来的期数"`
	RemoveDate       []string                  `description:"不展示的日期"`
	ManualDate       []string                  `description:"手动配置的日期(未来的日期)"`
	TableEdbInfoList []TableEdbInfo            `description:"表格内指标信息"`
	TextRowData      [][]request.ManualDataReq `description:"文本列表"`
}

type TableEdbInfo struct {
	EdbInfoId    int    `description:"指标ID"`
	Tag          string `description:"标签"`
	EdbName      string `description:"指标名称"`
	EdbAliasName string `description:"指标别名"`
	Frequency    string `description:"频度"`
	Unit         string `description:"单位"`
}

type ManualData struct {
	DataType            int                       `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算"`
	DataTime            string                    `description:"所属日期"`
	DataTimeType        int                       `description:"日期类型,1:实际日期;2:未来日期"`
	ShowValue           string                    `description:"展示值"`
	Value               string                    `description:"实际值(计算公式)"`
	EdbInfoId           int                       `description:"指标id"`
	Tag                 string                    `description:"下标"`
	RelationEdbInfoList []request.RelationEdbInfo `description:"关联指标(计算公式中关联的指标,用于计算的时候去匹配)"`
}

// GetTableDataConfig 根据TableDataReq配置获取相关数据配置
func GetTableDataConfig(reqData request.TableDataReq) (tableDataConfig TableDataConfig, err error) {
	// 指标数据
	tableDataConfig.EdbInfoIdList = reqData.EdbInfoIdList
	tableDataConfig.Sort = reqData.Sort

	if len(reqData.Data) <= 0 {
		err = errors.New("数据不能为空")
		return
	}

	// 开始日期
	var startDate string
	// A列的指标id
	var firstEdbInfoId int
	// 手工操作的数据列
	manualDataList := make([]ManualData, 0)
	// 指标配置列表
	tableEdbInfoList := make([]TableEdbInfo, 0)

	// 第一列的日期map
	firstDateMap := make(map[string]string)
	manualDateMap := make(map[string]string)

	for _, v := range reqData.Data {
		// 指标信息
		tmpTableEdbInfo := TableEdbInfo{
			EdbInfoId:    v.EdbInfoId,
			Tag:          v.Tag,
			EdbName:      v.EdbName,
			EdbAliasName: v.EdbAliasName,
			Frequency:    v.Frequency,
			Unit:         v.Unit,
		}
		tableEdbInfoList = append(tableEdbInfoList, tmpTableEdbInfo)

		// 确定数据A列
		if v.Tag == "A" {
			firstEdbInfoId = v.EdbInfoId
			lenData := len(v.Data)
			if lenData <= 0 {
				err = errors.New("A列不能为空")
				return
			}
			index := 0
			if reqData.Sort == 1 {
				// 倒序
				index = lenData - 1
			}

			startDate = v.Data[index].DataTime

			// 存在的日期列表
			for _, data := range v.Data {
				firstDateMap[data.DataTime] = data.DataTime

				if data.DataTimeType == 2 {
					manualDateMap[data.DataTime] = data.DataTime
				}
			}
		}

		for _, data := range v.Data {
			if data.DataType == 3 || data.DataType == 4 {
				tmpManualData := ManualData{
					DataType:            data.DataType,
					DataTime:            data.DataTime,
					DataTimeType:        data.DataTimeType,
					ShowValue:           data.ShowValue,
					Value:               data.Value,
					EdbInfoId:           v.EdbInfoId,
					Tag:                 v.Tag,
					RelationEdbInfoList: data.RelationEdbInfoList,
				}
				if data.DataType == 4 {
					tmpManualData.ShowValue = ``
				}
				manualDataList = append(manualDataList, tmpManualData)
			}
		}
	}

	// 总共需要的期数
	num := len(reqData.Data[0].Data)

	removeDate := make([]string, 0)

	// 获取期数
	{
		firstDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		edbInfo, tmpErr := data_manage.GetEdbInfoById(firstEdbInfoId)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		var firstDataList []*data_manage.EdbDataList
		switch edbInfo.EdbInfoType {
		case 0:
			firstDataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
		case 1:
			_, firstDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
		default:
			err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
		}
		if err != nil {
			return
		}

		// 获取日期内的数据(包含开始日期前一个日期,以及 结束日期后一个日期,目的为了做空日期时的 插值法兼容)
		baseDataList := make([]*data_manage.EdbDataList, 0)
		for _, data := range firstDataList {
			tmpDate := data.DataTime
			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			if tmpDateTime.Before(firstDateTime) {
				continue
			}
			baseDataList = append(baseDataList, data)
		}

		// 筛选出需要删除的日期
		for _, tmpData := range baseDataList {
			//firstDateMap{}
			if _, ok := firstDateMap[tmpData.DataTime]; !ok {
				removeDate = append(removeDate, tmpData.DataTime)
			}
		}
	}

	tableDataConfig.Num = num
	tableDataConfig.RemoveDate = removeDate
	tableDataConfig.Data = manualDataList
	tableDataConfig.TableEdbInfoList = tableEdbInfoList
	tableDataConfig.TextRowData = reqData.TextRowData

	return
}

// GetDataByTableDataConfig 根据数据配置获取表格数据
func GetDataByTableDataConfig(tableDataConfig TableDataConfig) (resultResp request.TableDataReq, err error) {
	// 没有选择指标的情况下,直接返回吧
	if len(tableDataConfig.EdbInfoIdList) <= 0 {
		return
	}

	// 实际期数没有的情况下,直接返回吧
	if tableDataConfig.Num <= 0 {
		return
	}

	// 获取所有的指标信息
	edbInfoMap := make(map[int]*data_manage.EdbInfo)
	edbInfoIdList := make([]int, 0)
	// 标签与指标id的map
	tagEdbInfoIdMap := make(map[string]int)
	{
		for _, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
			edbInfoIdList = append(edbInfoIdList, tableEdbInfo.EdbInfoId)
			tagEdbInfoIdMap[tableEdbInfo.Tag] = tableEdbInfo.EdbInfoId
		}
		edbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdList)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		for _, v := range edbInfoList {
			edbInfoMap[v.EdbInfoId] = v
		}
	}

	manualDateMap := make(map[string]string, 0)
	manualDateList := make([]string, 0)
	for _, v := range tableDataConfig.Data {
		if _, ok := manualDateMap[v.DataTime]; !ok {
			manualDateMap[v.DataTime] = v.DataTime
			manualDateList = append(manualDateList, v.DataTime)
		}
	}

	// 寻找A列的数据列表
	firstEdbInfo, ok := edbInfoMap[tableDataConfig.TableEdbInfoList[0].EdbInfoId]
	if !ok {
		err = errors.New("找不到A列指标")
		return
	}
	baseFirstEdbInfoDataList, err := GetFirstEdbDataList(firstEdbInfo, tableDataConfig.Num, manualDateList)
	if err != nil {
		return
	}
	// A列找不到数据,那么就直接返回吧
	if len(baseFirstEdbInfoDataList) <= 0 {
		return
	}

	firstEdbInfoDataList := make([]request.ManualDataReq, 0)
	if tableDataConfig.RemoveDate != nil && len(tableDataConfig.RemoveDate) > 0 {
		for _, v := range baseFirstEdbInfoDataList {
			if utils.InArrayByStr(tableDataConfig.RemoveDate, v.DataTime) {
				continue
			}
			firstEdbInfoDataList = append(firstEdbInfoDataList, v)
		}
	} else {
		firstEdbInfoDataList = baseFirstEdbInfoDataList
	}
	if len(firstEdbInfoDataList) <= 0 {
		return
	}
	// 实际数据的最后一天
	lastRealDateTime, err := time.ParseInLocation(utils.FormatDate, firstEdbInfoDataList[0].DataTime, time.Local)
	if err != nil {
		return
	}

	dateMap := make(map[string]string)
	dateList := make([]string, 0)
	edbInfoIdDateDataMap := make(map[int]map[string]request.ManualDataReq)
	firstDateDataMap := make(map[string]request.ManualDataReq)
	for _, v := range firstEdbInfoDataList {
		dateList = append(dateList, v.DataTime)
		dateMap[v.DataTime] = v.DataTime
		firstDateDataMap[v.DataTime] = v
	}

	// 将手工数据的日期填补进去(未来的日期,过去的就不管了)
	for _, manualData := range tableDataConfig.Data {
		if !utils.InArrayByStr(dateList, manualData.DataTime) {
			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, manualData.DataTime, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			if tmpDateTime.After(lastRealDateTime) {
				dateList = append(dateList, manualData.DataTime)
			}
		}
	}

	edbInfoIdDateDataMap[firstEdbInfo.EdbInfoId] = firstDateDataMap

	for k, edbInfoId := range tableDataConfig.EdbInfoIdList {
		if k == 0 {
			continue
		}

		tmpEdbInfo, ok := edbInfoMap[edbInfoId]
		if !ok {
			err = errors.New("找不到A列指标")
			return
		}
		otherDataList, tmpErr := GetOtherEdbDataList(tmpEdbInfo, dateList)
		if tmpErr != nil {
			err = tmpErr
			return
		}

		tmpDateDataMap := make(map[string]request.ManualDataReq)
		for _, v := range otherDataList {
			tmpDateDataMap[v.DataTime] = v
		}
		edbInfoIdDateDataMap[tmpEdbInfo.EdbInfoId] = tmpDateDataMap
	}

	for _, v := range tableDataConfig.Data {
		tmpDate := v.DataTime
		if _, ok := dateMap[tmpDate]; !ok {
			dateMap[v.DataTime] = tmpDate
		}

		edbInfoIdDateData, ok := edbInfoIdDateDataMap[v.EdbInfoId]
		if !ok {
			edbInfoIdDateData = make(map[string]request.ManualDataReq)
		}

		// 判断是否存在该日期的数据(不存在,那么插入数据吧,存在就不管了)
		tmpManualData, ok := edbInfoIdDateData[tmpDate]
		if !ok {
			edbInfoIdDateData[tmpDate] = request.ManualDataReq{
				DataType:  v.DataType,
				DataTime:  v.DataTime,
				ShowValue: v.ShowValue,
				Value:     v.Value,
			}
		} else {
			if (tmpManualData.DataType == 3 || tmpManualData.DataType == 4) && tmpManualData.ShowValue == `` {
				tmpManualData.DataType = v.DataType
				tmpManualData.ShowValue = v.ShowValue
				tmpManualData.Value = v.Value
				tmpManualData.RelationEdbInfoList = v.RelationEdbInfoList

				edbInfoIdDateData[tmpDate] = tmpManualData
			}
		}
		edbInfoIdDateDataMap[v.EdbInfoId] = edbInfoIdDateData
	}

	// 获取数据的日期排序
	sortDateTimeList := make([]time.Time, 0)
	{
		sortDateList := dateList
		if tableDataConfig.Sort == 1 {
			baseDateList := utils.StrArr{}
			baseDateList = append(baseDateList, sortDateList...)
			sort.Sort(baseDateList)
			sortDateList = append([]string{}, baseDateList...)
		} else {
			sort.Strings(sortDateList)
		}
		for _, v := range sortDateList {
			tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, v, time.Local)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			sortDateTimeList = append(sortDateTimeList, tmpDateTime)
		}
	}

	// 数据处理,处理成表格的数据格式
	tableDataMap, textRowListDataResp := handleTable(tagEdbInfoIdMap, lastRealDateTime, sortDateTimeList, edbInfoIdDateDataMap, tableDataConfig.Data, tableDataConfig.TextRowData)

	data := make([]request.EdbInfoData, 0)
	for _, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
		tagEdbInfoIdMap[tableEdbInfo.Tag] = tableEdbInfo.EdbInfoId

		manualDataReqList := make([]request.ManualDataReq, 0)
		tmpEdbInfoData := request.EdbInfoData{
			EdbInfoId:    tableEdbInfo.EdbInfoId,
			Tag:          tableEdbInfo.Tag,
			EdbName:      tableEdbInfo.EdbName,
			EdbAliasName: tableEdbInfo.EdbAliasName,
			Frequency:    tableEdbInfo.Frequency,
			Unit:         tableEdbInfo.Unit,
			Data:         manualDataReqList,
		}

		edbInfo, ok := edbInfoMap[tableEdbInfo.EdbInfoId]
		if ok {
			tmpEdbInfoData.EdbName = edbInfo.EdbName
			tmpEdbInfoData.Frequency = edbInfo.Frequency
			tmpEdbInfoData.Unit = edbInfo.Unit
			tmpEdbInfoData.ClassifyId = edbInfo.ClassifyId
			tmpEdbInfoData.IsJoinPermission = edbInfo.IsJoinPermission
		}

		for index, dateTime := range sortDateTimeList {
			dataTimeType := 1
			if dateTime.After(lastRealDateTime) {
				dataTimeType = 2
			}
			tmpDateTimeStr := dateTime.Format(utils.FormatDate)

			rowData, ok := tableDataMap[index+1]
			if !ok {
				manualDataReqList = append(manualDataReqList, request.ManualDataReq{
					DataType:            3,
					DataTime:            tmpDateTimeStr,
					DataTimeType:        dataTimeType,
					ShowValue:           "",
					Value:               "",
					RelationEdbInfoList: nil,
				})
				continue
			}

			tmpData, ok := rowData[tableEdbInfo.Tag]
			if !ok {
				manualDataReqList = append(manualDataReqList, request.ManualDataReq{
					DataType:            3,
					DataTime:            tmpDateTimeStr,
					DataTimeType:        dataTimeType,
					ShowValue:           "",
					Value:               "",
					RelationEdbInfoList: nil,
				})
				continue
			}

			tmpData.DataTimeType = dataTimeType
			manualDataReqList = append(manualDataReqList, tmpData)
		}

		tmpEdbInfoData.Data = manualDataReqList

		data = append(data, tmpEdbInfoData)
	}

	// 处理一下数据格式
	for _, d := range data {
		for k2, d2 := range d.Data {
			// 可能有ShowValue非数值, 转换一下报错则continue
			vf, e := strconv.ParseFloat(d2.ShowValue, 64)
			if e != nil {
				continue
			}
			d.Data[k2].ShowValue = utils.FormatTableDataShowValue(vf)
		}
	}
	for _, d := range textRowListDataResp {
		for k2, d2 := range d {
			// 可能有ShowValue非数值, 转换一下报错则continue
			vf, e := strconv.ParseFloat(d2.ShowValue, 64)
			if e != nil {
				continue
			}
			d[k2].ShowValue = utils.FormatTableDataShowValue(vf)
		}
	}

	resultResp = request.TableDataReq{
		EdbInfoIdList: edbInfoIdList,
		Sort:          tableDataConfig.Sort,
		TextRowData:   textRowListDataResp,
		Data:          data,
	}

	return
}

// handleTable 表格数据处理
func handleTable(tagEdbInfoIdMap map[string]int, lastRealDateTime time.Time, sortDateTimeList []time.Time, edbInfoIdDateDataMap map[int]map[string]request.ManualDataReq, manualDataList []ManualData, textRowData [][]request.ManualDataReq) (tableDataMap map[int]map[string]request.ManualDataReq, textRowListDataResp [][]request.ManualDataReq) {
	tagList := make([]string, 0)
	for tag, _ := range tagEdbInfoIdMap {
		tagList = append(tagList, tag)
	}
	sort.Strings(tagList)

	tableDataMap = make(map[int]map[string]request.ManualDataReq) //行、列数据

	// 日期与行的关系
	dateIndexMap := make(map[string]int)

	for k, dateTime := range sortDateTimeList {
		rowDataMap := make(map[string]request.ManualDataReq)

		dataTimeType := 1
		if dateTime.After(lastRealDateTime) {
			dataTimeType = 2
		}

		tmpDateTimeStr := dateTime.Format(utils.FormatDate)
		dateIndexMap[tmpDateTimeStr] = k + 1

		for _, tag := range tagList {
			edbInfoId, ok := tagEdbInfoIdMap[tag]
			if !ok { // 没有找到该指标的映射关系,那么就用空串填补
				rowDataMap[tag] = request.ManualDataReq{
					DataType:            3,
					DataTime:            tmpDateTimeStr,
					DataTimeType:        dataTimeType,
					ShowValue:           "",
					Value:               "",
					RelationEdbInfoList: nil,
				}
				continue
			}

			// 获取指标的数据map
			dateDataMap, ok := edbInfoIdDateDataMap[edbInfoId]
			if !ok { // 没有找到该指标的数据,那么就用空串填补
				rowDataMap[tag] = request.ManualDataReq{
					DataType:            3,
					DataTime:            tmpDateTimeStr,
					DataTimeType:        dataTimeType,
					ShowValue:           "",
					Value:               "",
					RelationEdbInfoList: nil,
				}
				continue
			}

			// 获取指标该日期的数据
			tmpData, ok := dateDataMap[tmpDateTimeStr]
			if !ok { // 该指标没有找到对应日期的数据,那么就用空串填补
				rowDataMap[tag] = request.ManualDataReq{
					DataType:            3,
					DataTime:            tmpDateTimeStr,
					DataTimeType:        dataTimeType,
					ShowValue:           "",
					Value:               "",
					RelationEdbInfoList: nil,
				}
				continue
			}
			tmpData.DataTimeType = dataTimeType
			rowDataMap[tag] = tmpData
		}
		tableDataMap[k+1] = rowDataMap
	}

	// 替换手工设置的数据
	for _, manualData := range manualDataList {
		// 找不到该日期,说明这日期过期了,不处理
		index, ok := dateIndexMap[manualData.DataTime]
		if !ok {
			continue
		}

		// 获取对应行的数据
		rowDataMap, ok := tableDataMap[index]
		if !ok {
			continue
		}

		// 找到对应的单元格
		tmpData, ok := rowDataMap[manualData.Tag]
		if !ok {
			continue
		}

		// 如果该单元格实际有数据(包含预测值),或者插值法补充了数据的话,那么就不用手动填入的数据
		if utils.InArrayByInt([]int{1, 2, 5}, tmpData.DataType) {
			continue
		}

		// 手工填写的数字
		if tmpData.DataType == 3 {
			tmpData.ShowValue = manualData.ShowValue
			tmpData.Value = manualData.Value
			tableDataMap[index][manualData.Tag] = tmpData

			//edbInfoIdDateDataMap[manualData.EdbInfoId][manualData.DataTime] = tmpData
			continue
		}

		// 公式
		tmpData.DataType = manualData.DataType
		tmpData.ShowValue = ``
		tmpData.Value = manualData.Value
		tmpData.RelationEdbInfoList = manualData.RelationEdbInfoList
		tableDataMap[index][manualData.Tag] = tmpData

	}

	// 文本行的列表插入
	lenTableData := len(tableDataMap)

	// 文本行第一列的数据列表(可能多行)
	firstColTextRowList := make([]request.ManualDataReq, 0)
	// 参与计算的文本行列表数据
	tmpTextRowList := make([][]request.ManualDataReq, 0)
	for k, textRowList := range textRowData {
		// 判断列数是否匹配,不匹配的话那么过滤
		if len(tagList)+1 != len(textRowList) {
			continue
		}
		rowDataMap := make(map[string]request.ManualDataReq)
		tmpTextRow := make([]request.ManualDataReq, 0)
		for index, textRow := range textRowList {
			// 移除第一列,因为第一列是日期列
			if index == 0 {
				firstColTextRowList = append(firstColTextRowList, textRow)
				continue
			}
			rowDataMap[tagList[index-1]] = textRow
			tmpTextRow = append(tmpTextRow, textRow)
		}

		tableDataMap[lenTableData+k+1] = rowDataMap
		tmpTextRowList = append(tmpTextRowList, tmpTextRow)
	}

	// 参与计算的单元格
	calculateCellMap := make(map[string]string)

	// 计算手工填写的单元格
	for _, manualData := range manualDataList {
		// 找不到该日期,说明这日期过期了,不处理
		index, ok := dateIndexMap[manualData.DataTime]
		if !ok {
			continue
		}

		// 获取对应行的数据
		rowDataMap, ok := tableDataMap[index]
		if !ok {
			continue
		}

		// 找到对应的单元格
		colData, ok := rowDataMap[manualData.Tag]
		if !ok {
			continue
		}

		// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
		if colData.DataType != 4 {
			continue
		}

		tagMap := make(map[string]float64)
		lenRelation := len(colData.RelationEdbInfoList)
		replaceNum := 0
		for _, relation := range colData.RelationEdbInfoList {
			relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
			valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
			if tmpErr != nil {
				continue
			}
			tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
			if tmpErr != nil {
				continue
			}
			tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
			replaceNum++
		}

		// 如果替换的数据与关联的不一致,那么就退出当前循环
		if lenRelation != replaceNum {
			continue
		}

		// 计算
		val, _, err := calculate(strings.ToUpper(colData.Value), tagMap)
		// 计算失败,退出循环
		if err != nil {
			continue
		}
		// 重新赋值
		colData.ShowValue = val
		tableDataMap[index][manualData.Tag] = colData

	}

	// 计算文本行的单元格
	for k, textRow := range tmpTextRowList {
		// 获取对应行的数据
		index := lenTableData + k + 1
		rowDataMap, ok := tableDataMap[index]
		if !ok {
			continue
		}

		for colIndex, _ := range textRow {
			currTag := tagList[colIndex]
			// 找到对应的单元格
			colData, ok := rowDataMap[currTag]
			if !ok {
				continue
			}

			// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
			if colData.DataType != 4 {
				continue
			}

			tagMap := make(map[string]float64)
			lenRelation := len(colData.RelationEdbInfoList)
			replaceNum := 0
			for _, relation := range colData.RelationEdbInfoList {
				relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
				valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
				if tmpErr != nil {
					continue
				}
				tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
				if tmpErr != nil {
					continue
				}
				tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
				replaceNum++
			}

			// 如果替换的数据与关联的不一致,那么就退出当前循环
			if lenRelation != replaceNum {
				continue
			}

			// 计算
			val, _, err := calculate(strings.ToUpper(colData.Value), tagMap)
			// 计算失败,退出循环
			if err != nil {
				continue
			}
			// 重新赋值
			colData.ShowValue = val
			tableDataMap[index][currTag] = colData
		}

	}

	// 计算文本行第一列的数据值(多行)
	for k, colData := range firstColTextRowList {
		// 如果该单元格不是计算公式的单元格,那么直接退出当前循环即可
		if colData.DataType != 4 {
			continue
		}

		tagMap := make(map[string]float64)
		lenRelation := len(colData.RelationEdbInfoList)
		replaceNum := 0
		for _, relation := range colData.RelationEdbInfoList {
			relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
			valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
			if tmpErr != nil {
				continue
			}
			tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
			if tmpErr != nil {
				continue
			}
			tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
			replaceNum++
		}

		// 如果替换的数据与关联的不一致,那么就退出当前循环
		if lenRelation != replaceNum {
			continue
		}

		// 计算
		val, _, err := calculate(strings.ToUpper(colData.Value), tagMap)
		// 计算失败,退出循环
		if err != nil {
			continue
		}
		// 重新赋值
		colData.ShowValue = val
		firstColTextRowList[k] = colData
	}

	{
		// 文本行的数据处理返回
		textRowListDataResp = make([][]request.ManualDataReq, 0)
		newLenTableDataMap := len(tableDataMap)
		// 文本行的第一行所在的位置
		firstTextRow := lenTableData + 1
		for i := firstTextRow; i <= newLenTableDataMap; i++ {
			textRowDataResp := make([]request.ManualDataReq, 0)

			textRowDataResp = append(textRowDataResp, firstColTextRowList[i-firstTextRow])
			for _, tmpTag := range tagList {
				textRowDataResp = append(textRowDataResp, tableDataMap[i][tmpTag])
			}
			textRowListDataResp = append(textRowListDataResp, textRowDataResp)
		}

	}

	return
}

// getCalculateValue 获取公式计算的结果
func getCalculateValue(tableDataMap map[int]map[string]request.ManualDataReq, tag, row string, calculateCellMap map[string]string) (val string, err error) {
	rowInt, err := strconv.Atoi(row)
	if err != nil {
		return
	}

	// 单元格的标签名
	cellTagName := strings.ToUpper(tag) + row
	val, ok := calculateCellMap[cellTagName]
	if ok {
		return
	}

	// 查找行数据
	rowData, ok := tableDataMap[rowInt]
	if !ok {
		err = errors.New("查找" + row + "行的数据失败")
		return
	}

	// 查找单元格数据
	colData, ok := rowData[tag]
	if !ok {
		err = errors.New("查找单元格" + tag + row + "的数据失败")
		return
	}

	// 如果不是计算单元格
	if colData.DataType != 4 {
		val = colData.ShowValue
		return
	}

	// 如果是计算单元格
	calculateCellMap[cellTagName] = ``

	tagMap := make(map[string]float64)
	for _, relation := range colData.RelationEdbInfoList {
		relationCellTagName := strings.ToUpper(relation.Tag) + relation.Row
		valStr, tmpErr := getCalculateValue(tableDataMap, relation.Tag, relation.Row, calculateCellMap)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		tmpValDecimal, tmpErr := decimal.NewFromString(valStr)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		tagMap[relationCellTagName], _ = tmpValDecimal.Float64()
	}

	// 计算
	val, _, err = calculate(strings.ToUpper(colData.Value), tagMap)
	if err != nil {
		return
	}
	// 重新赋值
	colData.ShowValue = val
	tableDataMap[rowInt][tag] = colData
	calculateCellMap[cellTagName] = val

	return
}

// calculate 公式计算
func calculate(calculateFormula string, TagMap map[string]float64) (calVal, errMsg string, err error) {
	if calculateFormula == "" {
		errMsg = "公式异常"
		err = errors.New(errMsg)
		return
	}
	calculateFormula = strings.TrimPrefix(calculateFormula, "=")
	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
	calculateFormula = strings.Replace(calculateFormula, ",", ",", -1)
	calculateFormula = strings.Replace(calculateFormula, "。", ".", -1)
	calculateFormula = strings.Replace(calculateFormula, "%", "*0.01", -1)

	formulaFormStr := utils.ReplaceFormula(TagMap, calculateFormula)
	//计算公式异常,那么就移除该指标
	if formulaFormStr == `` {
		errMsg = "公式异常"
		err = errors.New(errMsg)
		return
	}

	expression := formula.NewExpression(formulaFormStr)
	calResult, err := expression.Evaluate()
	if err != nil {
		errMsg = "计算失败"
		err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
		// 分母为0的报错
		if strings.Contains(err.Error(), "divide by zero") {
			errMsg = "分母不能为0"
			err = errors.New("分母不能为空,计算公式:" + formulaFormStr)
		}
		return
	}
	// 如果计算结果是NAN,那么就提示报错
	if calResult.IsNan() {
		errMsg = "计算失败"
		err = errors.New("计算失败:计算结果是:NAN;formulaStr:" + formulaFormStr)
		return
	}
	calVal = calResult.String()

	// 转Decimal然后四舍五入
	valDecimal, err := decimal.NewFromString(calVal)
	if err != nil {
		errMsg = "计算失败"
		err = errors.New("计算失败,结果转 Decimal 失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
		return
	}
	calVal = valDecimal.Round(4).String()

	return
}

// GetEdbIdsFromExcelCodes 获取表格中的指标IDs
func GetEdbIdsFromExcelCodes(excelCodes []string, sysUserId int, lang string) (edbIds []int, err error) {
	edbIds = make([]int, 0)
	edbIdExist := make(map[int]bool)
	for _, v := range excelCodes {
		// 表格详情
		detail, msg, e := GetExcelDetailInfoByUnicode(v, sysUserId, lang)
		if e != nil {
			err = fmt.Errorf("GetExcelDetailInfoByExcelInfoId err: %s, errMsg: %s", e.Error(), msg)
			return
		}

		// 自定义表格
		if detail.Source == utils.TIME_TABLE {
			jsonByte, e := json.Marshal(detail.TableData)
			if e != nil {
				err = fmt.Errorf("JSON格式化自定义表格数据失败, Err: %s", e.Error())
				return
			}
			var tableData request.TableDataReq
			if e = json.Unmarshal(jsonByte, &tableData); e != nil {
				err = fmt.Errorf("解析自定义表格数据失败, Err: %s", e.Error())
				return
			}
			for _, tv := range tableData.EdbInfoIdList {
				if edbIdExist[tv] {
					continue
				}
				edbIdExist[tv] = true
				edbIds = append(edbIds, tv)
			}
		}

		// 混合表格
		if detail.Source == utils.MIXED_TABLE {
			jsonByte, e := json.Marshal(detail.TableData)
			if e != nil {
				err = fmt.Errorf("JSON格式化混合表格数据失败, Err: %s", e.Error())
				return
			}
			var tableData request.MixedTableReq
			if e = json.Unmarshal(jsonByte, &tableData); e != nil {
				err = fmt.Errorf("解析混合表格数据失败, Err: %s", e.Error())
				return
			}
			if len(tableData.Data) > 0 {
				for _, td := range tableData.Data {
					for _, tv := range td {
						if tv.EdbInfoId > 0 && !edbIdExist[tv.EdbInfoId] {
							edbIdExist[tv.EdbInfoId] = true
							edbIds = append(edbIds, tv.EdbInfoId)
						}
					}
				}
			}
		}
	}

	return
}

// GetExcelEdbBatchRefreshKey 获取批量刷新表格指标缓存key
func GetExcelEdbBatchRefreshKey(source string, reportId, chapterId int) string {
	if source == `` {
		return ``
	}

	return fmt.Sprint("batch_refresh_excel_edb:", source, ":", reportId, ":", chapterId)
}


// GetEdbSourceByEdbInfoIdList 获取关联指标的来源
func GetEdbSourceByEdbInfoIdList(edbInfoIdList []int) (sourceNameList, sourceNameEnList []string,err error) {
	sourceNameList = make([]string, 0)
	sourceNameEnList = make([]string, 0)
	sourceMap := make(map[int]string)
	edbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdList)
	if tmpErr != nil {
		err = tmpErr
		return
	}
	for _, v := range edbInfoList {
		// 指标类型:1:基础指标,2:计算指标
		if v.EdbType == 2 {
			//sourceMap[0] = "弘则研究"
			baseEdbInfoArr, _, _ := data_manage.GetRefreshEdbInfoFromBase(v.EdbInfoId, v.Source)
			for _, baseEdbInfo := range baseEdbInfoArr {
				if baseEdbInfo.EdbInfoType == 0 { //普通指标才参与,预测指标不参与
					sourceMap[baseEdbInfo.Source] = baseEdbInfo.SourceName
				}
			}
		} else {
			sourceMap[v.Source] = v.SourceName
		}
	}

	for source, sourceName := range sourceMap {
		if utils.InArrayByInt([]int{utils.DATA_SOURCE_MANUAL, utils.DATA_SOURCE_MYSTEEL_CHEMICAL}, source) {
			continue
		}
		sourceNameList = append(sourceNameList, sourceName)

		sourceNameEn, ok := utils.DataSourceEnMap[source]
		if !ok {
			sourceNameEn = sourceName
		}
		sourceNameEnList = append(sourceNameEnList, sourceNameEn)
	}
	//sourceNameList = append(sourceNameList, utils.ChartDefaultNameCn)
	//sourceNameEnList = append(sourceNameEnList, utils.ChartDefaultNameEn)

	// 图表来源
	conf, e := models.GetBusinessConf()
	if e != nil {
		return
	}
	if conf[models.BusinessConfCompanyName] != "" {
		sourceNameList = append(sourceNameList, conf[models.BusinessConfCompanyName])
		sourceNameEnList = append(sourceNameEnList, conf[models.BusinessConfCompanyName])
	}
	return
}