package cross_variety import ( "encoding/json" "errors" "eta_gn/eta_api/models/data_manage" cross_varietyModel "eta_gn/eta_api/models/data_manage/cross_variety" "eta_gn/eta_api/models/data_manage/cross_variety/request" "eta_gn/eta_api/models/system" "eta_gn/eta_api/services/data" "eta_gn/eta_api/utils" "fmt" "github.com/shopspring/decimal" "strconv" "strings" "time" ) // ChartInfoResp 截面散点图数据 type ChartInfoResp struct { XName string `description:"x轴名称"` XNameEn string `description:"x轴名称(英文)"` XUnitName string `description:"x轴单位名称"` XUnitNameEn string `description:"x轴单位名称(英文)"` YName string `description:"y轴名称"` YNameEn string `description:"y轴名称(英文)"` YUnitName string `description:"y轴单位名称"` YUnitNameEn string `description:"y轴单位名称(英文)"` XMinValue string `description:"X轴的最小值"` XMaxValue string `description:"X轴的最大值"` YMinValue string `description:"Y轴的最小值"` YMaxValue string `description:"Y轴的最大值"` DataList []SectionScatterSeriesItemResp `description:"数据列"` } // SectionScatterSeriesItemResp 系列的返回 type SectionScatterSeriesItemResp struct { Name string `description:"系列名"` NameEn string `description:"系列名(英文)"` Color string `description:"颜色"` CoordinatePointData []CoordinatePoint `description:"趋势线的前后坐标点"` } // SectionScatterEdbItemResp 截面散点的返回参数 type SectionScatterEdbItemResp struct { XEdbInfoId int `description:"X轴指标id"` XDate string `description:"X轴指标实际日期"` XName string `description:"X轴指标名称"` XNameEn string `description:"X轴指标英文名称"` XValue float64 `description:"X轴实际值"` YEdbInfoId int `description:"Y轴指标id"` YDate string `description:"Y轴指标实际日期"` YName string `description:"Y轴指标名称"` YNameEn string `description:"Y轴指标英文名称"` YValue float64 `description:"Y轴实际值"` IsShow bool `description:"是否展示"` Name string `description:"标签名称"` NameEn string `description:"英文标签名称"` } // CoordinatePoint 坐标点 type CoordinatePoint struct { X float64 Y float64 XEdbInfoId int YEdbInfoId int XDate string YDate string DateType int `description:"日期类型:1-最新日期;2-N天前;3-固定日期"` DaysAgo int `description:"N天前的N值"` ShowTips int `description:"是否显示标注:0-否;1-是"` } // GetChartData // @Description: 获取跨品种分析图表数据 // @author: Roc // @datetime 2023-11-24 09:42:59 // @param chartInfoId int // @param config request.ChartConfigReq // @return edbList []*data_manage.ChartEdbInfoMapping // @return dataResp ChartInfoResp // @return err error // @return errMsg string // @return isSendEmail bool func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*data_manage.ChartEdbInfoMapping, dataResp ChartInfoResp, err error, errMsg string, isSendEmail bool) { moveUnitDays, ok := utils.FrequencyDaysMap[config.CalculateUnit] if !ok { errMsg = "错误的分析周期" err = errors.New(errMsg) isSendEmail = false return } isSendEmail = true // 品种map varietyMap := make(map[int]*cross_varietyModel.ChartVariety) { varietyList, tmpErr := cross_varietyModel.GetVarietyListByIdList(config.VarietyList) if tmpErr != nil { err = tmpErr return } for _, v := range varietyList { varietyMap[v.ChartVarietyId] = v } } // 标签m var xTagInfo, yTagInfo *cross_varietyModel.ChartTag { tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{config.TagX, config.TagY}) if tmpErr != nil { err = tmpErr return } for _, v := range tagList { if v.ChartTagId == config.TagX { xTagInfo = v } else if v.ChartTagId == config.TagY { yTagInfo = v } } } if xTagInfo == nil { errMsg = "找不到对应的X轴标签" err = errors.New(errMsg) return } if yTagInfo == nil { errMsg = "找不到对应的Y轴标签" err = errors.New(errMsg) return } xVarietyEdbMap, yVarietyEdbMap, edbInfoIdList, err := GetXYEdbIdList(config.TagX, config.TagY, config.VarietyList) if err != nil { return } if len(edbInfoIdList) <= 0 { errMsg = "品种未配置指标" err = errors.New(errMsg) isSendEmail = false return } mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList) if err != nil { errMsg = "获取指标信息失败" err = errors.New("获取指标信息失败,ERR:" + err.Error()) return } // 指标对应的所有数据 chartType := 1 //1:普通图,2:季节性图 calendar := "公历" edbDataListMap, edbList, err := data.GetEdbDataMapList(chartInfoId, chartType, calendar, "", "", mappingList, "") if err != nil { return } currDay := time.Now() currDay = time.Date(currDay.Year(), currDay.Month(), currDay.Day(), 0, 0, 0, 0, time.Local) dataMap := make(map[string]float64) dateMap := make(map[string]string) dateTypeMap := make(map[int]int) // 日期配置key对应的日期类型 daysAgoMap := make(map[int]int) // 日期配置key对应的N天前的N值 showTipsMap := make(map[int]int) // 日期配置key对应点是否显示标注 for dateIndex, dateConfig := range config.DateConfigList { dateTypeMap[dateIndex] = dateConfig.DateType daysAgoMap[dateIndex] = dateConfig.Num showTipsMap[dateIndex] = dateConfig.ShowTips for _, edbInfoMapping := range mappingList { // 数据会是正序的 dataList, ok := edbDataListMap[edbInfoMapping.EdbInfoId] if !ok { continue } lenData := len(dataList) if lenData <= 0 { continue } // 数据的开始索引 k := lenData - 1 // 数据的最晚日期 dataEndDateStr := dataList[k].DataTime dataEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, dataEndDateStr, time.Local) if tmpErr != nil { err = tmpErr return } // 数据开始日期 endDateStr := `` var endDate time.Time var currVal float64 switch dateConfig.DateType { case 1: // 1:最新日期; endDateStr = dataEndDateStr endDate = dataEndDate currVal = dataList[k].Value case 2: // 2:N天前(原为指标最新日期的N天前, 现为系统日期的N天) tmpEndDate := time.Now().AddDate(0, 0, -dateConfig.Num) tmpEndDateStr := tmpEndDate.Format(utils.FormatDate) for i := k; i >= 0; i-- { tmpDateStr := dataList[i].DataTime // 如果正好是这一天,那么就直接break了 if tmpEndDateStr == tmpDateStr { k = i endDateStr = tmpDateStr endDate = tmpEndDate currVal = dataList[i].Value break } tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local) if tmpErr != nil { err = tmpErr return } // 如果这期的日期晚于选择的日期,那么继续遍历 if tmpDate.After(tmpEndDate) { continue } k = i endDateStr = tmpDateStr endDate = tmpDate currVal = dataList[i].Value break } case 3: // 固定日期 if dateConfig.FixDate == "" { errMsg = "固定日期不可为空" err = fmt.Errorf("固定日期为空") return } strFixDate := dateConfig.FixDate fixDate, e := time.ParseInLocation(utils.FormatDate, strFixDate, time.Local) if e != nil { errMsg = "固定日期格式有误" err = fmt.Errorf("固定日期有误, FixDate: %s", dateConfig.FixDate) return } for i := k; i >= 0; i-- { strThisDate := dataList[i].DataTime // 如果正好是这一天,那么就直接break了 if strFixDate == strThisDate { k = i endDateStr = strThisDate endDate = fixDate currVal = dataList[i].Value break } // 若固定日期无值, 则取固定日期之前, 能找到的第一个值(同上N天前的逻辑) thisDate, e := time.ParseInLocation(utils.FormatDate, strThisDate, time.Local) if e != nil { err = fmt.Errorf("数据日期格式有误: %s", e.Error()) return } if thisDate.After(fixDate) { continue } k = i endDateStr = strThisDate endDate = thisDate currVal = dataList[i].Value break } } // 没有找到日期,那么就不处理 if endDateStr == `` || endDate.IsZero() { continue } // 最早的日期 earliestDate := endDate.AddDate(0, 0, -config.CalculateValue*moveUnitDays) earliestDateStr := earliestDate.Format(utils.FormatDate) var percentVal float64 // 百分位计算值 // 百分位数据区间算法 if config.PercentType == utils.PercentCalculateTypeRange { var minVal, maxVal float64 var isNotFirst bool // 是否是第一条数据 for i := k; i >= 0; i-- { tmpData := dataList[i] if !isNotFirst { maxVal = tmpData.Value minVal = tmpData.Value isNotFirst = true continue } tmpDateStr := dataList[i].DataTime // 如果正好是这一天,那么就直接break了 if earliestDateStr == tmpDateStr { break } tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local) if tmpErr != nil { err = tmpErr return } // 如果这期的日期早于选择的日期,那么继续停止遍历 if tmpDate.Before(earliestDate) { continue } if tmpData.Value > maxVal { maxVal = tmpData.Value } if tmpData.Value < minVal { minVal = tmpData.Value } } // 最大值等于最小值,说明计算结果无效 if maxVal == minVal { continue } // 数据区间百分位=(现值-Min)/(Max-Min) tmpV := (currVal - minVal) / (maxVal - minVal) * 100 percentVal, _ = decimal.NewFromFloat(tmpV).Round(4).Float64() } // 百分位数据个数算法 // 数据区间第一个和最后一个数据点的时间和数据分别为(T1,S1)(T2,S2); N=T1到T2指标数据个数, n=小于等于S2的数据个数 // 个数百分位=(n-1)/(N-1) if config.PercentType == utils.PercentCalculateTypeNum { // T1为earliestDate, T2为endDate, S2为currVal var tinyN, bigN int lastVal := decimal.NewFromFloat(currVal) for i := k; i >= 0; i-- { date, e := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local) if e != nil { err = fmt.Errorf("数据日期格式有误: %s", e.Error()) return } if !date.Before(earliestDate) && !date.After(endDate) { bigN += 1 dateVal := decimal.NewFromFloat(dataList[i].Value) if dateVal.LessThanOrEqual(lastVal) { tinyN += 1 } } } // N<=1时说明计算无效 if bigN <= 1 { continue } numerator := decimal.NewFromInt(int64(tinyN - 1)) denominator := decimal.NewFromInt(int64(bigN - 1)) percentVal, _ = numerator.Div(denominator).Mul(decimal.NewFromFloat(100)).Round(4).Float64() } // key的生成(日期配置下标+指标id) key := fmt.Sprint(dateIndex, "_", edbInfoMapping.EdbInfoId) dataMap[key] = percentVal dateMap[key] = endDateStr } } // 返回数据处理 dataList := make([]SectionScatterSeriesItemResp, 0) var xMinVal, xMaxVal, yMinVal, yMaxVal float64 var isNotFirst bool for _, varietyId := range config.VarietyList { xEdbInfoId, ok1 := xVarietyEdbMap[varietyId] if !ok1 { continue } yEdbInfoId, ok2 := yVarietyEdbMap[varietyId] if !ok2 { continue } variety, ok := varietyMap[varietyId] if !ok { continue } coordinatePointList := make([]CoordinatePoint, 0) for dateIndex, _ := range config.DateConfigList { key1 := fmt.Sprint(dateIndex, "_", xEdbInfoId) xVal, ok1 := dataMap[key1] if !ok1 { continue } key2 := fmt.Sprint(dateIndex, "_", yEdbInfoId) yVal, ok2 := dataMap[key2] if !ok2 { continue } if !isNotFirst { xMinVal = xVal xMaxVal = xVal yMinVal = yVal yMaxVal = yVal isNotFirst = true } else { if xVal < xMinVal { xMinVal = xVal } if xVal > xMaxVal { xMaxVal = xVal } if yVal < yMinVal { yMinVal = yVal } if yVal > yMaxVal { yMaxVal = yVal } } coordinatePointList = append(coordinatePointList, CoordinatePoint{ X: xVal, Y: yVal, XEdbInfoId: xEdbInfoId, YEdbInfoId: yEdbInfoId, XDate: dateMap[key1], YDate: dateMap[key2], DateType: dateTypeMap[dateIndex], // 日期类型 DaysAgo: daysAgoMap[dateIndex], // N天前的N值 ShowTips: showTipsMap[dateIndex], // 是否显示标注 }) } dataList = append(dataList, SectionScatterSeriesItemResp{ Name: variety.ChartVarietyName, NameEn: variety.ChartVarietyNameEn, Color: "", CoordinatePointData: coordinatePointList, }) } // 处理颜色 colorMap := utils.GetColorMap() for k, _ := range dataList { if c, ok1 := colorMap[k]; ok1 { dataList[k].Color = c } } dataResp = ChartInfoResp{ XName: xTagInfo.ChartTagName + "百分位", XNameEn: xTagInfo.ChartTagNameEn, XUnitName: "%", XUnitNameEn: "%", YName: yTagInfo.ChartTagName + "百分位", YNameEn: yTagInfo.ChartTagNameEn, YUnitName: "%", YUnitNameEn: "%", XMinValue: fmt.Sprint(xMinVal), XMaxValue: fmt.Sprint(xMaxVal), YMinValue: fmt.Sprint(yMinVal), YMaxValue: fmt.Sprint(yMaxVal), DataList: dataList, } // 去除返回指标中的数据信息,避免没必要的数据传输 for k, _ := range edbList { edbList[k].DataList = nil } return } // GetXYEdbIdList // @Description: 根据标签id和品种获取指标列表信息 // @author: Roc // @datetime 2023-11-27 14:31:23 // @param tagX int // @param tagY int // @param varietyList []int // @return xVarietyEdbMap map[int]int // @return yVarietyEdbMap map[int]int // @return edbInfoIdList []int // @return errMsg string // @return err error func GetXYEdbIdList(tagX, tagY int, varietyList []int) (xVarietyEdbMap, yVarietyEdbMap map[int]int, edbInfoIdList []int, err error) { edbInfoIdList = make([]int, 0) xVarietyEdbMap = make(map[int]int) yVarietyEdbMap = make(map[int]int) xList, err := cross_varietyModel.GetChartTagVarietyListByTagAndVariety(tagX, varietyList) if err != nil { err = errors.New("获取X轴的品种指标配置信息失败,Err:" + err.Error()) return } yList, err := cross_varietyModel.GetChartTagVarietyListByTagAndVariety(tagY, varietyList) if err != nil { err = errors.New("获取Y轴的品种指标配置信息失败,Err:" + err.Error()) return } baseVarietyIdMap := make(map[int]int) for _, v := range xList { baseVarietyIdMap[v.ChartVarietyId] = v.ChartVarietyId } // 两个标签里面的品种并集 needVarietyIdMap := make(map[int]int) for _, v := range yList { if val, ok := baseVarietyIdMap[v.ChartVarietyId]; ok { // 如果在 map2 中存在相同的键,则将键和值添加到结果中 needVarietyIdMap[v.ChartVarietyId] = val } } for _, v := range xList { if _, ok := needVarietyIdMap[v.ChartVarietyId]; ok { xVarietyEdbMap[v.ChartVarietyId] = v.EdbInfoId edbInfoIdList = append(edbInfoIdList, v.EdbInfoId) } } for _, v := range yList { if _, ok := needVarietyIdMap[v.ChartVarietyId]; ok { yVarietyEdbMap[v.ChartVarietyId] = v.EdbInfoId edbInfoIdList = append(edbInfoIdList, v.EdbInfoId) } } return } // AddChartInfo // @Description: AddChartInfo // @author: Roc // @datetime 2023-11-24 15:58:14 // @param req request.AddChartReq // @param sysUser *system.Admin // @return chartInfo *data_manage.ChartInfo // @return lang string // @return err error // @return errMsg string // @return isSendEmail bool func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) { isSendEmail = true source := utils.CHART_SOURCE_CROSS_HEDGING req.ChartName = strings.Trim(req.ChartName, " ") if req.ChartName == "" { errMsg = "请填写图表名称!" err = errors.New(errMsg) isSendEmail = false return } if req.TagX <= 0 { errMsg = "请选择X轴坐标的标签!" err = errors.New(errMsg) isSendEmail = false return } if req.TagY <= 0 { errMsg = "请选择Y轴坐标的标签!" err = errors.New(errMsg) isSendEmail = false return } if req.CalculateValue <= 0 { errMsg = "请设置时间长度!" err = errors.New(errMsg) isSendEmail = false return } if req.CalculateUnit == `` { errMsg = "请设置时间频度!" err = errors.New(errMsg) isSendEmail = false return } if req.PercentType != utils.PercentCalculateTypeRange && req.PercentType != utils.PercentCalculateTypeNum { errMsg = "请选择百分位" err = errors.New(errMsg) isSendEmail = false return } // 品种配置 if len(req.VarietyList) < 0 { errMsg = "请选择品种!" err = errors.New(errMsg) isSendEmail = false return } // 日期配置 dateConfigList := len(req.DateConfigList) if dateConfigList < 0 { errMsg = "请选择日期!" err = errors.New(errMsg) isSendEmail = false return } if dateConfigList > 5 { errMsg = "日期数量已达上限!" err = errors.New(errMsg) isSendEmail = false return } // 基础配置转string extraConfigByte, err := json.Marshal(req) if err != nil { return } chartClassify, err := data_manage.GetCrossVarietyChartClassifyBySysUserId(sysUser.AdminId) if err != nil { if !utils.IsErrNoRow(err) { errMsg = "获取分类信息失败" err = errors.New("获取分类信息失败,Err:" + err.Error()) return } // 分类没有,需要创建新的分类,那么err置空 err = nil chartClassify, err, errMsg, isSendEmail = data.AddChartClassify(sysUser.RealName, 0, 1, source, lang, sysUser) if err != nil { return } } edbInfoIdArr := make([]int, 0) // 数据校验(品种、标签、指标) { // 标签m var xTagInfo, yTagInfo *cross_varietyModel.ChartTag { tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY}) if tmpErr != nil { err = tmpErr return } for _, v := range tagList { if v.ChartTagId == req.TagX { xTagInfo = v } else if v.ChartTagId == req.TagY { yTagInfo = v } } } if xTagInfo == nil { errMsg = "找不到对应的X轴标签" err = errors.New(errMsg) return } if yTagInfo == nil { errMsg = "找不到对应的Y轴标签" err = errors.New(errMsg) return } _, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList) if tmpErr != nil { err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error()) return } if len(edbInfoIdList) <= 0 { errMsg = "品种未配置指标" err = errors.New(errMsg) isSendEmail = false return } edbInfoIdArr = edbInfoIdList mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList) if tmpErr != nil { errMsg = "获取指标信息失败" err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error()) return } if len(mappingList) <= 0 { errMsg = "关联指标为空" err = errors.New(errMsg) isSendEmail = false return } } var chartInfoId int // 判断图表是否存在 chartInfo = new(data_manage.ChartInfo) chartInfo.ChartName = req.ChartName chartInfo.ChartNameEn = req.ChartNameEn chartInfo.SysUserId = sysUser.AdminId chartInfo.SysUserRealName = sysUser.RealName chartInfo.ChartImage = req.ChartImage 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) chartInfo.ChartType = 9 // 相关性图 chartInfo.Calendar = "公历" chartInfo.DateType = 6 chartInfo.LeftMin = req.LeftMin chartInfo.LeftMax = req.LeftMax chartInfo.XMin = req.XMin chartInfo.XMax = req.XMax chartInfo.Source = source chartInfo.ExtraConfig = string(extraConfigByte) chartInfo.ChartImage = req.ChartImage chartInfo.ChartThemeId = req.ChartThemeId chartInfo.SourcesFrom = req.SourcesFrom chartInfo.Instructions = req.Instructions chartInfo.MarkersLines = req.MarkersLines chartInfo.MarkersAreas = req.MarkersAreas // 图表品种 chartVarietyMappingList := make([]*cross_varietyModel.ChartVarietyMapping, 0) for _, varietyId := range req.VarietyList { chartVarietyMappingList = append(chartVarietyMappingList, &cross_varietyModel.ChartVarietyMapping{ Id: 0, ChartInfoId: 0, ChartVarietyId: varietyId, ModifyTime: time.Now(), CreateTime: time.Now(), }) } // 图表配置 chartInfoCrossVariety := &cross_varietyModel.ChartInfoCrossVariety{ Id: 0, ChartInfoId: 0, ChartXTagId: req.TagX, ChartYTagId: req.TagY, CalculateValue: req.CalculateValue, CalculateUnit: req.CalculateUnit, ModifyTime: time.Now(), CreateTime: time.Now(), } // 新增图表和指标mapping chartInfoId, e := cross_varietyModel.CreateChart(chartInfo, chartClassify, chartVarietyMappingList, chartInfoCrossVariety) if e != nil { errMsg = "操作失败" err = errors.New("新增相关性图表失败, Err: " + e.Error()) return } chartInfo.ChartInfoId = chartInfoId // 添加指标引用记录 _ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo) //添加es数据 go data.EsAddOrEditChartInfo(chartInfoId) return } // EditChartInfo // @Description: 编辑图表 // @author: Roc // @datetime 2023-11-24 15:58:31 // @param req request.EditChartReq // @param sysUser *system.Admin // @return chartItem *data_manage.ChartInfo // @return err error // @return errMsg string // @return isSendEmail bool func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string) (chartItem *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) { isSendEmail = true chartItem, err = data_manage.GetChartInfoById(req.ChartInfoId) if err != nil { if utils.IsErrNoRow(err) { errMsg = "图表已被删除,请刷新页面" err = errors.New(errMsg) isSendEmail = false return } errMsg = "获取图表信息失败" err = errors.New("获取图表信息失败,Err:" + err.Error()) return } if chartItem.Source != utils.CHART_SOURCE_CROSS_HEDGING { errMsg = "该图不是跨品种分析图表!" err = errors.New(errMsg) isSendEmail = false return } req.ChartName = strings.Trim(req.ChartName, " ") if req.ChartName == "" { errMsg = "请填写图表名称!" err = errors.New(errMsg) isSendEmail = false return } if req.TagX <= 0 { errMsg = "请选择X轴坐标的标签!" err = errors.New(errMsg) isSendEmail = false return } if req.TagY <= 0 { errMsg = "请选择Y轴坐标的标签!" err = errors.New(errMsg) isSendEmail = false return } if req.CalculateValue <= 0 { errMsg = "请设置时间长度!" err = errors.New(errMsg) isSendEmail = false return } if req.CalculateUnit == `` { errMsg = "请设置时间频度!" err = errors.New(errMsg) isSendEmail = false return } if req.PercentType != utils.PercentCalculateTypeRange && req.PercentType != utils.PercentCalculateTypeNum { errMsg = "请选择百分位" err = errors.New(errMsg) isSendEmail = false return } // 品种配置 if len(req.VarietyList) < 0 { errMsg = "请选择品种!" err = errors.New(errMsg) isSendEmail = false return } // 日期配置 dateConfigList := len(req.DateConfigList) if dateConfigList < 0 { errMsg = "请选择日期!" err = errors.New(errMsg) isSendEmail = false return } if dateConfigList > 5 { errMsg = "日期数量已达上限!" err = errors.New(errMsg) isSendEmail = false return } // 基础配置转string extraConfigByte, err := json.Marshal(req) if err != nil { return } // 图表操作权限 ok := data.CheckOpChartPermission(sysUser, chartItem.SysUserId, true) if !ok { errMsg = "没有该图表的操作权限" err = errors.New(errMsg) isSendEmail = false return } edbInfoIdArr := make([]int, 0) // 数据校验(品种、标签、指标) { // 标签m var xTagInfo, yTagInfo *cross_varietyModel.ChartTag { tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY}) if tmpErr != nil { err = tmpErr return } for _, v := range tagList { if v.ChartTagId == req.TagX { xTagInfo = v } else if v.ChartTagId == req.TagY { yTagInfo = v } } } if xTagInfo == nil { errMsg = "找不到对应的X轴标签" err = errors.New(errMsg) return } if yTagInfo == nil { errMsg = "找不到对应的Y轴标签" err = errors.New(errMsg) return } _, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList) if tmpErr != nil { err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error()) return } if len(edbInfoIdList) <= 0 { errMsg = "品种未配置指标" err = errors.New(errMsg) isSendEmail = false return } edbInfoIdArr = edbInfoIdList mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList) if tmpErr != nil { errMsg = "获取指标信息失败" err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error()) return } if len(mappingList) <= 0 { errMsg = "关联指标为空" err = errors.New(errMsg) isSendEmail = false return } } //判断图表是否存在 //var condition string //var pars []interface{} //condition += " AND chart_info_id <> ? " //pars = append(pars, req.ChartInfoId) //condition += " AND chart_name=? AND source = ? " //pars = append(pars, req.ChartName, chartItem.Source) //count, err := data_manage.GetChartInfoCountByCondition(condition, pars) //if err != nil { // errMsg = "判断图表名称是否存在失败" // err = errors.New("判断图表名称是否存在失败,Err:" + err.Error()) // return //} //if count > 0 { // errMsg = "图表已存在,请重新填写" // err = errors.New(errMsg) // isSendEmail = false // return //} switch lang { case utils.EnLangVersion: chartItem.ChartNameEn = req.ChartName default: chartItem.ChartName = req.ChartName } chartItem.ExtraConfig = string(extraConfigByte) chartItem.ModifyTime = time.Now() chartItem.LeftMin = req.LeftMin chartItem.LeftMax = req.LeftMax chartItem.XMin = req.XMin chartItem.XMax = req.XMax chartUpdateCols := []string{"ChartName", "ChartNameEn", "ExtraConfig", "ModifyTime", "LeftMin", "LeftMax", "XMin", "XMax"} // 跨品种分析配置 chartInfoCrossVariety, err := cross_varietyModel.GetChartInfoCrossVarietyByChartInfoId(chartItem.ChartInfoId) if err != nil { return } chartInfoCrossVariety.ChartXTagId = req.TagX chartInfoCrossVariety.ChartYTagId = req.TagY chartInfoCrossVariety.CalculateValue = req.CalculateValue chartInfoCrossVariety.CalculateUnit = req.CalculateUnit chartInfoCrossVariety.ModifyTime = time.Now() chartInfoCrossVarietyUpdateCols := []string{"ChartXTagId", "ChartYTagId", "CalculateValue", "CalculateUnit", "ModifyTime"} // 图表品种 chartVarietyMappingList := make([]*cross_varietyModel.ChartVarietyMapping, 0) for _, varietyId := range req.VarietyList { chartVarietyMappingList = append(chartVarietyMappingList, &cross_varietyModel.ChartVarietyMapping{ Id: 0, ChartInfoId: 0, ChartVarietyId: varietyId, ModifyTime: time.Now(), CreateTime: time.Now(), }) } err = cross_varietyModel.EditChart(chartItem, chartVarietyMappingList, chartInfoCrossVariety, chartUpdateCols, chartInfoCrossVarietyUpdateCols) if err != nil { errMsg = "保存失败" err = errors.New("保存失败,Err:" + err.Error()) return } resp := new(data_manage.AddChartInfoResp) resp.ChartInfoId = chartItem.ChartInfoId resp.UniqueCode = chartItem.UniqueCode //resp.ChartType = req.ChartType // 添加指标引用记录 _ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartItem) //添加es数据 go data.EsAddOrEditChartInfo(chartItem.ChartInfoId) //修改my eta es数据 go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId) return } // ModifyChartEdbMapping // @Description: 修改图表的关系表 // @author: Roc // @datetime 2023-12-11 17:32:31 // @param tagId int func ModifyChartEdbMapping(tagId int) { errMsgList := make([]string, 0) var err error defer func() { if err != nil { errMsgList = append(errMsgList, err.Error()) } if len(errMsgList) > 0 { utils.FileLog.Error("修改跨品种分析的图表关联指标失败:\n" + strings.Join(errMsgList, "\n")) } }() // 找出标签关联的图表 list, err := cross_varietyModel.GeChartInfoCrossVarietyListByTagId(tagId) if err != nil { return } chartInfoIdList := make([]int, 0) tagIdList := make([]int, 0) tagIdMap := make(map[int]int, 0) for _, v := range list { chartInfoIdList = append(chartInfoIdList, v.ChartInfoId) if _, ok := tagIdMap[v.ChartXTagId]; !ok { tagIdList = append(tagIdList, v.ChartXTagId) tagIdMap[v.ChartXTagId] = 1 } if _, ok := tagIdMap[v.ChartYTagId]; !ok { tagIdList = append(tagIdList, v.ChartYTagId) tagIdMap[v.ChartYTagId] = 1 } } // 找出所有标签关联的品种和对应的指标 chartTagVarietyList, err := cross_varietyModel.GetChartTagVarietyListByTagIdList(tagIdList) if err != nil { return } // 所有指标id allEdbInfoIdList := make([]int, 0) // 标签关联品种的指标列表 tagVarietyEdbMap := make(map[string][]int) for _, v := range chartTagVarietyList { if v.EdbInfoId <= 0 { continue } key := fmt.Sprint(v.ChartTagId, "_", v.ChartVarietyId) tagVarietyEdbList, ok := tagVarietyEdbMap[key] if !ok { tagVarietyEdbList = make([]int, 0) } tagVarietyEdbMap[key] = append(tagVarietyEdbList, v.EdbInfoId) allEdbInfoIdList = append(allEdbInfoIdList, v.EdbInfoId) } edbInfoMap := make(map[int]*data_manage.EdbInfo) // 获取指标列表 if len(allEdbInfoIdList) > 0 { allEdbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(allEdbInfoIdList) if tmpErr != nil { err = tmpErr return } for _, v := range allEdbInfoList { edbInfoMap[v.EdbInfoId] = v } } // 图表关联的品种列表 chartVarietyMappingList, err := cross_varietyModel.GetChartVarietyMappingListByChartInfoIdList(chartInfoIdList) if err != nil { return } // 图表关联的品种map chartVarietyMappingListMap := make(map[int][]int) for _, v := range chartVarietyMappingList { if v.ChartInfoId <= 0 { continue } varietyMappingList, ok := chartVarietyMappingListMap[v.ChartInfoId] if !ok { varietyMappingList = make([]int, 0) } chartVarietyMappingListMap[v.ChartInfoId] = append(varietyMappingList, v.ChartVarietyId) } // 处理图表 for _, v := range list { // 获取关联的指标id edbInfoList := make([]*data_manage.EdbInfo, 0) edbInfoIdMap := make(map[int]int, 0) // 找出图表关联的品种 varietyIdList, ok := chartVarietyMappingListMap[v.ChartInfoId] if ok { // 获取品种与标签的id for _, varietyId := range varietyIdList { // 先处理x轴 key := fmt.Sprint(v.ChartXTagId, "_", varietyId) if tmpEdbInfoIdList, ok2 := tagVarietyEdbMap[key]; ok2 { for _, edbInfoId := range tmpEdbInfoIdList { if _, ok3 := edbInfoIdMap[edbInfoId]; !ok3 { if edbInfo, ok4 := edbInfoMap[edbInfoId]; ok4 { edbInfoList = append(edbInfoList, edbInfo) } edbInfoIdMap[edbInfoId] = edbInfoId } } } // 处理y轴 key = fmt.Sprint(v.ChartYTagId, "_", varietyId) if tmpEdbInfoIdList, ok2 := tagVarietyEdbMap[key]; ok2 { for _, edbInfoId := range tmpEdbInfoIdList { if _, ok3 := edbInfoIdMap[edbInfoId]; !ok3 { if edbInfo, ok4 := edbInfoMap[edbInfoId]; ok4 { edbInfoList = append(edbInfoList, edbInfo) } edbInfoIdMap[edbInfoId] = edbInfoId } } } } } tmpErr := data_manage.ModifyChartEdbMapping(v.ChartInfoId, edbInfoList) if tmpErr != nil { errMsgList = append(errMsgList, fmt.Sprint("修改", v.ChartInfoId, "失败,err:", tmpErr)) } } return }