package data

import (
	"encoding/json"
	"errors"
	"eta/eta_api/models/data_manage"
	"eta/eta_api/models/data_manage/chart_theme"
	excelModel "eta/eta_api/models/data_manage/excel"
	"eta/eta_api/models/data_manage/excel/request"
	"eta/eta_api/models/system"
	"eta/eta_api/services/data/data_manage_permission"
	"eta/eta_api/utils"
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"
	"time"
)

// AddBalanceExcelChart 添加平衡表图表
func AddBalanceExcelChart(excelInfo *excelModel.ExcelInfo, req request.AddBalanceTableChartReq, sysUser *system.Admin, dataListMap map[int][]*data_manage.EdbDataList) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {

	/*// 操作权限校验, 增加协作人判断
	{
		checkExcelInfo := excelInfo
		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 = fmt.Errorf("获取平衡表格信息失败，Err:" + err.Error())
				return
			}
		}
		// 数据权限
		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUser.AdminId)
		if e != nil {
			errMsg = "获取ETA表格权限失败"
			err = fmt.Errorf("获取表格权限信息失败，Err" + e.Error())
			return
		}

		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
		if !button.OpButton {
			errMsg = "无操作权限"
			isSendEmail = false
			return
		}
	}*/

	if len(req.ChartEdbInfoList) == 0 {
		errMsg = "图表数据不能为空！"
		err = fmt.Errorf("图表数据不能为空！%s", err.Error())
		return
	}
	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
	for k, chartEdb := range req.ChartEdbInfoList {
		excelEdb := new(excelModel.ExcelChartEdb)
		excelEdb.EdbName = chartEdb.EdbName
		excelEdb.EdbNameEn = excelEdb.EdbName
		excelEdb.Unit = chartEdb.Unit
		excelEdb.UnitEn = excelEdb.Unit
		randStr := utils.GetRandDigit(4)
		excelEdb.EdbCode = `T` + time.Now().Format("060102150405") + "_" + randStr
		excelEdb.ExcelInfoId = excelInfo.ExcelInfoId
		excelEdb.DateSequence = chartEdb.DateSequenceStr
		excelEdb.DataSequence = chartEdb.DataSequenceStr
		excelEdb.SysUserId = sysUser.AdminId
		excelEdb.SysUserRealName = sysUser.RealName
		excelEdb.MaxData = chartEdb.MaxData
		excelEdb.MinData = chartEdb.MinData
		excelEdb.IsOrder = chartEdb.IsOrder
		excelEdb.IsAxis = chartEdb.IsAxis
		excelEdb.FromTag = chartEdb.FromTag
		excelEdb.EdbInfoType = chartEdb.EdbInfoType
		excelEdb.LeadValue = chartEdb.LeadValue
		excelEdb.LeadUnit = chartEdb.LeadUnit
		excelEdb.CreateTime = time.Now()
		excelEdb.ModifyTime = time.Now()
		excelEdb.ChartWidth = 1
		var dataList []*excelModel.ExcelChartData
		if excelInfo.BalanceType == 1 {
			tmpList, ok := dataListMap[k]
			if !ok {
				errMsg = "查询图表数据失败！"
				err = fmt.Errorf("查询图表数据失败！%s", err.Error())
				return
			}
			for _, l := range tmpList {
				tmp := &excelModel.ExcelChartData{
					DataTime:      l.DataTime,
					Value:         l.Value,
					DataTimestamp: l.DataTimestamp,
				}
				dataList = append(dataList, tmp)
			}
		}

		// 处理日期列表和值列表
		addItem := &excelModel.AddChartEdbAndDataItem{
			ChartEdb: excelEdb,
			DataList: dataList,
		}
		chartEdbList = append(chartEdbList, addItem)
	}
	chartInfo, err, errMsg, isSendEmail = addBalanceExcelChart(req, sysUser.AdminId, sysUser.RealName)
	if err != nil {
		if errMsg == "" {
			errMsg = "新增图表失败！"
		}
		err = fmt.Errorf("新增图表失败！%s, %s", errMsg, err.Error())
		return
	}
	obj := new(excelModel.ExcelChartEdb)
	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, []int{})
	if err != nil {
		errMsg = "新增图表失败！"
		err = fmt.Errorf("新增图表数据失败！%s", err.Error())
		return
	}
	return
}

