processor_business_logic.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. package area_graph
  2. import (
  3. "errors"
  4. "eta/eta_api/models/data_manage"
  5. "eta/eta_api/utils"
  6. "github.com/shopspring/decimal"
  7. "math"
  8. "sort"
  9. "time"
  10. )
  11. type InterpolateStrategy struct{}
  12. // Deal 空值填充:插值法填充
  13. func (i *InterpolateStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) {
  14. for _, v := range edbDataList {
  15. if v.EdbInfoId != tmpConfig.StandardEdbInfoId {
  16. if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok {
  17. // 插值法补充数据
  18. var startEdbInfoData *data_manage.EdbDataList
  19. for index := 0; index < len(dataList)-1; index++ {
  20. // 获取当前数据和下一个数据
  21. beforeIndexData := dataList[index]
  22. afterIndexData := dataList[index+1]
  23. if startEdbInfoData == nil {
  24. startEdbInfoData = beforeIndexData
  25. continue
  26. }
  27. // 获取两条数据之间相差的天数
  28. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  29. currDataTime, _ := time.ParseInLocation(utils.FormatDate, afterIndexData.DataTime, time.Local)
  30. betweenHour := int(currDataTime.Sub(startDataTime).Hours())
  31. betweenDay := betweenHour / 24
  32. // 如果相差一天,那么过滤
  33. if betweenDay <= 1 {
  34. startEdbInfoData = afterIndexData
  35. continue
  36. }
  37. // 生成线性方程式
  38. var a, b float64
  39. {
  40. coordinateData := make([]utils.Coordinate, 0)
  41. tmpCoordinate1 := utils.Coordinate{
  42. X: 1,
  43. Y: startEdbInfoData.Value,
  44. }
  45. coordinateData = append(coordinateData, tmpCoordinate1)
  46. tmpCoordinate2 := utils.Coordinate{
  47. X: float64(betweenDay) + 1,
  48. Y: afterIndexData.Value,
  49. }
  50. coordinateData = append(coordinateData, tmpCoordinate2)
  51. a, b = utils.GetLinearResult(coordinateData)
  52. if math.IsNaN(a) || math.IsNaN(b) {
  53. err = errors.New("线性方程公式生成失败")
  54. return
  55. }
  56. }
  57. // 插值补充数据
  58. for i := 1; i < betweenDay; i++ {
  59. tmpDataTime := startDataTime.AddDate(0, 0, i)
  60. aDecimal := decimal.NewFromFloat(a)
  61. xDecimal := decimal.NewFromInt(int64(i) + 1)
  62. bDecimal := decimal.NewFromFloat(b)
  63. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  64. nextDay := tmpDataTime.Format(utils.FormatDate)
  65. replenishIndexData := data_manage.EdbDataList{
  66. EdbDataId: afterIndexData.EdbDataId,
  67. DataTime: nextDay,
  68. DataTimestamp: tmpDataTime.UnixMilli(),
  69. Value: val,
  70. }
  71. // 将补充数据加入补充数据列表
  72. dataList = append(dataList[:index+1], append([]*data_manage.EdbDataList{&replenishIndexData}, dataList[index+1:]...)...)
  73. }
  74. startEdbInfoData = afterIndexData
  75. }
  76. // 根据基准指标筛选出符合数据
  77. var resultDataList []*data_manage.EdbDataList
  78. for _, dataObject := range dataList {
  79. if _, ok := standardIndexMap[dataObject.DataTime]; ok {
  80. // 存在才保留
  81. resultDataList = append(resultDataList, dataObject)
  82. }
  83. }
  84. // 排序
  85. sort.Slice(resultDataList, func(i, j int) bool {
  86. return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp
  87. })
  88. v.DataList = resultDataList
  89. }
  90. }
  91. }
  92. return nil
  93. }
  94. type FillWithPreviousStrategy struct{}
  95. // Deal 空值填充:前值填充
  96. func (f *FillWithPreviousStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) {
  97. // 按自然日补充,再根据基准指标取对应数据
  98. for _, v := range edbDataList {
  99. if v.EdbInfoId != tmpConfig.StandardEdbInfoId {
  100. if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok {
  101. // 存放补充数据
  102. var replenishDataList []*data_manage.EdbDataList
  103. // 处理从 startDate 到第一个数据的日期补充
  104. if len(dataList) > 0 {
  105. firstData := dataList[0]
  106. // 将 startDate 到第一个数据日期之间的自然日填充补充数据,值为 0
  107. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
  108. firstDataTime, _ := time.ParseInLocation(utils.FormatDate, firstData.DataTime, time.Local)
  109. // 计算两个日期之间的天数差
  110. for startDataTime.Before(firstDataTime) {
  111. // 补充数据
  112. nextDay := startDataTime.Format(utils.FormatDate)
  113. // 生成补充数据,值为 0
  114. replenishIndexData := data_manage.EdbDataList{
  115. EdbInfoId: v.EdbInfoId,
  116. DataTime: nextDay,
  117. DataTimestamp: startDataTime.UnixMilli(),
  118. Value: 0,
  119. }
  120. // 将补充数据加入补充数据列表
  121. replenishDataList = append(replenishDataList, &replenishIndexData)
  122. // 更新 startDataTime 到下一个日期
  123. startDataTime = startDataTime.AddDate(0, 0, 1)
  124. }
  125. }
  126. // 处理指标中空值数据
  127. for index := 0; index < len(dataList)-1; index++ {
  128. // 获取当前数据和下一个数据
  129. beforeIndexData := dataList[index]
  130. afterIndexData := dataList[index+1]
  131. for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  132. // 创建补充数据
  133. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  134. toTime := utils.StringToTime(nextDay)
  135. replenishIndexData := data_manage.EdbDataList{
  136. EdbInfoId: v.EdbInfoId,
  137. DataTime: nextDay,
  138. DataTimestamp: toTime.UnixMilli(),
  139. Value: beforeIndexData.Value,
  140. }
  141. // 将补充数据加入补充数据列表
  142. replenishDataList = append(replenishDataList, &replenishIndexData)
  143. //dataList = append(dataList[:index+1], append([]*data_manage.EdbDataList{&replenishIndexData}, dataList[index+1:]...)...)
  144. // 更新 beforeIndexData 为新创建的补充数据
  145. beforeIndexData = &replenishIndexData
  146. }
  147. }
  148. // 处理从最后一个数据到 endDate 的日期补充
  149. if len(dataList) > 0 {
  150. lastData := dataList[len(dataList)-1]
  151. // 将最后一个数据日期到 endDate 之间的自然日填充补充数据,值为 0
  152. lastDataTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local)
  153. endDataTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
  154. // 如果 lastDataTime 不等于 endDate,进行补充
  155. if !lastDataTime.Equal(endDataTime) {
  156. // 补充数据直到 endDate
  157. for !lastDataTime.After(endDataTime) {
  158. // 补充数据
  159. nextDay := lastDataTime.Format(utils.FormatDate)
  160. // 生成补充数据,值为 0
  161. replenishIndexData := data_manage.EdbDataList{
  162. EdbInfoId: v.EdbInfoId,
  163. DataTime: nextDay,
  164. DataTimestamp: lastDataTime.UnixMilli(),
  165. Value: 0,
  166. }
  167. // 将补充数据加入补充数据列表
  168. replenishDataList = append(replenishDataList, &replenishIndexData)
  169. // 更新 lastDataTime 到下一个日期
  170. lastDataTime = lastDataTime.AddDate(0, 0, 1)
  171. }
  172. }
  173. }
  174. dataList = append(dataList, replenishDataList...)
  175. // 根据基准指标筛选出符合数据
  176. var resultDataList []*data_manage.EdbDataList
  177. for _, dataObject := range dataList {
  178. _, ok = standardIndexMap[dataObject.DataTime]
  179. if ok {
  180. // 存在才保留
  181. resultDataList = append(resultDataList, dataObject)
  182. }
  183. }
  184. // 排序
  185. sort.Slice(resultDataList, func(i, j int) bool {
  186. return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp
  187. })
  188. v.DataList = resultDataList
  189. }
  190. }
  191. }
  192. return nil
  193. }
  194. type FillWithNextStrategy struct{}
  195. // Deal 空值填充:后值填充
  196. func (f *FillWithNextStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) {
  197. // 按自然日补充,再根据基准指标取对应数据
  198. for _, v := range edbDataList {
  199. if v.EdbInfoId != tmpConfig.StandardEdbInfoId {
  200. if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok {
  201. // 将切片数据倒序
  202. reverseSlice(dataList)
  203. for index := 0; index < len(dataList)-1; index++ {
  204. // 获取当前数据和下一个数据
  205. beforeIndexData := dataList[index]
  206. afterIndexData := dataList[index+1]
  207. for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  208. // 创建补充数据
  209. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  210. toTime := utils.StringToTime(nextDay)
  211. replenishIndexData := data_manage.EdbDataList{
  212. EdbInfoId: v.EdbInfoId,
  213. DataTime: nextDay,
  214. DataTimestamp: toTime.UnixMilli(),
  215. Value: beforeIndexData.Value,
  216. }
  217. // 将补充数据加入补充数据列表
  218. dataList = append(dataList[:index+1], append([]*data_manage.EdbDataList{&replenishIndexData}, dataList[index+1:]...)...)
  219. // 更新 beforeIndexData 为新创建的补充数据
  220. beforeIndexData = &replenishIndexData
  221. }
  222. }
  223. // 根据基准指标筛选出符合数据
  224. var resultDataList []*data_manage.EdbDataList
  225. for _, dataObject := range dataList {
  226. _, ok = standardIndexMap[dataObject.DataTime]
  227. if ok {
  228. // 存在才保留
  229. resultDataList = append(resultDataList, dataObject)
  230. }
  231. }
  232. // 排序
  233. sort.Slice(resultDataList, func(i, j int) bool {
  234. return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp
  235. })
  236. v.DataList = resultDataList
  237. }
  238. }
  239. }
  240. return nil
  241. }
  242. type SetToZeroStrategy struct{}
  243. // Deal 空值填充:设为0
  244. func (s *SetToZeroStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) (err error) {
  245. // 按自然日补充,再根据基准指标取对应数据
  246. for _, v := range edbDataList {
  247. if v.EdbInfoId != tmpConfig.StandardEdbInfoId {
  248. if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok {
  249. for index := 0; index < len(dataList)-1; index++ {
  250. // 获取当前数据和下一个数据
  251. beforeIndexData := dataList[index]
  252. afterIndexData := dataList[index+1]
  253. for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  254. // 创建补充数据
  255. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  256. toTime := utils.StringToTime(nextDay)
  257. replenishIndexData := data_manage.EdbDataList{
  258. EdbInfoId: v.EdbInfoId,
  259. DataTime: nextDay,
  260. DataTimestamp: toTime.UnixMilli(),
  261. Value: 0,
  262. }
  263. // 将补充数据加入补充数据列表
  264. dataList = append(dataList[:index+1], append([]*data_manage.EdbDataList{&replenishIndexData}, dataList[index+1:]...)...)
  265. // 更新 beforeIndexData 为新创建的补充数据
  266. beforeIndexData = &replenishIndexData
  267. }
  268. }
  269. // 根据基准指标筛选出符合数据
  270. var resultDataList []*data_manage.EdbDataList
  271. for _, dataObject := range dataList {
  272. _, ok = standardIndexMap[dataObject.DataTime]
  273. if ok {
  274. // 存在才保留
  275. resultDataList = append(resultDataList, dataObject)
  276. }
  277. }
  278. // 排序
  279. sort.Slice(resultDataList, func(i, j int) bool {
  280. return resultDataList[i].DataTimestamp < resultDataList[j].DataTimestamp
  281. })
  282. v.DataList = resultDataList
  283. }
  284. }
  285. }
  286. return nil
  287. }
  288. type DeleteDateStrategy struct{}
  289. // Deal 删除日期
  290. func (d *DeleteDateStrategy) Deal(tmpConfig data_manage.AreaExtraConf, edbDataList []*data_manage.ChartEdbInfoMapping, standardIndexMap map[string]*data_manage.EdbDataList, startDate string, endDate string) error {
  291. // 取所有指标的时间交集
  292. for _, v := range edbDataList {
  293. if dataList, ok := v.DataList.([]*data_manage.EdbDataList); ok {
  294. // 创建一个 map 来保存每个时间点的出现次数
  295. timeMap := make(map[string]int)
  296. // 遍历所有的 dataList,为每个 DataTime 增加一个计数
  297. for _, dataObject := range dataList {
  298. timeMap[dataObject.DataTime]++
  299. }
  300. // 遍历所有的 dataList,保留所有时间点在所有指标中都存在的数据
  301. var resultDataList []*data_manage.EdbDataList
  302. for _, dataObject := range dataList {
  303. if timeMap[dataObject.DataTime] == len(edbDataList) {
  304. // 如果该时间点在所有指标中都存在,加入到结果列表
  305. resultDataList = append(resultDataList, dataObject)
  306. }
  307. }
  308. // 将符合条件的数据重新赋值回 v.DataList
  309. v.DataList = resultDataList
  310. }
  311. }
  312. return nil
  313. }
  314. // 将列表颠倒
  315. func reverseSlice(dataList []*data_manage.EdbDataList) {
  316. // 使用双指针法,前后两个指针向中间逼近
  317. for i, j := 0, len(dataList)-1; i < j; i, j = i+1, j-1 {
  318. // 交换位置
  319. dataList[i], dataList[j] = dataList[j], dataList[i]
  320. }
  321. }