package area_graph import ( "errors" "eta/eta_api/models/data_manage" "eta/eta_api/utils" "github.com/shopspring/decimal" "math" "sort" "time" ) type InterpolateStrategy struct{} // Deal 空值填充:插值法填充 func (i *InterpolateStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) { for _, v := range edbDataList { if v.EdbInfoId != tmpConfig.StandardEdbInfoId { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 存放补充数据 var replenishDataList []*data_manage.EdbDataList // 处理从 startDate 到第一个数据的日期补充 if len(dataList) > 0 { firstData := dataList[0] // 将 startDate 到第一个数据日期之间的自然日填充补充数据,值为 0 startDataTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local) firstDataTime, _ := time.ParseInLocation(utils.FormatDate, firstData.DataTime, time.Local) // 计算两个日期之间的天数差 if !startDataTime.Equal(firstDataTime) { for startDataTime.Before(firstDataTime) { // 补充数据 nextDay := startDataTime.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: startDataTime.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 startDataTime 到下一个日期 startDataTime = startDataTime.AddDate(0, 0, 1) } } } // 插值法补充数据 var startEdbInfoData *data_manage.EdbDataList for index := 0; index < len(dataList)-1; index++ { // 获取当前数据和下一个数据 beforeIndexData := dataList[index] afterIndexData := dataList[index+1] if startEdbInfoData == nil { startEdbInfoData = beforeIndexData continue } // 获取两条数据之间相差的天数 startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local) currDataTime, _ := time.ParseInLocation(utils.FormatDate, afterIndexData.DataTime, time.Local) betweenHour := int(currDataTime.Sub(startDataTime).Hours()) betweenDay := betweenHour / 24 // 如果相差一天,那么过滤 if betweenDay <= 1 { startEdbInfoData = afterIndexData continue } // 生成线性方程式 var a, b float64 { coordinateData := make([]utils.Coordinate, 0) tmpCoordinate1 := utils.Coordinate{ X: 1, Y: startEdbInfoData.Value, } coordinateData = append(coordinateData, tmpCoordinate1) tmpCoordinate2 := utils.Coordinate{ X: float64(betweenDay) + 1, Y: afterIndexData.Value, } coordinateData = append(coordinateData, tmpCoordinate2) a, b = utils.GetLinearResult(coordinateData) if math.IsNaN(a) || math.IsNaN(b) { err = errors.New("线性方程公式生成失败") return } } // 插值补充数据 for i := 1; i < betweenDay; i++ { tmpDataTime := startDataTime.AddDate(0, 0, i) aDecimal := decimal.NewFromFloat(a) xDecimal := decimal.NewFromInt(int64(i) + 1) bDecimal := decimal.NewFromFloat(b) val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64() nextDay := tmpDataTime.Format(utils.FormatDate) replenishIndexData := data_manage.EdbDataList{ EdbDataId: afterIndexData.EdbDataId, DataTime: nextDay, DataTimestamp: tmpDataTime.UnixMilli(), Value: val, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) } startEdbInfoData = afterIndexData } // 处理从最后一个数据到 endDate 的日期补充 if len(dataList) > 0 { lastData := dataList[len(dataList)-1] // 将最后一个数据日期到 endDate 之间的自然日填充补充数据,值为 0 lastDataTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) endDataTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local) // 如果 lastDataTime 不等于 endDate,进行补充 if !lastDataTime.Equal(endDataTime) { // 补充数据直到 endDate for lastDataTime.Before(endDataTime) { // 补充数据 addDate := lastDataTime.AddDate(0, 0, 1) nextDay := addDate.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: addDate.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 lastDataTime 到下一个日期 lastDataTime = addDate } } } dataList = append(dataList, replenishDataList...) // 根据基准指标筛选出符合数据 var resultDataList []*data_manage.EdbDataList for _, dataObject := range dataList { if _, ok := standardIndexMap[dataObject.DataTime]; ok { // 存在才保留 resultDataList = append(resultDataList, dataObject) } } // 排序 sort.Slice(resultDataList, func(i, j int) bool { return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp }) v.DataList = resultDataList } } } return nil } type FillWithPreviousStrategy struct{} // Deal 空值填充:前值填充 func (f *FillWithPreviousStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) { // 按自然日补充,再根据基准指标取对应数据 for _, v := range edbDataList { if v.EdbInfoId != tmpConfig.StandardEdbInfoId { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 存放补充数据 var replenishDataList []*data_manage.EdbDataList // 处理从 startDate 到第一个数据的日期补充 if len(dataList) > 0 { firstData := dataList[0] // 将 startDate 到第一个数据日期之间的自然日填充补充数据,值为 0 startDataTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local) firstDataTime, _ := time.ParseInLocation(utils.FormatDate, firstData.DataTime, time.Local) // 计算两个日期之间的天数差 if !startDataTime.Equal(firstDataTime) { for startDataTime.Before(firstDataTime) { // 补充数据 nextDay := startDataTime.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: startDataTime.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 startDataTime 到下一个日期 startDataTime = startDataTime.AddDate(0, 0, 1) } } } // 处理指标中空值数据 for index := 0; index < len(dataList)-1; index++ { // 获取当前数据和下一个数据 beforeIndexData := dataList[index] afterIndexData := dataList[index+1] for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) { // 创建补充数据 nextDay := utils.GetNextDay(beforeIndexData.DataTime) toTime := utils.StringToTime(nextDay) replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: toTime.UnixMilli(), Value: beforeIndexData.Value, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 beforeIndexData 为新创建的补充数据 beforeIndexData = &replenishIndexData } } // 处理从最后一个数据到 endDate 的日期补充 if len(dataList) > 0 { lastData := dataList[len(dataList)-1] // 将最后一个数据日期到 endDate 之间的自然日填充补充数据,值为 0 lastDataTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) endDataTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local) // 如果 lastDataTime 不等于 endDate,进行补充 if !lastDataTime.Equal(endDataTime) { // 补充数据直到 endDate for lastDataTime.Before(endDataTime) { // 补充数据 addDate := lastDataTime.AddDate(0, 0, 1) nextDay := addDate.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: addDate.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 lastDataTime 到下一个日期 lastDataTime = addDate } } } dataList = append(dataList, replenishDataList...) // 根据基准指标筛选出符合数据 var resultDataList []*data_manage.EdbDataList for _, dataObject := range dataList { _, ok = standardIndexMap[dataObject.DataTime] if ok { // 存在才保留 resultDataList = append(resultDataList, dataObject) } } // 排序 sort.Slice(resultDataList, func(i, j int) bool { return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp }) v.DataList = resultDataList } } } return nil } type FillWithNextStrategy struct{} // Deal 空值填充:后值填充 func (f *FillWithNextStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) { // 按自然日补充,再根据基准指标取对应数据 for _, v := range edbDataList { if v.EdbInfoId != tmpConfig.StandardEdbInfoId { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 存放补充数据 var replenishDataList []*data_manage.EdbDataList // 处理从 startDate 到第一个数据的日期补充 if len(dataList) > 0 { firstData := dataList[0] // 将 startDate 到第一个数据日期之间的自然日填充补充数据,值为 0 startDataTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local) firstDataTime, _ := time.ParseInLocation(utils.FormatDate, firstData.DataTime, time.Local) // 计算两个日期之间的天数差 if !startDataTime.Equal(firstDataTime) { for !startDataTime.After(firstDataTime) { // 补充数据 nextDay := startDataTime.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: startDataTime.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 startDataTime 到下一个日期 startDataTime = startDataTime.AddDate(0, 0, 1) } } } // 处理从最后一个数据到 endDate 的日期补充 if len(dataList) > 0 { lastData := dataList[len(dataList)-1] // 将最后一个数据日期到 endDate 之间的自然日填充补充数据,值为 0 lastDataTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) endDataTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local) // 如果 lastDataTime 不等于 endDate,进行补充 if !lastDataTime.Equal(endDataTime) { // 补充数据直到 endDate for lastDataTime.Before(endDataTime) { // 补充数据 addDate := lastDataTime.AddDate(0, 0, 1) nextDay := addDate.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: addDate.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 lastDataTime 到下一个日期 lastDataTime = addDate } } } // 将切片数据倒序 reverseSlice(dataList) // 处理指标中空值数据 for index := 0; index < len(dataList)-1; index++ { // 获取当前数据和下一个数据 beforeIndexData := dataList[index] afterIndexData := dataList[index+1] for utils.IsMoreThanOneDay(afterIndexData.DataTime, beforeIndexData.DataTime) { // 创建补充数据 nextDay := utils.GetNextDay(afterIndexData.DataTime) toTime := utils.StringToTime(nextDay) replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: toTime.UnixMilli(), Value: afterIndexData.Value, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 beforeIndexData 为新创建的补充数据 afterIndexData = &replenishIndexData } } dataList = append(dataList, replenishDataList...) // 根据基准指标筛选出符合数据 var resultDataList []*data_manage.EdbDataList for _, dataObject := range dataList { _, ok = standardIndexMap[dataObject.DataTime] if ok { // 存在才保留 resultDataList = append(resultDataList, dataObject) } } // 排序 sort.Slice(resultDataList, func(i, j int) bool { return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp }) v.DataList = resultDataList } } } return nil } type SetToZeroStrategy struct{} // Deal 空值填充:设为0 func (s *SetToZeroStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) { // 按自然日补充,再根据基准指标取对应数据 for _, v := range edbDataList { if v.EdbInfoId != tmpConfig.StandardEdbInfoId { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 存放补充数据 var replenishDataList []*data_manage.EdbDataList // 处理从 startDate 到第一个数据的日期补充 if len(dataList) > 0 { firstData := dataList[0] // 将 startDate 到第一个数据日期之间的自然日填充补充数据,值为 0 startDataTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local) firstDataTime, _ := time.ParseInLocation(utils.FormatDate, firstData.DataTime, time.Local) // 计算两个日期之间的天数差 if !startDataTime.Equal(firstDataTime) { for startDataTime.Before(firstDataTime) { // 补充数据 nextDay := startDataTime.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: startDataTime.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 startDataTime 到下一个日期 startDataTime = startDataTime.AddDate(0, 0, 1) } } } // 处理指标中空值数据 for index := 0; index < len(dataList)-1; index++ { // 获取当前数据和下一个数据 beforeIndexData := dataList[index] afterIndexData := dataList[index+1] for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) { // 创建补充数据 nextDay := utils.GetNextDay(beforeIndexData.DataTime) toTime := utils.StringToTime(nextDay) replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: toTime.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 beforeIndexData 为新创建的补充数据 beforeIndexData = &replenishIndexData } } // 处理从最后一个数据到 endDate 的日期补充 if len(dataList) > 0 { lastData := dataList[len(dataList)-1] // 将最后一个数据日期到 endDate 之间的自然日填充补充数据,值为 0 lastDataTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) endDataTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local) // 如果 lastDataTime 不等于 endDate,进行补充 if !lastDataTime.Equal(endDataTime) { // 补充数据直到 endDate for lastDataTime.Before(endDataTime) { // 补充数据 addDate := lastDataTime.AddDate(0, 0, 1) nextDay := addDate.Format(utils.FormatDate) // 生成补充数据,值为 0 replenishIndexData := data_manage.EdbDataList{ EdbInfoId: v.EdbInfoId, DataTime: nextDay, DataTimestamp: addDate.UnixMilli(), Value: 0, } // 将补充数据加入补充数据列表 replenishDataList = append(replenishDataList, &replenishIndexData) // 更新 lastDataTime 到下一个日期 lastDataTime = addDate } } } dataList = append(dataList, replenishDataList...) // 根据基准指标筛选出符合数据 var resultDataList []*data_manage.EdbDataList for _, dataObject := range dataList { _, ok = standardIndexMap[dataObject.DataTime] if ok { // 存在才保留 resultDataList = append(resultDataList, dataObject) } } // 排序 sort.Slice(resultDataList, func(i, j int) bool { return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp }) v.DataList = resultDataList } } } return nil } type DeleteDateStrategy struct{} // Deal 删除日期 func (d *DeleteDateStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) error { // 取所有指标的时间交集 // 创建一个 map 来保存每个时间点的出现次数 timeMap := make(map[string]int) for _, v := range edbDataList { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 遍历所有的 dataList,为每个 DataTime 增加一个计数 for _, dataObject := range dataList { timeMap[dataObject.DataTime]++ } } } for _, v := range edbDataList { if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok { // 遍历所有的 dataList,保留所有时间点在所有指标中都存在的数据 var resultDataList []*data_manage.EdbDataList for _, dataObject := range dataList { if timeMap[dataObject.DataTime] == len(edbDataList) { // 如果该时间点在所有指标中都存在,加入到结果列表 resultDataList = append(resultDataList, dataObject) } } // 将符合条件的数据重新赋值回 v.DataList v.DataList = resultDataList } } return nil } // 将列表颠倒 func reverseSlice(dataList []*data_manage.EdbDataList) { // 使用双指针法,前后两个指针向中间逼近 for i, j := 0, len(dataList)-1; i < j; i, j = i+1, j-1 { // 交换位置 dataList[i], dataList[j] = dataList[j], dataList[i] } }