func addBalanceExcelChart(req request.AddBalanceTableChartReq, sysUserId int, sysUserRealName string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
	isSendEmail = true // 默认错误的时候要发送邮件

	req.ChartName = strings.Trim(req.ChartName, " ")
	if req.ChartName == "" {
		errMsg = "请填写图表名称！"
		err = fmt.Errorf(errMsg)
		isSendEmail = false
		return
	}
	chartType := req.ChartType
	extraConfig := req.ExtraConfig
	// 查找默认主题设置
	// 查找主题类型id
	chartThemeType, err := chart_theme.GetChartThemeTypeByChartType(chartType)
	if err != nil {
		errMsg = "查找主题类型失败！"
		err = fmt.Errorf("%s, %s", errMsg, err.Error())
		return
	}
	chartThemeId := chartThemeType.DefaultChartThemeId
	// 季节性图表额外配置信息
	var seasonExtraConfig string

	if len(req.ChartEdbInfoList) <= 0 {
		errMsg = "请选择指标！"
		err = fmt.Errorf(errMsg)
		return
	}
	if chartType == 2 {
		// 处理季节性图表横轴配置
		{
			if req.SeasonExtraConfig.XEndDate != "" {
				if req.SeasonExtraConfig.XStartDate > req.SeasonExtraConfig.XEndDate && req.SeasonExtraConfig.JumpYear != 1 {
					errMsg = "季节性图表配置信息异常：横坐标日期配置错误"
					err = fmt.Errorf("季节性图表配置信息异常： 横坐标日期配置错误")
					return
				}
				seasonExtra, tErr := json.Marshal(req.SeasonExtraConfig)
				if tErr != nil {
					errMsg = "季节性图表配置信息异常"
					err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
					return
				}

				seasonExtraConfig = string(seasonExtra)
			}
		}
	}

	// 图表额外配置
	extraConfig, err, errMsg = HandleExtraConfig(chartType, extraConfig)
	if err != nil {
		if errMsg == `` {
			errMsg = "指标异常！"
		}
		err = fmt.Errorf("指标异常！Err:" + err.Error())
		return
	}

	//判断图表是否存在
	var condition string
	var pars []interface{}

	// 图表名称在不同图分类下不允许重复 需求调整时间：2022年11月07日09:47:07
	condition += " AND chart_classify_id=0 "

	condition += " AND chart_name=? AND source = ? "
	pars = append(pars, req.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)

	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
	if err != nil {
		errMsg = "判断图表名称是否存在失败"
		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
		return
	}

	if count > 0 {
		errMsg = "图表名称已存在，请重新填写"
		err = fmt.Errorf("判断图表名称是否存在失败")
		isSendEmail = false
		return
	}

	chartInfo = new(data_manage.ChartInfo)
	chartInfo.ChartName = req.ChartName
	chartInfo.ChartNameEn = chartInfo.ChartName
	//chartInfo.EdbInfoIds = edbInfoIdStr
	//chartInfo.ChartClassifyId = req.ChartClassifyId
	chartInfo.SysUserId = sysUserId
	chartInfo.SysUserRealName = sysUserRealName
	chartInfo.CreateTime = time.Now()
	chartInfo.ModifyTime = time.Now()
	chartInfo.IsSetName = 0
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)

	// todo 判断是否需要重新计算用户的start_date
	chartInfo.DateType = 3

	if chartType == 0 {
		chartType = 1
	}
	chartInfo.ChartType = chartType

	calendar := req.Calendar
	if calendar == "" {
		calendar = "公历"
	}

	chartInfo.Calendar = calendar
	/*	chartInfo.StartDate = req.StartDate
		chartInfo.EndDate = req.EndDate
		chartInfo.SeasonStartDate = req.StartDate
		chartInfo.SeasonEndDate = req.EndDate*/
	chartInfo.LeftMin = req.LeftMin
	chartInfo.LeftMax = req.LeftMax
	chartInfo.RightMin = req.RightMin
	chartInfo.RightMax = req.RightMax
	chartInfo.Right2Min = req.Right2Min
	chartInfo.Right2Max = req.Right2Max
	chartInfo.MinMaxSave = req.MinMaxSave
	//chartInfo.Disabled = disableVal
	//chartInfo.BarConfig = barChartConf
	chartInfo.ExtraConfig = extraConfig
	chartInfo.SeasonExtraConfig = seasonExtraConfig
	//chartInfo.StartYear = req.StartYear
	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
	chartInfo.ChartThemeId = chartThemeId
	chartInfo.SourcesFrom = req.SourcesFrom
	/*	chartInfo.Instructions = req.Instructions
		chartInfo.MarkersLines = req.MarkersLines
		chartInfo.MarkersAreas = req.MarkersAreas
		chartInfo.Unit = req.Unit
		chartInfo.UnitEn = req.UnitEn*/
	/*newId, err := data_manage.AddChartInfo(chartInfo)
	if err != nil {
		errMsg = `保存失败`
		err = fmt.Errorf("保存失败，Err:" + err.Error())
		return
	}
	chartInfo.ChartInfoId = int(newId)*/

	//添加es数据
	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)

	return
}

