123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- 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]
- }
- }
|