residual_analysis_service.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package residual_analysis_service
  2. import (
  3. "eta/eta_api/models/data_manage"
  4. "eta/eta_api/models/residual_analysis_model"
  5. "eta/eta_api/utils"
  6. "fmt"
  7. "time"
  8. )
  9. func ResidualAnalysisPreview(req residual_analysis_model.ResidualAnalysisReq) (residual_analysis_model.ResidualAnalysisResp, error) {
  10. if req.DateType < 0 {
  11. return residual_analysis_model.ResidualAnalysisResp{}, fmt.Errorf("时间类型错误", nil)
  12. }
  13. mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoIdList([]int{req.EdbInfoIdA, req.EdbInfoIdB})
  14. if err != nil {
  15. return residual_analysis_model.ResidualAnalysisResp{}, fmt.Errorf("获取图表,指标信息失败,Err:%s", err.Error())
  16. }
  17. var edbInfoMappingA, edbInfoMappingB *data_manage.ChartEdbInfoMapping
  18. for _, v := range mappingList {
  19. if v.EdbInfoId == req.EdbInfoIdA {
  20. edbInfoMappingA = v
  21. }
  22. if v.EdbInfoId == req.EdbInfoIdB {
  23. edbInfoMappingB = v
  24. }
  25. }
  26. if edbInfoMappingA == nil {
  27. return residual_analysis_model.ResidualAnalysisResp{}, fmt.Errorf("指标A不存在", nil)
  28. }
  29. if edbInfoMappingB == nil {
  30. return residual_analysis_model.ResidualAnalysisResp{}, fmt.Errorf("指标B不存在", nil)
  31. }
  32. // 时间处理
  33. var startDate, endDate string
  34. switch req.DateType {
  35. case 0:
  36. startDate = req.StartDate
  37. endDate = req.EndDate
  38. case 1:
  39. startDate = req.StartDate
  40. endDate = ""
  41. default:
  42. startDate = utils.GetPreYear(req.DateType)
  43. endDate = ""
  44. }
  45. resp := residual_analysis_model.ResidualAnalysisResp{}
  46. // 图表基础信息
  47. baseChartInfo := new(residual_analysis_model.ResidualAnalysisChartInfo)
  48. baseChartInfo.Calendar = `公历`
  49. baseChartInfo.Source = utils.CHART_SOURCE_DEFAULT
  50. baseChartInfo.DateType = req.DateType
  51. baseChartInfo.StartDate = startDate
  52. baseChartInfo.EndDate = endDate
  53. baseChartInfo.ChartType = utils.CHART_TYPE_CURVE
  54. // 原始图表信息
  55. var OriginalEdbList []*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
  56. OriginalEdbList, err = fillOriginalChart(req, mappingList, startDate, endDate, edbInfoMappingA, edbInfoMappingB, OriginalEdbList)
  57. if err != nil {
  58. return residual_analysis_model.ResidualAnalysisResp{}, err
  59. }
  60. baseChartInfo.ChartName = edbInfoMappingA.EdbName + "与" + edbInfoMappingB.EdbName
  61. resp.OriginalChartData = residual_analysis_model.ChartResp{
  62. ChartInfo: baseChartInfo,
  63. EdbInfoList: OriginalEdbList,
  64. }
  65. dataAList, ok := edbInfoMappingA.DataList.([]data_manage.EdbDataList)
  66. if !ok {
  67. return residual_analysis_model.ResidualAnalysisResp{}, fmt.Errorf("数据类型转换失败", nil)
  68. }
  69. indexADataMap := map[string]data_manage.EdbDataList{}
  70. for _, indexData := range dataAList {
  71. indexADataMap[indexData.DataTime] = indexData
  72. }
  73. // 映射图表信息
  74. mappingEdbList, err := fillMappingChartInfo(req, edbInfoMappingA, edbInfoMappingB, OriginalEdbList, indexADataMap)
  75. if err != nil {
  76. return residual_analysis_model.ResidualAnalysisResp{}, err
  77. }
  78. baseChartInfo.ChartName = edbInfoMappingA.EdbName + "与" + edbInfoMappingB.EdbName + "映射" + edbInfoMappingA.EdbName
  79. resp.MappingChartData = residual_analysis_model.ChartResp{
  80. ChartInfo: baseChartInfo,
  81. EdbInfoList: mappingEdbList,
  82. }
  83. // 残差图表信息
  84. ResidualEdbList, err := fillResidualChartInfo(edbInfoMappingA, edbInfoMappingB, mappingEdbList)
  85. if err != nil {
  86. return residual_analysis_model.ResidualAnalysisResp{}, err
  87. }
  88. baseChartInfo.ChartName = edbInfoMappingA.EdbName + "与" + edbInfoMappingA.EdbName + "映射残差/" + edbInfoMappingB.EdbName
  89. resp.MappingChartData = residual_analysis_model.ChartResp{
  90. ChartInfo: baseChartInfo,
  91. EdbInfoList: ResidualEdbList,
  92. }
  93. return resp, nil
  94. }
  95. func fillResidualChartInfo(edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, mappingEdbList []*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping) ([]*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {
  96. // 计算公式 映射残差 = 因变量指标 - 映射指标
  97. var edbInfoA, edbInfoB *residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
  98. if mappingEdbList[0].EdbInfoId == edbInfoMappingA.EdbInfoId {
  99. edbInfoA = mappingEdbList[0]
  100. edbInfoB = mappingEdbList[1]
  101. } else {
  102. edbInfoA = mappingEdbList[1]
  103. edbInfoB = mappingEdbList[0]
  104. }
  105. dataAList, ok := edbInfoA.DataList.([]data_manage.EdbDataList)
  106. if !ok {
  107. return nil, fmt.Errorf("数据类型转换失败", nil)
  108. }
  109. edbData := dataAList
  110. dataBList, ok := edbInfoB.DataList.([]data_manage.EdbDataList)
  111. if !ok {
  112. return nil, fmt.Errorf("数据类型转换失败", nil)
  113. }
  114. var indexDataBMap map[string]data_manage.EdbDataList
  115. for _, data := range dataBList {
  116. indexDataBMap[data.DataTime] = data
  117. }
  118. var valueB float64
  119. for _, indexData := range edbData {
  120. if dataB, ok := indexDataBMap[indexData.DataTime]; ok {
  121. valueB = dataB.Value
  122. } else {
  123. valueB = 0
  124. }
  125. indexData.Value = indexData.Value - valueB
  126. }
  127. for _, mapping := range mappingEdbList {
  128. if mapping.EdbInfoId != edbInfoMappingA.EdbInfoId {
  129. mapping.DataList = edbData
  130. mapping.EdbName = edbInfoMappingA.EdbName + "映射残差/" + edbInfoMappingB.EdbName
  131. }
  132. }
  133. return mappingEdbList, nil
  134. }
  135. func fillMappingChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, originalEdbList []*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, indexADataMap map[string]data_manage.EdbDataList) ([]*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {
  136. // 计算公式:Y=aX+b,Y为映射后的指标,X为自变量指标
  137. // 正序:a=(L2-L1)/(R2-R1) b=L2-R2*a
  138. // 逆序:a=(L2-L1)/(R1-R2) b=L2-R1*a
  139. // L2:左轴下限 R2:右轴上限 L1:左轴上限 R1:右轴下限
  140. var a, b float64
  141. if req.IsOrder {
  142. a = (req.LeftIndexMax - req.LeftIndexMin) / (req.RightIndexMax - req.RightIndexMin)
  143. b = req.LeftIndexMax - req.RightIndexMax*a
  144. } else {
  145. a = (req.LeftIndexMax - req.LeftIndexMin) / (req.RightIndexMin - req.RightIndexMax)
  146. b = req.LeftIndexMax - req.RightIndexMin*a
  147. }
  148. dataList, ok := edbInfoMappingB.DataList.([]data_manage.EdbDataList)
  149. if !ok {
  150. return nil, fmt.Errorf("数据类型转换失败", nil)
  151. }
  152. // 领先指标 dataList进行数据处理
  153. if req.IndexType == 2 {
  154. if req.LeadValue < 0 {
  155. return nil, fmt.Errorf("领先值不能小于0", nil)
  156. } else if req.LeadValue > 0 {
  157. for _, indexData := range dataList {
  158. switch req.LeadFrequency {
  159. case "天":
  160. indexData.DataTime = utils.GetNextDayN(indexData.DataTime, req.LeadValue)
  161. case "周":
  162. indexData.DataTime = utils.GetNextDayN(indexData.DataTime, req.LeadValue*7)
  163. case "月":
  164. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), 0, req.LeadValue), utils.YearMonthDay)
  165. case "季":
  166. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), 0, req.LeadValue*3), utils.YearMonthDay)
  167. case "年":
  168. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), req.LeadValue, 0), utils.YearMonthDay)
  169. }
  170. }
  171. }
  172. }
  173. for index, indexData := range dataList {
  174. // 计算映射值
  175. indexData.Value = a*indexData.Value + b
  176. // 从最早时间开始 补充时间为自然日
  177. beforeIndexData := dataList[index]
  178. afterIndexData := dataList[index+1]
  179. if utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  180. replenishIndexData := data_manage.EdbDataList{
  181. DataTime: utils.GetNextDay(beforeIndexData.DataTime),
  182. DataTimestamp: time.Now().UnixMilli(),
  183. Value: beforeIndexData.Value,
  184. }
  185. dataList = append(dataList, replenishIndexData)
  186. }
  187. }
  188. // 根据指标A的时间key,在B的映射指标中筛选出对应的值
  189. var dataBList []data_manage.EdbDataList
  190. for _, indexData := range dataList {
  191. if _, ok := indexADataMap[indexData.DataTime]; ok {
  192. dataBList = append(dataBList, indexData)
  193. }
  194. }
  195. mappingEdbList := originalEdbList
  196. for _, mapping := range mappingEdbList {
  197. if mapping.EdbInfoId == req.EdbInfoIdB {
  198. mapping.EdbInfoId = 0
  199. mapping.EdbCode = ""
  200. mapping.EdbName = edbInfoMappingB.EdbName + "映射" + edbInfoMappingA.EdbName
  201. mapping.DataList = dataList
  202. }
  203. }
  204. return mappingEdbList, nil
  205. }
  206. func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingList []*data_manage.ChartEdbInfoMapping, startDate string, endDate string, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, OriginalEdbList []*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping) ([]*residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {
  207. for _, v := range mappingList {
  208. var edbInfoMapping *residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
  209. edbInfoMapping.EdbInfoType = 1
  210. edbInfoMapping.IsOrder = false
  211. edbInfoMapping.IsAxis = 1
  212. edbInfoMapping.ChartColor = `#00F`
  213. edbInfoMapping.ChartWidth = 3
  214. // 获取图表中的指标数据
  215. dataList, err := data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, startDate, endDate)
  216. if err != nil {
  217. return nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
  218. }
  219. if v.EdbInfoId == req.EdbInfoIdB {
  220. edbInfoMapping.LeadValue = req.LeadValue
  221. edbInfoMapping.LeadUnit = req.LeadFrequency
  222. edbInfoMapping.EdbInfoType = req.IndexType
  223. edbInfoMapping.IsOrder = req.IsOrder
  224. edbInfoMapping.IsAxis = 0
  225. edbInfoMapping.ChartColor = `#F00`
  226. edbInfoMapping.ChartWidth = 1
  227. edbInfoMappingB.DataList = dataList
  228. } else {
  229. edbInfoMappingA.DataList = dataList
  230. }
  231. edbInfoMapping.EdbInfoId = v.EdbInfoId
  232. edbInfoMapping.EdbName = v.EdbName
  233. edbInfoMapping.EdbCode = v.EdbCode
  234. edbInfoMapping.Unit = v.Unit
  235. edbInfoMapping.Frequency = v.Frequency
  236. edbInfoMapping.Source = v.Source
  237. edbInfoMapping.SourceName = v.SourceName
  238. edbInfoMapping.DataList = dataList
  239. OriginalEdbList = append(OriginalEdbList, edbInfoMapping)
  240. }
  241. return OriginalEdbList, nil
  242. }
  243. func ContrastPreview(indexCode string) (residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {
  244. var condition string
  245. var pars []interface{}
  246. if indexCode != "" {
  247. condition += " and edb_code=?"
  248. pars = append(pars, indexCode)
  249. }
  250. edbInfo, err := data_manage.GetEdbInfoByCondition(condition, pars)
  251. if err != nil {
  252. return residual_analysis_model.ResidualAnalysisChartEdbInfoMapping{}, err
  253. }
  254. if edbInfo == nil {
  255. return residual_analysis_model.ResidualAnalysisChartEdbInfoMapping{}, fmt.Errorf("指标不存在")
  256. }
  257. dataList, err := data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, "", "")
  258. var resp residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
  259. resp.EdbInfoId = edbInfo.EdbInfoId
  260. resp.SourceName = edbInfo.SourceName
  261. resp.EdbName = edbInfo.EdbName
  262. resp.Unit = edbInfo.Unit
  263. resp.Frequency = edbInfo.Frequency
  264. resp.DataList = dataList
  265. return resp, nil
  266. }