// EditBalanceExcelChart 添加平衡表图表
func EditBalanceExcelChart(excelInfo *excelModel.ExcelInfo, req request.AddBalanceTableChartReq, sysUser *system.Admin, dataListMap map[int][]*data_manage.EdbDataList) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
	if len(req.ChartEdbInfoList) == 0 {
		errMsg = "图表数据不能为空！"
		err = fmt.Errorf("图表数据不能为空！%s", err.Error())
		return
	}
	/*// 操作权限校验, 增加协作人判断
	{
		checkExcelInfo := excelInfo
		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 = fmt.Errorf("获取平衡表格信息失败，Err:" + err.Error())
				return
			}
		}
		// 数据权限
		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUser.AdminId)
		if e != nil {
			errMsg = "获取ETA表格权限失败"
			err = fmt.Errorf("获取表格权限信息失败，Err" + e.Error())
			return
		}

		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
		if !button.OpButton {
			errMsg = "无操作权限"
			isSendEmail = false
			return
		}
	}
	*/
	//查询已有的mapping
	mapping, err := excelModel.GetExcelChartEdbMappingByChartInfoId(req.ChartInfoId)
	if err != nil {
		errMsg = "查询图表mapping失败！"
		err = fmt.Errorf("查询图表mapping失败！%s", err.Error())
		return
	}
	deleteMap := make(map[int]int)
	for _, v := range mapping {
		deleteMap[v.ExcelChartEdbId] = v.ExcelChartEdbId
	}

	// 查询edbIds
	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
	for k, chartEdb := range req.ChartEdbInfoList {
		if _, ok := deleteMap[chartEdb.ExcelChartEdbId]; ok {
			delete(deleteMap, chartEdb.ExcelChartEdbId)
		}
		excelChartEdbId := chartEdb.ExcelChartEdbId
		excelEdb := new(excelModel.ExcelChartEdb)
		if excelChartEdbId > 0 {
			excelEdb, err = excelModel.GetExcelChartEdbById(excelChartEdbId)
			if err != nil {
				if err.Error() == utils.ErrNoRow() {
					errMsg = "指标不存在！"
					err = errors.New("指标不存在，edbInfoId:" + strconv.Itoa(excelChartEdbId))
					return
				} else {
					errMsg = "获取指标信息失败！"
					err = errors.New("获取图表的指标信息失败，Err:" + err.Error())
					return
				}
			}
		} else {
			excelEdb.ExcelInfoId = excelInfo.ExcelInfoId
			randStr := utils.GetRandDigit(4)
			excelEdb.EdbCode = `T` + time.Now().Format("060102150405") + "_" + randStr
			excelEdb.SysUserId = sysUser.AdminId
			excelEdb.SysUserRealName = sysUser.RealName
			excelEdb.CreateTime = time.Now()
		}

		excelEdb.EdbName = chartEdb.EdbName
		excelEdb.EdbNameEn = excelEdb.EdbName
		excelEdb.Unit = chartEdb.Unit
		excelEdb.UnitEn = excelEdb.Unit
		excelEdb.DateSequence = chartEdb.DateSequenceStr
		excelEdb.DataSequence = chartEdb.DataSequenceStr
		excelEdb.MaxData = chartEdb.MaxData
		excelEdb.MinData = chartEdb.MinData
		excelEdb.IsOrder = chartEdb.IsOrder
		excelEdb.IsAxis = chartEdb.IsAxis
		excelEdb.FromTag = chartEdb.FromTag
		excelEdb.EdbInfoType = chartEdb.EdbInfoType
		excelEdb.LeadValue = chartEdb.LeadValue
		excelEdb.LeadUnit = chartEdb.LeadUnit
		excelEdb.ChartWidth = 1
		excelEdb.ModifyTime = time.Now()

		var dataList []*excelModel.ExcelChartData
		if excelInfo.BalanceType == 1 {
			tmpList, ok := dataListMap[k]
			if !ok {
				errMsg = "查询图表数据失败！"
				err = fmt.Errorf("查询图表数据失败！")
				return
			}
			for _, l := range tmpList {
				tmp := &excelModel.ExcelChartData{
					DataTime:      l.DataTime,
					Value:         l.Value,
					DataTimestamp: l.DataTimestamp,
				}
				dataList = append(dataList, tmp)
			}
		}

		// 处理日期列表和值列表
		addItem := &excelModel.AddChartEdbAndDataItem{
			ChartEdb: excelEdb,
			DataList: dataList,
		}
		chartEdbList = append(chartEdbList, addItem)
	}
	chartInfo, err, errMsg, isSendEmail = editBalanceExcelChart(req)
	if err != nil {
		//errMsg = "新增图表失败！"
		err = fmt.Errorf("新增图表失败！%s, %s", errMsg, err.Error())
		return
	}
	obj := new(excelModel.ExcelChartEdb)
	//删除原先多余的指标
	deleteEdbIds := make([]int, 0)
	for k, _ := range deleteMap {
		deleteEdbIds = append(deleteEdbIds, k)
	}
	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, deleteEdbIds)
	if err != nil {
		errMsg = "新增图表失败！"
		err = fmt.Errorf("新增图表数据失败！%s", err.Error())
		return
	}
	return
}

func editBalanceExcelChart(req request.AddBalanceTableChartReq) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
	isSendEmail = true // 默认错误的时候要发送邮件
	chartType := req.ChartType
	extraConfig := req.ExtraConfig

	chartInfo, err = data_manage.GetChartInfoById(req.ChartInfoId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			errMsg = "图表已被删除，请刷新页面"
			err = errors.New(errMsg)
			isSendEmail = false
			return
		}
		errMsg = "获取图表信息失败"
		err = errors.New("获取图表信息失败,Err:" + err.Error())
		return
	}
	// 查找主题类型id
	chartThemeType, err := chart_theme.GetChartThemeTypeByChartType(chartType)
	if err != nil {
		errMsg = "查找主题类型失败！"
		err = fmt.Errorf("%s, %s", errMsg, err.Error())
		return
	}
	chartThemeId := chartThemeType.DefaultChartThemeId
	// 季节性图表额外配置信息
	var seasonExtraConfig string

	if chartType == 2 {
		// 处理季节性图表横轴配置
		{
			if req.SeasonExtraConfig.XEndDate != "" {
				if req.SeasonExtraConfig.XStartDate > req.SeasonExtraConfig.XEndDate && req.SeasonExtraConfig.JumpYear != 1 {
					errMsg = "季节性图表配置信息异常：横坐标日期配置错误"
					err = fmt.Errorf("季节性图表配置信息异常： 横坐标日期配置错误")
					return
				}
				seasonExtra, tErr := json.Marshal(req.SeasonExtraConfig)
				if tErr != nil {
					errMsg = "季节性图表配置信息异常"
					err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
					return
				}

				seasonExtraConfig = string(seasonExtra)
			}
		}
	}

	/*var extraConfigEdbInfoIdArr []int
	extraConfigEdbInfoIdArr, err, errMsg = CheckChartExtraConfig(req.ChartType, req.ExtraConfig)
	if err != nil {
		err = errors.New("添加失败:" + err.Error())
		return
	}*/

	// 图表额外配置
	extraConfig, err, errMsg = HandleExtraConfig(chartType, extraConfig)
	if err != nil {
		if errMsg == `` {
			errMsg = "指标异常！"
		}
		err = fmt.Errorf("指标异常！Err:" + err.Error())
		return
	}

	//判断图表是否存在
	var condition string
	var pars []interface{}
	condition += " AND chart_info_id<>? "
	pars = append(pars, req.ChartInfoId)
	// 图表名称在不同图分类下不允许重复 需求调整时间：2022年11月07日09:47:07
	condition += " AND chart_classify_id=0 "

	condition += " AND chart_name=? AND source = ? "
	pars = append(pars, req.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)

	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
	if err != nil {
		errMsg = "判断图表名称是否存在失败"
		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
		return
	}

	if count > 0 {
		errMsg = "图表名称已存在，请重新填写"
		err = fmt.Errorf("判断图表名称是否存在失败")
		isSendEmail = false
		return
	}
	// todo 判断是否是禁用的图表
	//	disableVal := data.CheckIsDisableChart(edbInfoIdArr)
	chartInfo.ChartName = req.ChartName
	chartInfo.ChartNameEn = chartInfo.ChartName
	//chartInfo.EdbInfoIds = edbInfoIdStr
	//chartInfo.ChartClassifyId = req.ChartClassifyId
	chartInfo.ModifyTime = time.Now()
	chartInfo.IsSetName = 0
	// todo 判断是否需要重新计算用户的start_date
	chartInfo.DateType = 3

	if chartType == 0 {
		chartType = 1
	}
	chartInfo.ChartType = chartType

	calendar := req.Calendar
	if calendar == "" {
		calendar = "公历"
	}

	chartInfo.Calendar = calendar
	/*	chartInfo.StartDate = req.StartDate
		chartInfo.EndDate = req.EndDate
		chartInfo.SeasonStartDate = req.StartDate
		chartInfo.SeasonEndDate = req.EndDate*/
	chartInfo.LeftMin = req.LeftMin
	chartInfo.LeftMax = req.LeftMax
	chartInfo.RightMin = req.RightMin
	chartInfo.RightMax = req.RightMax
	chartInfo.Right2Min = req.Right2Min
	chartInfo.Right2Max = req.Right2Max
	chartInfo.MinMaxSave = req.MinMaxSave
	//chartInfo.Disabled = disableVal
	//chartInfo.BarConfig = barChartConf
	chartInfo.ExtraConfig = extraConfig
	chartInfo.SeasonExtraConfig = seasonExtraConfig
	//chartInfo.StartYear = req.StartYear
	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
	chartInfo.ChartThemeId = chartThemeId
	chartInfo.SourcesFrom = req.SourcesFrom
	/*	chartInfo.Instructions = req.Instructions
		chartInfo.MarkersLines = req.MarkersLines
		chartInfo.MarkersAreas = req.MarkersAreas
		chartInfo.Unit = req.Unit
		chartInfo.UnitEn = req.UnitEn*/
	/*newId, err := data_manage.AddChartInfo(chartInfo)
	if err != nil {
		errMsg = `保存失败`
		err = fmt.Errorf("保存失败，Err:" + err.Error())
		return
	}
	chartInfo.ChartInfoId = int(newId)*/

	//添加es数据
	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)

	return
}

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, err := TransferChartEdbToEdbMappingFormat(chartInfoId, chartType, mappingListTmp, dataListMap)
	if err != nil {
		return
	}
	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
	}

	// todo 平衡表图表操作权限平衡表表格的操作权限保持一致，前端未用到该按钮权限，故不处理
	chartInfo.IsEdit, _ = GetBalanceExcelInfoOpButtonByChartInfoId(sysUser.AdminId, chartInfo.ChartInfoId, 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 = 1
			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
			// 对dataList 根据dataTimestamp 进行排序
			sort.Slice(dataList, func(i, j int) bool {
				return dataList[i].DataTimestamp < dataList[j].DataTimestamp
			})
		} else {
			//err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.EdbInfoId))
			utils.FileLog.Info(fmt.Sprintf("获取失败,指标数据异常 %d", v.EdbInfoId))
		}
		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
}

// GetBalanceExcelSeasonChartLegendPreview 获取预览的季节性图例
func GetBalanceExcelSeasonChartLegendPreview(dataList []*data_manage.EdbDataList, calendar string, seasonExtraConfigReq data_manage.SeasonExtraItem) (quarterDataList data_manage.QuarterDataList, err error, errMsg string) {
	seasonExtraConfig := ""
	if seasonExtraConfigReq.XEndDate != "" {
		if seasonExtraConfigReq.XStartDate > seasonExtraConfigReq.XEndDate && seasonExtraConfigReq.JumpYear != 1 {
			errMsg = "季节性图表配置信息异常：横坐标日期配置错误"
			err = fmt.Errorf("季节性图表配置信息异常： 横坐标日期配置错误")
			return
		}
		seasonExtra, tErr := json.Marshal(seasonExtraConfigReq)
		if tErr != nil {
			errMsg = "季节性图表配置信息异常"
			err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
			return
		}

		seasonExtraConfig = string(seasonExtra)
	}
	var latestDate time.Time //最新日期
	startDate, endDate, _, _, _, _ := getBalanceDataListStartDateAndValue(dataList)
	calendarPreYear := 0
	startDateReal := startDate
	latestDate, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
	if calendar == "农历" {
		newStartDateReal, e := time.Parse(utils.FormatDate, startDateReal)
		if e != nil {
			err = fmt.Errorf("开始时间解析失败 time.Parse:" + e.Error())
			return
		}
		calendarPreYear = newStartDateReal.Year() - 1
		newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
		startDateReal = newStartDateReal.Format(utils.FormatDate)
	}
	if calendar == "农历" {
		if len(dataList) <= 0 {
			return
		} else {
			result, tmpErr := data_manage.AddCalculateQuarterV6(dataList)
			if tmpErr != nil {
				err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
				return
			}
			quarterDataList, err = GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
			if err != nil {
				err = errors.New("获取季节性图表数据失败,Err:" + err.Error())
				return
			}
		}

	} else {
		quarterDataList, err = GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
		if err != nil {
			err = errors.New("获取季节性图表数据失败,Err:" + err.Error())
			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
}

// AddBalanceStaticExcel 另存为和存为静态表以及子表的复制都调用该接口
func AddBalanceStaticExcel(oldExcelInfo *excelModel.ExcelInfo, excelClassifyId int, versionName string, sysUser *system.Admin, parentId, relExcelInfoId, balanceType int, childExcelList []*excelModel.ExcelInfo, pingNameFlag bool, excelDataMap map[int]map[int][]*data_manage.EdbDataList) (excelInfo *excelModel.ExcelInfo, err error, errMsg string, isSendEmail bool) {
	isSendEmail = true

	versionName = utils.TrimLRStr(versionName)
	// 检验分类下是否存在该表格名称
	// todo 检验动态表分类下表格名称是否存在
	if balanceType == 1 && versionName != "" {
		var condition string
		var pars []interface{}
		condition += " AND rel_excel_info_id=? AND balance_type=1 AND parent_id=0"
		pars = append(pars, oldExcelInfo.ExcelInfoId)

		condition += " AND version_name=? "
		pars = append(pars, versionName)

		count, tmpErr := excelModel.GetExcelInfoCountByCondition(condition, pars)
		if tmpErr != nil {
			errMsg = "查询版本名称失败"
			err = tmpErr
			return
		}
		if count > 0 {
			errMsg = "表格版本名称已存在，请重新填写版本名称"
			err = errors.New(errMsg)
			isSendEmail = false
			return
		}
	}

	// 表格信息
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	excelName := oldExcelInfo.ExcelName
	if pingNameFlag && versionName != "" && parentId == 0 {
		excelName += "(" + versionName + ")"
	}

	// 处理表格内容, 静态表去除动态指标关联
	content := oldExcelInfo.Content
	excelInfo = &excelModel.ExcelInfo{
		//ExcelInfoId:     0,
		ExcelName:          excelName,
		Source:             oldExcelInfo.Source,
		ExcelType:          oldExcelInfo.ExcelType,
		UniqueCode:         utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
		ExcelClassifyId:    excelClassifyId,
		SysUserId:          sysUser.AdminId,
		SysUserRealName:    sysUser.RealName,
		Content:            content,
		ExcelImage:         oldExcelInfo.ExcelImage,
		FileUrl:            oldExcelInfo.FileUrl,
		ParentId:           parentId,
		RelExcelInfoId:     relExcelInfoId,
		VersionName:        versionName,
		UpdateUserId:       sysUser.AdminId,
		UpdateUserRealName: sysUser.RealName,
		BalanceType:        balanceType,
		Sort:               oldExcelInfo.Sort,
		IsDelete:           0,
		ModifyTime:         time.Now(),
		CreateTime:         time.Now(),
	}

	excelEdbMappingList := make([]*excelModel.ExcelEdbMapping, 0)
	if balanceType == 0 {
		// 复制动态表才需要获取原excel与指标的关系表
		excelEdbMappingListTmp, e := excelModel.GetAllExcelEdbMappingByExcelInfoId(oldExcelInfo.ExcelInfoId)
		if e != nil {
			err = e
			errMsg = "获取失败"
			return
		}
		for _, v := range excelEdbMappingListTmp {
			tmp := new(excelModel.ExcelEdbMapping)
			tmp.EdbInfoId = v.EdbInfoId
			tmp.Source = utils.BALANCE_TABLE
			tmp.CreateTime = time.Now()
			tmp.ModifyTime = time.Now()
			excelEdbMappingList = append(excelEdbMappingList, tmp)
		}
	}

	var childExcel *excelModel.ExcelInfo
	err = excelModel.AddExcelInfo(excelInfo, excelEdbMappingList, childExcel)
	if err != nil {
		errMsg = "保存失败"
		return
	}
	if parentId == 0 && len(childExcelList) > 0 {
		for _, childExcelInfo := range childExcelList {
			_, err, errMsg, isSendEmail = AddBalanceStaticExcel(childExcelInfo, excelClassifyId, versionName, sysUser, excelInfo.ExcelInfoId, relExcelInfoId, balanceType, []*excelModel.ExcelInfo{}, pingNameFlag, excelDataMap)
			if err != nil {
				return
			}
		}
	} else if parentId > 0 {
		// 如果复制的是动态表的子表，则同步复制关联的图表
		// 查出所有的chart_list, 同步复制图表和图表指标
		// 相关联指标
		mappingListTmp, e := excelModel.GetExcelChartEdbMappingByExcelInfoId(oldExcelInfo.ExcelInfoId)
		if e != nil {
			errMsg = "获取图表指标失败"
			err = fmt.Errorf(" 获取图表，指标信息失败 Err:%s", e.Error())
			return
		}
		mappingListMap := make(map[int][]*excelModel.ExcelChartEdb, 0)
		charInfoIds := make([]int, 0)
		for k, _ := range mappingListTmp {
			mappingListTmp[k].ExcelInfoId = excelInfo.ExcelInfoId
			mappingListMap[mappingListTmp[k].ChartInfoId] = append(mappingListMap[mappingListTmp[k].ChartInfoId], mappingListTmp[k])
		}
		for k, _ := range mappingListMap {
			charInfoIds = append(charInfoIds, k)
		}
		if len(charInfoIds) > 0 {
			chartInfoList, e := data_manage.GetChartInfoViewByIdList(charInfoIds)
			if e != nil {
				errMsg = "获取失败"
				err = fmt.Errorf(" 获取图表，指标信息失败 Err:%s", e.Error())
				return
			}
			for _, chartInfo := range chartInfoList {
				mappingList, ok := mappingListMap[chartInfo.ChartInfoId]
				if !ok {
					err = fmt.Errorf("未找到图表关联的指标信息")
					return
				}
				chartEdbDataMap, ok := excelDataMap[chartInfo.ChartInfoId]
				if !ok && oldExcelInfo.BalanceType == 1 { //
					err = fmt.Errorf("未找到图表关联的指标信息")
					return
				}
				err, errMsg, isSendEmail = CopyBalanceExcelChart(chartInfo, mappingList, versionName, sysUser, pingNameFlag, chartEdbDataMap)
				if err != nil {
					err = fmt.Errorf("复制图表失败 Err:%s", err.Error())
					return
				}
			}
		}
	}
	return
}

// CopyBalanceExcelChart 复制平衡表图表
func CopyBalanceExcelChart(oldChartInfo *data_manage.ChartInfoView, oldChartEdbList []*excelModel.ExcelChartEdb, versionName string, sysUser *system.Admin, pingNameFlag bool, dataListMap map[int][]*data_manage.EdbDataList) (err error, errMsg string, isSendEmail bool) {
	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
	if pingNameFlag && versionName != "" {
		oldChartInfo.ChartName += "(" + versionName + ")"
	}
	for _, chartEdb := range oldChartEdbList {
		excelEdb := new(excelModel.ExcelChartEdb)
		excelEdb.EdbName = chartEdb.EdbName
		if pingNameFlag && versionName != "" {
			excelEdb.EdbName += "(" + versionName + ")"
		}
		excelEdb.EdbNameEn = excelEdb.EdbName
		excelEdb.Unit = chartEdb.Unit
		excelEdb.UnitEn = excelEdb.Unit
		randStr := utils.GetRandDigit(4)
		excelEdb.EdbCode = `T` + time.Now().Format("060102150405") + "_" + randStr
		excelEdb.ExcelInfoId = chartEdb.ExcelInfoId
		excelEdb.DateSequence = chartEdb.DateSequence
		excelEdb.DataSequence = chartEdb.DataSequence
		excelEdb.SysUserId = sysUser.AdminId
		excelEdb.SysUserRealName = sysUser.RealName
		excelEdb.MaxData = chartEdb.MaxData
		excelEdb.MinData = chartEdb.MinData
		excelEdb.IsOrder = chartEdb.IsOrder
		excelEdb.IsAxis = chartEdb.IsAxis
		excelEdb.FromTag = chartEdb.FromTag
		excelEdb.EdbInfoType = chartEdb.EdbInfoType
		excelEdb.LeadValue = chartEdb.LeadValue
		excelEdb.LeadUnit = chartEdb.LeadUnit
		excelEdb.ChartWidth = 1
		excelEdb.CreateTime = time.Now()
		excelEdb.ModifyTime = time.Now()
		var dataList []*excelModel.ExcelChartData
		tmpList, ok := dataListMap[chartEdb.ExcelChartEdbId]
		if ok {
			for _, l := range tmpList {
				tmp := &excelModel.ExcelChartData{
					DataTime:      l.DataTime,
					Value:         l.Value,
					DataTimestamp: l.DataTimestamp,
				}
				dataList = append(dataList, tmp)
			}
		}

		// 处理日期列表和值列表
		addItem := &excelModel.AddChartEdbAndDataItem{
			ChartEdb: excelEdb,
			DataList: dataList,
		}
		chartEdbList = append(chartEdbList, addItem)
	}
	chartInfo, err, errMsg, isSendEmail := copyBalanceExcelChart(oldChartInfo, sysUser.AdminId, sysUser.RealName)
	if err != nil {
		errMsg = "新增图表失败！"
		err = fmt.Errorf("新增图表失败！%s, %s", errMsg, err.Error())
		return
	}
	obj := new(excelModel.ExcelChartEdb)
	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, []int{})
	if err != nil {
		errMsg = "新增图表失败！"
		err = fmt.Errorf("新增图表数据失败！%s", err.Error())
		return
	}
	return
}

func copyBalanceExcelChart(oldChartInfo *data_manage.ChartInfoView, sysUserId int, sysUserRealName string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
	isSendEmail = true // 默认错误的时候要发送邮件

	oldChartInfo.ChartName = strings.Trim(oldChartInfo.ChartName, " ")
	if oldChartInfo.ChartName == "" {
		errMsg = "请填写图表名称！"
		err = fmt.Errorf(errMsg)
		isSendEmail = false
		return
	}
	//判断图表是否存在
	var condition string
	var pars []interface{}

	// 图表名称在不同图分类下不允许重复 需求调整时间：2022年11月07日09:47:07
	condition += " AND chart_classify_id=0 "

	condition += " AND chart_name=? AND source = ? "
	pars = append(pars, oldChartInfo.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)

	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
	if err != nil {
		errMsg = "判断图表名称是否存在失败"
		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
		return
	}

	if count > 0 {
		/*errMsg = "图表已存在，请重新填写"
		err = fmt.Errorf("判断图表名称是否存在失败")
		isSendEmail = false
		return*/
		oldChartInfo.ChartName += " " + strconv.Itoa(count)
	}

	chartInfo = new(data_manage.ChartInfo)
	chartInfo.ChartName = oldChartInfo.ChartName
	chartInfo.ChartNameEn = oldChartInfo.ChartName
	//chartInfo.EdbInfoIds = edbInfoIdStr
	//chartInfo.ChartClassifyId = req.ChartClassifyId
	chartInfo.SysUserId = sysUserId
	chartInfo.SysUserRealName = sysUserRealName
	chartInfo.CreateTime = time.Now()
	chartInfo.ModifyTime = time.Now()
	chartInfo.IsSetName = 0
	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)

	// todo 判断是否需要重新计算用户的start_date
	chartInfo.DateType = oldChartInfo.DateType
	chartInfo.ChartType = oldChartInfo.ChartType
	chartInfo.Calendar = oldChartInfo.Calendar
	/*	chartInfo.StartDate = req.StartDate
		chartInfo.EndDate = req.EndDate
		chartInfo.SeasonStartDate = req.StartDate
		chartInfo.SeasonEndDate = req.EndDate*/
	chartInfo.LeftMin = oldChartInfo.LeftMin
	chartInfo.LeftMax = oldChartInfo.LeftMax
	chartInfo.RightMin = oldChartInfo.RightMin
	chartInfo.RightMax = oldChartInfo.RightMax
	chartInfo.Right2Min = oldChartInfo.Right2Min
	chartInfo.Right2Max = oldChartInfo.Right2Max
	chartInfo.MinMaxSave = oldChartInfo.MinMaxSave
	//chartInfo.Disabled = disableVal
	//chartInfo.BarConfig = barChartConf
	chartInfo.ExtraConfig = oldChartInfo.ExtraConfig
	chartInfo.SeasonExtraConfig = oldChartInfo.SeasonExtraConfig
	//chartInfo.StartYear = req.StartYear
	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
	chartInfo.ChartThemeId = oldChartInfo.ChartThemeId
	chartInfo.SourcesFrom = oldChartInfo.SourcesFrom
	/*	chartInfo.Instructions = req.Instructions
		chartInfo.MarkersLines = req.MarkersLines
		chartInfo.MarkersAreas = req.MarkersAreas
		chartInfo.Unit = req.Unit
		chartInfo.UnitEn = req.UnitEn*/
	/*newId, err := data_manage.AddChartInfo(chartInfo)
	if err != nil {
		errMsg = `保存失败`
		err = fmt.Errorf("保存失败，Err:" + err.Error())
		return
	}
	chartInfo.ChartInfoId = int(newId)*/

	//添加es数据
	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)

	return
}

// CopyBalanceExcel 动态平衡表另存为
func CopyBalanceExcel(oldExcelInfo *excelModel.ExcelInfo, excelClassifyId int, excelName string, sysUser *system.Admin) (excelInfo *excelModel.ExcelInfo, err error, errMsg string, isSendEmail bool) {
	if oldExcelInfo.ParentId != 0 && oldExcelInfo.BalanceType != 0 {
		errMsg = "平衡表类型错误"
		err = fmt.Errorf("平衡表类型错误 ")
		return
	}

	// 查询excel表格名称是否已经存在
	// 检验分类下是否存在该表格名称
	{
		var nameCondition string
		var namePars []interface{}
		nameCondition += " AND excel_classify_id=?  AND parent_id=?"
		namePars = append(namePars, excelClassifyId, 0)

		nameCondition += " AND excel_name=? "
		namePars = append(namePars, excelName)

		count, tmpErr := excelModel.GetExcelInfoCountByCondition(nameCondition, namePars)
		if tmpErr != nil {
			errMsg = "判断表格名称是否存在失败"
			err = tmpErr
			return
		}
		if count > 0 {
			errMsg = "表格名称已存在，请重新填写表格名称"
			err = errors.New(errMsg)
			isSendEmail = false
			return
		}
	}
	oldExcelInfo.ExcelName = excelName

	// 先复制动态表，再复制动态子表，复制静态表，再复制静态子表
	condition := " AND parent_id = ? AND balance_type = 0 "
	var pars []interface{}
	pars = append(pars, oldExcelInfo.ExcelInfoId)
	childExcelList, err := excelModel.GetExcelInfoListByCondition(condition, pars)
	if err != nil {
		errMsg = "获取子表失败"
		err = fmt.Errorf("获取子表失败 %s", err.Error())
		return
	}
	// 查询出每个子表的内容，并将内容转为静态版本
	excelDataMap := make(map[int]map[int][]*data_manage.EdbDataList)
	excelInfo, err, errMsg, isSendEmail = AddBalanceStaticExcel(oldExcelInfo, excelClassifyId, "", sysUser, 0, 0, 0, childExcelList, false, excelDataMap)
	if err != nil {
		errMsg = "复制动态表失败"
		err = fmt.Errorf("复制动态表失败 %s", err.Error())
		return
	}

	//复制静态表
	staticCondition := " AND parent_id = 0 AND balance_type = 1 AND rel_excel_info_id=? "
	var staticPars []interface{}
	staticPars = append(staticPars, oldExcelInfo.ExcelInfoId)
	staticExcelList, err := excelModel.GetExcelInfoListByCondition(staticCondition, staticPars)
	if err != nil {
		errMsg = "获取子表失败"
		err = fmt.Errorf("获取子表失败 %s", err.Error())
		return
	}
	for _, staticExcelInfo := range staticExcelList {
		cCondition := " AND parent_id = ? AND balance_type = 1"
		var cPars []interface{}
		cPars = append(cPars, staticExcelInfo.ExcelInfoId)
		childList, e := excelModel.GetExcelInfoListByCondition(cCondition, cPars)
		if e != nil {
			errMsg = "获取子表失败"
			err = fmt.Errorf("获取子表失败 %s", err.Error())
			return
		}
		excelDataMap = make(map[int]map[int][]*data_manage.EdbDataList)
		for _, childExcelInfo := range childList {
			//得到表格数据并落库
			tmpDataList, e := excelModel.GetExcelChartDataByExcelInfoId(childExcelInfo.ExcelInfoId)
			if e != nil {
				err = fmt.Errorf(" 获取图表，指标信息失败 Err:%s", err.Error())
				return
			}
			if len(tmpDataList) > 0 {
				for _, v := range tmpDataList {
					child, ok := excelDataMap[v.ChartInfoId]
					if !ok {
						child = make(map[int][]*data_manage.EdbDataList)
					}
					tmp := &data_manage.EdbDataList{
						DataTime:      v.DataTime,
						DataTimestamp: v.DataTimestamp,
						Value:         v.Value,
					}
					child[v.ExcelChartEdbId] = append(child[v.ExcelChartEdbId], tmp)
					excelDataMap[v.ChartInfoId] = child
				}
			}
		}
		_, err, errMsg, isSendEmail = AddBalanceStaticExcel(staticExcelInfo, excelClassifyId, staticExcelInfo.VersionName, sysUser, 0, excelInfo.ExcelInfoId, 1, childList, false, excelDataMap)
		if err != nil {
			errMsg = "复制动态表失败"
			err = fmt.Errorf("复制动态表失败 %s", err.Error())
			return
		}
	}
	return
}

func TransferChartEdbToEdbMappingFormat(chartInfoId, chartType int, mappingListTmp []*excelModel.ExcelChartEdb, dataListMap map[int][]*data_manage.EdbDataList) (mappingList []*data_manage.ChartEdbInfoMapping, err error) {
	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))
			utils.FileLog.Info(fmt.Sprintf("获取失败,指标数据异常 %d", v.ExcelChartEdbId))
		}
		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:         v.EdbNameEn,
			EdbAliasNameEn:    "",
			EdbType:           0,
			Frequency:         "",
			FrequencyEn:       "",
			Unit:              v.Unit,
			UnitEn:            v.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:       v.EdbInfoType,
			//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)
	}
	return
}

// GetBalanceExcelInfoOpButtonByChartInfoId 获取图表权限
func GetBalanceExcelInfoOpButtonByChartInfoId(sysUserId, chartInfoId int, chartHaveOperaAuth bool) (opButton bool, err error) {
	// 如果没有数据权限，那么直接返回
	if !chartHaveOperaAuth {
		return
	}
	// 获取表格信息
	excelInfo, e := excelModel.GetExcelInfoByChartInfoId(chartInfoId)
	if e != nil {
		err = fmt.Errorf("获取ETA表格失败 Err %s", e.Error())
		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, e = excelModel.GetExcelInfoById(checkExcelInfoId)
			if e != nil {
				err = fmt.Errorf("获取平衡表格信息失败，Err:" + e.Error())
				return
			}
		}
	} else {
		return
	}
	// 数据权限
	haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUserId)
	if e != nil {
		err = fmt.Errorf("获取表格权限信息失败，Err" + e.Error())
		return
	}
	// 如果没有数据权限，那么直接返回
	if !haveOperaAuth {
		return
	}
	//button := GetBalanceExcelInfoOpButton(sysUserId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)

	if sysUserId == checkExcelInfo.SysUserId {
		opButton = true
	} else {
		obj := new(excelModel.ExcelWorker)
		workerList, e := obj.GetByExcelInfoId(checkExcelInfo.ExcelInfoId)
		if e == nil {
			for _, v := range workerList {
				if v.SysUserId == sysUserId {
					opButton = true
					break
				}
			}
		}
	}
	return
}
