chart_info.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. package data
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "github.com/shopspring/decimal"
  7. "hongze/hongze_ETA_mobile_api/models/company"
  8. "hongze/hongze_ETA_mobile_api/models/data_manage"
  9. "hongze/hongze_ETA_mobile_api/models/system"
  10. "hongze/hongze_ETA_mobile_api/services/alarm_msg"
  11. "hongze/hongze_ETA_mobile_api/utils"
  12. "math"
  13. "sort"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. type ChartInfoReq struct {
  19. ChartInfoId int `description:"图表id,新增时传0"`
  20. }
  21. // DeleteChartInfoDataRedis 清除图表缓存
  22. func DeleteChartInfoDataRedis(bodyByte []byte) (err error) {
  23. var req ChartInfoReq
  24. err = json.Unmarshal(bodyByte, &req)
  25. if err != nil {
  26. return
  27. }
  28. if req.ChartInfoId > 0 {
  29. err = utils.Rc.Delete(GetChartInfoDataKey(req.ChartInfoId))
  30. }
  31. return
  32. }
  33. // DeleteChartClassifyRedis 清除图表分类缓存
  34. func DeleteChartClassifyRedis(bodyByte []byte) (err error) {
  35. err = utils.Rc.Delete(utils.CACHE_CHART_CLASSIFY)
  36. return
  37. }
  38. // GetChartInfoDataKey 获取图表缓存的key
  39. func GetChartInfoDataKey(chartInfoId int) string {
  40. key := fmt.Sprint(utils.CACHE_CHART_INFO_DATA, chartInfoId)
  41. return key
  42. }
  43. // CheckOpChartPermission 判断图表操作权限
  44. func CheckOpChartPermission(sysUser *system.Admin, createUserId int) (ok bool) {
  45. if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN {
  46. ok = true
  47. }
  48. // 如果图表创建人与当前操作人相同的话,那么就是允许操作
  49. if ok == false && createUserId == sysUser.AdminId {
  50. ok = true
  51. }
  52. // 如果图表权限id 是 1 ,那么允许编辑
  53. if ok == false && sysUser.ChartPermission == 1 {
  54. ok = true
  55. }
  56. return
  57. }
  58. // GetChartEdbData 获取图表的指标数据
  59. func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, extraConfigStr string) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, yDataList []data_manage.YData, dataResp interface{}, err error, errMsg string) {
  60. edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
  61. xEdbIdValue = make([]int, 0)
  62. yDataList = make([]data_manage.YData, 0)
  63. var extraConfig interface{}
  64. switch chartType {
  65. case 7: // 柱形图
  66. var barConfig data_manage.BarChartInfoReq
  67. if extraConfigStr == `` {
  68. errMsg = "柱方图未配置"
  69. err = errors.New(errMsg)
  70. return
  71. }
  72. err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
  73. if err != nil {
  74. errMsg = "柱方图配置异常"
  75. err = errors.New(errMsg)
  76. return
  77. }
  78. extraConfig = barConfig
  79. case 10: // 截面散点图
  80. var tmpExtraConfig data_manage.SectionScatterReq
  81. if extraConfigStr == `` {
  82. errMsg = "截面散点图未配置"
  83. err = errors.New(errMsg)
  84. return
  85. }
  86. err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
  87. if err != nil {
  88. errMsg = "截面散点配置异常"
  89. err = errors.New(errMsg)
  90. return
  91. }
  92. extraConfig = tmpExtraConfig
  93. default:
  94. xEdbIdValue = make([]int, 0)
  95. yDataList = make([]data_manage.YData, 0)
  96. }
  97. // 指标对应的所有数据
  98. edbDataListMap, edbList, err := getEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList)
  99. if err != nil {
  100. return
  101. }
  102. // 特殊图形数据处理
  103. switch chartType {
  104. case 7: // 柱形图
  105. barChartConf := extraConfig.(data_manage.BarChartInfoReq)
  106. xEdbIdValue, yDataList, err = BarChartData(mappingList, edbDataListMap, barChartConf.DateList, barChartConf.Sort)
  107. for _, v := range edbList {
  108. // 指标别名
  109. if barChartConf.EdbInfoIdList != nil && len(barChartConf.EdbInfoIdList) > 0 {
  110. for _, reqEdb := range barChartConf.EdbInfoIdList {
  111. if v.EdbInfoId == reqEdb.EdbInfoId {
  112. v.EdbAliasName = reqEdb.Name
  113. }
  114. }
  115. }
  116. }
  117. case 10: // 截面散点图
  118. sectionScatterConf := extraConfig.(data_manage.SectionScatterReq)
  119. xEdbIdValue, dataResp, err = GetSectionScatterChartData(mappingList, edbDataListMap, sectionScatterConf)
  120. // 这个数据没有必要返回给前端
  121. for _, v := range edbList {
  122. v.DataList = nil
  123. }
  124. }
  125. return
  126. }
  127. // getEdbDataMapList 获取指标最后的基础数据
  128. func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
  129. // 指标对应的所有数据
  130. edbDataListMap = make(map[int][]*data_manage.EdbDataList)
  131. for _, v := range mappingList {
  132. //fmt.Println("v:", v.EdbInfoId)
  133. item := new(data_manage.ChartEdbInfoMapping)
  134. item.EdbInfoId = v.EdbInfoId
  135. item.SourceName = v.SourceName
  136. item.Source = v.Source
  137. item.EdbCode = v.EdbCode
  138. item.EdbName = v.EdbName
  139. item.EdbNameEn = v.EdbNameEn
  140. item.Frequency = v.Frequency
  141. item.EdbType = v.EdbType
  142. item.FrequencyEn = GetFrequencyEn(v.Frequency)
  143. if v.Unit != `无` {
  144. item.Unit = v.Unit
  145. }
  146. item.UnitEn = v.UnitEn
  147. item.StartDate = v.StartDate
  148. item.EndDate = v.EndDate
  149. item.ModifyTime = v.ModifyTime
  150. item.EdbInfoCategoryType = v.EdbInfoCategoryType
  151. item.PredictChartColor = v.PredictChartColor
  152. item.ClassifyId = v.ClassifyId
  153. if chartInfoId <= 0 {
  154. item.IsAxis = 1
  155. item.LeadValue = 0
  156. item.LeadUnit = ""
  157. item.ChartEdbMappingId = 0
  158. item.ChartInfoId = 0
  159. item.IsOrder = false
  160. item.EdbInfoType = 1
  161. item.ChartStyle = ""
  162. item.ChartColor = ""
  163. item.ChartWidth = 0
  164. item.MaxData = v.MaxValue
  165. item.MinData = v.MinValue
  166. } else {
  167. item.IsAxis = v.IsAxis
  168. item.EdbInfoType = v.EdbInfoType
  169. item.LeadValue = v.LeadValue
  170. item.LeadUnit = v.LeadUnit
  171. item.LeadUnitEn = GetLeadUnitEn(v.LeadUnit)
  172. item.ChartEdbMappingId = v.ChartEdbMappingId
  173. item.ChartInfoId = v.ChartInfoId
  174. item.ChartStyle = v.ChartStyle
  175. item.ChartColor = v.ChartColor
  176. item.ChartWidth = v.ChartWidth
  177. item.IsOrder = v.IsOrder
  178. item.MaxData = v.MaxData
  179. item.MinData = v.MinData
  180. }
  181. item.LatestValue = v.LatestValue
  182. item.LatestDate = v.LatestDate
  183. item.UniqueCode = v.UniqueCode
  184. var startDateReal string
  185. var diffSeconds int64
  186. if chartType == 2 { //季节性图
  187. startDateReal = startDate
  188. } else {
  189. if v.EdbInfoType == 0 && v.LeadUnit != "" && v.LeadValue > 0 { //领先指标
  190. var startTimeRealTemp time.Time
  191. startDateParse, _ := time.Parse(utils.FormatDate, startDate)
  192. switch v.LeadUnit {
  193. case "天":
  194. startTimeRealTemp = startDateParse.AddDate(0, 0, -v.LeadValue)
  195. case "月":
  196. startTimeRealTemp = startDateParse.AddDate(0, -v.LeadValue, 0)
  197. case "季":
  198. startTimeRealTemp = startDateParse.AddDate(0, -3*v.LeadValue, 0)
  199. case "周":
  200. startTimeRealTemp = startDateParse.AddDate(0, 0, -7*v.LeadValue)
  201. case "年":
  202. startTimeRealTemp = startDateParse.AddDate(-v.LeadValue, 0, 0)
  203. }
  204. if startTimeRealTemp.Before(startDateParse) {
  205. startDateReal = startTimeRealTemp.Format(utils.FormatDate)
  206. diffSeconds = (int64(startTimeRealTemp.UnixNano()) - int64(startDateParse.UnixNano())) / 1e6
  207. } else {
  208. startDateReal = startDate
  209. diffSeconds = 0
  210. }
  211. } else {
  212. startDateReal = startDate
  213. }
  214. }
  215. //fmt.Println("line 1011 chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
  216. calendarPreYear := 0
  217. if calendar == "农历" {
  218. newStartDateReal, err := time.Parse(utils.FormatDate, startDateReal)
  219. if err != nil {
  220. fmt.Println("time.Parse:" + err.Error())
  221. }
  222. calendarPreYear = newStartDateReal.Year() - 1
  223. newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
  224. startDateReal = newStartDateReal.Format(utils.FormatDate)
  225. }
  226. dataList := make([]*data_manage.EdbDataList, 0)
  227. //fmt.Println("chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
  228. //var newEdbInfo *data_manage.EdbInfo
  229. switch v.EdbInfoCategoryType {
  230. case 0:
  231. dataList, err = data_manage.GetEdbDataList(v.Source, v.EdbInfoId, startDateReal, endDate)
  232. case 1:
  233. _, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(v.EdbInfoId, startDateReal, endDate, false)
  234. default:
  235. err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.EdbInfoCategoryType))
  236. }
  237. if err != nil {
  238. return
  239. }
  240. edbDataListMap[v.EdbInfoId] = dataList
  241. if diffSeconds != 0 && v.EdbInfoType == 0 {
  242. dataListLen := len(dataList)
  243. for i := 0; i < dataListLen; i++ {
  244. dataList[i].DataTimestamp = dataList[i].DataTimestamp - diffSeconds
  245. }
  246. }
  247. if chartType == 2 {
  248. latestDateStr := v.LatestDate //实际数据的截止日期
  249. latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
  250. if tmpErr != nil {
  251. //item.DataList = dataList
  252. item.IsNullData = true
  253. edbList = append(edbList, item)
  254. continue
  255. err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
  256. return
  257. }
  258. latestDateYear := latestDate.Year() //实际数据截止年份
  259. if calendar == "农历" {
  260. if len(dataList) <= 0 {
  261. result := new(data_manage.EdbDataResult)
  262. item.DataList = result
  263. } else {
  264. result, tmpErr := data_manage.AddCalculateQuarterV4(dataList)
  265. if tmpErr != nil {
  266. err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
  267. return
  268. }
  269. // 处理季节图的截止日期
  270. for k, edbDataItems := range result.List {
  271. var cuttingDataTimestamp int64
  272. // 切割的日期时间字符串
  273. cuttingDataTimeStr := latestDate.AddDate(0, 0, edbDataItems.BetweenDay).Format(utils.FormatDate)
  274. //如果等于最后的实际日期,那么遍历找到该日期对应的时间戳,并将其赋值为 切割时间戳
  275. if edbDataItems.Year >= latestDateYear {
  276. for _, tmpData := range edbDataItems.Items {
  277. if tmpData.DataTime == cuttingDataTimeStr {
  278. cuttingDataTimestamp = tmpData.DataTimestamp
  279. break
  280. }
  281. }
  282. }
  283. edbDataItems.CuttingDataTimestamp = cuttingDataTimestamp
  284. result.List[k] = edbDataItems
  285. }
  286. if result.List[0].Year != calendarPreYear {
  287. itemList := make([]*data_manage.EdbDataList, 0)
  288. items := new(data_manage.EdbDataItems)
  289. //items.Year = calendarPreYear
  290. items.Items = itemList
  291. newResult := new(data_manage.EdbDataResult)
  292. newResult.List = append(newResult.List, items)
  293. newResult.List = append(newResult.List, result.List...)
  294. item.DataList = newResult
  295. } else {
  296. item.DataList = result
  297. }
  298. }
  299. } else {
  300. currentYear := time.Now().Year()
  301. quarterDataList := make([]*data_manage.QuarterData, 0)
  302. quarterMap := make(map[int][]*data_manage.EdbDataList)
  303. var quarterArr []int
  304. for _, v := range dataList {
  305. itemDate, tmpErr := time.Parse(utils.FormatDate, v.DataTime)
  306. if tmpErr != nil {
  307. err = errors.New("季度指标日期转换,Err:" + tmpErr.Error() + ";DataTime:" + v.DataTime)
  308. return
  309. }
  310. year := itemDate.Year()
  311. newItemDate := itemDate.AddDate(currentYear-year, 0, 0)
  312. timestamp := newItemDate.UnixNano() / 1e6
  313. v.DataTimestamp = timestamp
  314. if findVal, ok := quarterMap[year]; !ok {
  315. quarterArr = append(quarterArr, year)
  316. findVal = append(findVal, v)
  317. quarterMap[year] = findVal
  318. } else {
  319. findVal = append(findVal, v)
  320. quarterMap[year] = findVal
  321. }
  322. }
  323. for _, v := range quarterArr {
  324. itemList := quarterMap[v]
  325. quarterItem := new(data_manage.QuarterData)
  326. quarterItem.Year = v
  327. quarterItem.DataList = itemList
  328. //如果等于最后的实际日期,那么将切割时间戳记录
  329. if v == latestDateYear {
  330. var cuttingDataTimestamp int64
  331. for _, tmpData := range itemList {
  332. if tmpData.DataTime == latestDateStr {
  333. cuttingDataTimestamp = tmpData.DataTimestamp
  334. break
  335. }
  336. }
  337. quarterItem.CuttingDataTimestamp = cuttingDataTimestamp
  338. } else if v > latestDateYear {
  339. //如果大于最后的实际日期,那么第一个点就是切割的时间戳
  340. if len(itemList) > 0 {
  341. quarterItem.CuttingDataTimestamp = itemList[0].DataTimestamp - 100
  342. }
  343. }
  344. quarterDataList = append(quarterDataList, quarterItem)
  345. }
  346. item.DataList = quarterDataList
  347. }
  348. } else if chartType == 7 { //柱方图
  349. //item.DataList = dataList
  350. } else {
  351. item.DataList = dataList
  352. }
  353. edbList = append(edbList, item)
  354. }
  355. return
  356. }
  357. // BarChartData 柱方图的数据处理
  358. func BarChartData(mappingList []*data_manage.ChartEdbInfoMapping, edbDataListMap map[int][]*data_manage.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, barChartInfoSort data_manage.BarChartInfoSortReq) (edbIdList []int, yDataList []data_manage.YData, err error) {
  359. // 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
  360. edbDataMap := make(map[int]map[string]float64)
  361. for edbInfoId, edbDataList := range edbDataListMap {
  362. edbDateData := make(map[string]float64)
  363. for _, edbData := range edbDataList {
  364. edbDateData[edbData.DataTime] = edbData.Value
  365. }
  366. edbDataMap[edbInfoId] = edbDateData
  367. }
  368. // edbIdList 指标展示顺序;x轴的指标顺序
  369. edbIdList = make([]int, 0)
  370. //Sort int `description:"排序类型,0:默认,1:升序,2:降序"`
  371. dateData := make(map[int]float64)
  372. if barChartInfoSort.Sort == 0 {
  373. for _, v := range mappingList {
  374. edbIdList = append(edbIdList, v.EdbInfoId)
  375. }
  376. } else {
  377. lenBarChartInfoDateList := len(barChartInfoDateList)
  378. if barChartInfoSort.DateIndex >= lenBarChartInfoDateList {
  379. err = errors.New("排序日期异常")
  380. return
  381. }
  382. notDataEdbIdList := make([]int, 0) //没有数据的指标id
  383. // 日期配置
  384. barChartInfoDate := barChartInfoDateList[barChartInfoSort.DateIndex]
  385. for edbInfoId, dataList := range edbDataListMap {
  386. if len(dataList) <= 0 {
  387. // 没有数据的指标id
  388. notDataEdbIdList = append(notDataEdbIdList, edbInfoId)
  389. continue
  390. }
  391. findDate := barChartInfoDate.Date
  392. switch barChartInfoDate.Type {
  393. case 1: //最新值
  394. findDate = dataList[len(dataList)-1].DataTime
  395. case 2: //近期几天
  396. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[len(dataList)-1].DataTime, time.Local)
  397. if tmpErr != nil {
  398. err = tmpErr
  399. return
  400. }
  401. findDateTime = findDateTime.AddDate(0, 0, -barChartInfoDate.Value)
  402. lenData := len(dataList) - 1
  403. for i := lenData; i >= 0; i-- {
  404. currDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
  405. if tmpErr != nil {
  406. err = tmpErr
  407. return
  408. }
  409. if currDateTime.Equal(findDateTime) || currDateTime.Before(findDateTime) {
  410. findDate = dataList[i].DataTime
  411. break
  412. }
  413. }
  414. case 3: // 固定日期
  415. //最早的日期
  416. minDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
  417. if tmpErr != nil {
  418. err = tmpErr
  419. return
  420. }
  421. //寻找固定日期的数据
  422. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
  423. if tmpErr != nil {
  424. err = tmpErr
  425. return
  426. }
  427. for tmpDateTime := findDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
  428. tmpDate := tmpDateTime.Format(utils.FormatDate)
  429. if _, ok := edbDataMap[edbInfoId][tmpDate]; ok { //如果能找到数据,那么就返回
  430. findDate = tmpDate
  431. break
  432. }
  433. }
  434. default:
  435. err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
  436. return
  437. }
  438. if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
  439. dateData[edbInfoId] = tmpValue
  440. } else {
  441. // 没有数据的指标id
  442. notDataEdbIdList = append(notDataEdbIdList, edbInfoId)
  443. }
  444. }
  445. //Sort int `description:"排序类型,0:默认,1:升序,2:降序"`
  446. // 排序
  447. dateDataSort := utils.NewMapSorter(dateData)
  448. sort.Sort(dateDataSort)
  449. if barChartInfoSort.Sort == 1 {
  450. // 先将没有数据的指标id放在最前面
  451. if len(notDataEdbIdList) > 0 {
  452. edbIdList = append(edbIdList, notDataEdbIdList...)
  453. }
  454. for _, v := range dateDataSort {
  455. edbIdList = append(edbIdList, v.Key)
  456. }
  457. } else {
  458. for i := len(dateDataSort) - 1; i >= 0; i-- {
  459. edbIdList = append(edbIdList, dateDataSort[i].Key)
  460. }
  461. // 再将没有数据的指标id放在最后面
  462. if len(notDataEdbIdList) > 0 {
  463. edbIdList = append(edbIdList, notDataEdbIdList...)
  464. }
  465. }
  466. }
  467. yDataList = make([]data_manage.YData, 0) //y轴的数据列表
  468. for _, barChartInfoDate := range barChartInfoDateList {
  469. var maxDate time.Time
  470. findDataList := make([]float64, 0) // 当前日期的数据值
  471. for _, edbInfoId := range edbIdList {
  472. findDate := barChartInfoDate.Date //需要的日期值
  473. dataList := edbDataListMap[edbInfoId] //指标的所有数据值
  474. if len(dataList) <= 0 {
  475. // 没有数据的指标id
  476. findDataList = append(findDataList, 0)
  477. continue
  478. }
  479. switch barChartInfoDate.Type {
  480. case 1: //最新值
  481. dataList := edbDataListMap[edbInfoId]
  482. findDate = dataList[len(dataList)-1].DataTime
  483. case 2: //近期几天
  484. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[len(dataList)-1].DataTime, time.Local)
  485. if tmpErr != nil {
  486. err = tmpErr
  487. return
  488. }
  489. findDateTime = findDateTime.AddDate(0, 0, -barChartInfoDate.Value)
  490. lenData := len(dataList) - 1
  491. for i := lenData; i >= 0; i-- {
  492. currDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
  493. if tmpErr != nil {
  494. err = tmpErr
  495. return
  496. }
  497. if currDateTime.Equal(findDateTime) || currDateTime.Before(findDateTime) {
  498. findDate = dataList[i].DataTime
  499. break
  500. }
  501. }
  502. case 3: // 固定日期
  503. //最早的日期
  504. minDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
  505. if tmpErr != nil {
  506. err = tmpErr
  507. return
  508. }
  509. //寻找固定日期的数据
  510. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, barChartInfoDate.Date, time.Local)
  511. if tmpErr != nil {
  512. err = tmpErr
  513. return
  514. }
  515. for tmpDateTime := findDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
  516. tmpDate := tmpDateTime.Format(utils.FormatDate)
  517. if _, ok := edbDataMap[edbInfoId][tmpDate]; ok { //如果能找到数据,那么就返回
  518. findDate = tmpDate
  519. break
  520. }
  521. }
  522. default:
  523. err = errors.New(fmt.Sprint("日期类型异常,Type:", barChartInfoDate.Type))
  524. return
  525. }
  526. findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
  527. if maxDate.IsZero() {
  528. maxDate = findDateTime
  529. } else {
  530. if findDateTime.After(maxDate) {
  531. maxDate = findDateTime
  532. }
  533. }
  534. if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
  535. findDataList = append(findDataList, tmpValue)
  536. } else {
  537. findDataList = append(findDataList, 0)
  538. }
  539. }
  540. yDate := "0000-00-00"
  541. if !maxDate.IsZero() {
  542. yDate = maxDate.Format(utils.FormatDate)
  543. }
  544. yDataList = append(yDataList, data_manage.YData{
  545. Date: yDate,
  546. Value: findDataList,
  547. Color: barChartInfoDate.Color,
  548. Name: barChartInfoDate.Name,
  549. })
  550. }
  551. return
  552. }
  553. func CheckIsEnChart(chartNameEn string, edbList []*data_manage.ChartEdbInfoMapping, source, chartType int) bool {
  554. // 相关性图表不判断指标
  555. if source == utils.CHART_SOURCE_CORRELATION && chartNameEn != "" {
  556. return true
  557. }
  558. if chartNameEn == "" {
  559. return false
  560. }
  561. // 截面散点图的话,肯定是有英文配置的
  562. if chartType == utils.CHART_TYPE_SECTION_SCATTER {
  563. return true
  564. }
  565. for _, v := range edbList {
  566. if v.EdbNameEn == "" {
  567. return false
  568. }
  569. if v.Unit != "无" && v.Unit != "" && v.UnitEn == "" {
  570. return false
  571. }
  572. }
  573. return true
  574. }
  575. func CheckIsEnEdb(edbNameEn, unit, unitEn string) bool {
  576. if edbNameEn == "" {
  577. return false
  578. }
  579. if unit != "无" && unit != "" && unitEn == "" {
  580. return false
  581. }
  582. return true
  583. }
  584. // CheckIsDisableChart 根据指标Id判断是否是禁用图表
  585. // return int 0:启用,1:禁用
  586. func CheckIsDisableChart(edbInfoIdArr []int) (isDisable int) {
  587. crmConfig, err := company.GetConfigDetailByCode("chart_disabled_edb")
  588. if err != nil {
  589. return
  590. }
  591. //没有配置,立马返回
  592. if crmConfig.ConfigValue == `` {
  593. return
  594. }
  595. confEdbInfoIdList := strings.Split(crmConfig.ConfigValue, ",")
  596. for _, edbInfoId := range edbInfoIdArr {
  597. for _, confEdbInfoId := range confEdbInfoIdList {
  598. if strconv.Itoa(edbInfoId) == confEdbInfoId {
  599. isDisable = 1
  600. return
  601. }
  602. }
  603. }
  604. return
  605. }
  606. // CheckChartExtraConfig 校验图表额外配置的信息,并且获取相关联的指标id
  607. func CheckChartExtraConfig(chartType int, extraConfigStr string) (edbIdList []int, err error, errMsg string) {
  608. switch chartType {
  609. case 10: //截面散点
  610. var extraConfig data_manage.SectionScatterReq
  611. err = json.Unmarshal([]byte(extraConfigStr), &extraConfig)
  612. if err != nil {
  613. return
  614. }
  615. // 判断是否有配置日期序列
  616. if len(extraConfig.SeriesList) <= 0 {
  617. errMsg = `请配置序列`
  618. err = errors.New(errMsg)
  619. return
  620. }
  621. // 判断是否有填写指标
  622. if len(extraConfig.SeriesList[0].EdbInfoList) <= 0 {
  623. errMsg = `请选择指标`
  624. err = errors.New(errMsg)
  625. return
  626. }
  627. // 遍历指标列表获取指标id
  628. edbIdMap := make(map[int]int)
  629. for _, v := range extraConfig.SeriesList[0].EdbInfoList {
  630. // X 轴的指标id
  631. if _, ok := edbIdMap[v.XEdbInfoId]; !ok {
  632. edbIdMap[v.XEdbInfoId] = v.XEdbInfoId
  633. edbIdList = append(edbIdList, v.XEdbInfoId)
  634. }
  635. // Y 轴的指标id
  636. if _, ok := edbIdMap[v.YEdbInfoId]; !ok {
  637. edbIdMap[v.YEdbInfoId] = v.YEdbInfoId
  638. edbIdList = append(edbIdList, v.YEdbInfoId)
  639. }
  640. }
  641. }
  642. return
  643. }
  644. // GetSectionScatterChartData 截面散点图的数据处理
  645. func GetSectionScatterChartData(mappingList []*data_manage.ChartEdbInfoMapping, edbDataListMap map[int][]*data_manage.EdbDataList, extraConfig data_manage.SectionScatterReq) (edbIdList []int, chartDataResp data_manage.SectionScatterInfoResp, err error) {
  646. // 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
  647. edbDataMap := make(map[int]map[string]float64)
  648. for edbInfoId, edbDataList := range edbDataListMap {
  649. edbDateData := make(map[string]float64)
  650. for _, edbData := range edbDataList {
  651. edbDateData[edbData.DataTime] = edbData.Value
  652. }
  653. edbDataMap[edbInfoId] = edbDateData
  654. }
  655. // edbIdList 指标展示顺序;x轴的指标顺序
  656. edbIdList = make([]int, 0)
  657. edbMappingMap := make(map[int]*data_manage.ChartEdbInfoMapping)
  658. for _, v := range mappingList {
  659. edbIdList = append(edbIdList, v.EdbInfoId)
  660. edbMappingMap[v.EdbInfoId] = v
  661. }
  662. //SectionScatterSeriesInfoResp
  663. dataListResp := make([]data_manage.SectionScatterSeriesItemResp, 0) //y轴的数据列表
  664. for _, seriesItem := range extraConfig.SeriesList {
  665. var maxDate time.Time
  666. // 系列中的指标数据
  667. tmpSeriesEdbInfoList := make([]data_manage.SectionScatterEdbItemResp, 0)
  668. var minXVal, maxXVal, minYVal, maxYVal float64
  669. for _, edbConf := range seriesItem.EdbInfoList {
  670. tmpItem := data_manage.SectionScatterEdbItemResp{
  671. IsShow: edbConf.IsShow,
  672. Name: edbConf.Name,
  673. NameEn: edbConf.NameEn,
  674. } //单个坐标点的数据
  675. //X轴的数据
  676. {
  677. edbInfoId := edbConf.XEdbInfoId //X轴的指标
  678. edbMappingInfo, ok := edbMappingMap[edbInfoId]
  679. if !ok {
  680. continue
  681. }
  682. findDate := edbConf.XDate //需要的日期值
  683. dataList := edbDataListMap[edbInfoId] //指标的所有数据值
  684. if len(dataList) <= 0 {
  685. // 没有数据的指标id
  686. //findDataList = append(findDataList, 0)
  687. continue
  688. }
  689. tmpItem.XEdbInfoId = edbInfoId
  690. tmpItem.XName = edbMappingInfo.EdbName
  691. tmpItem.XNameEn = edbMappingInfo.EdbNameEn
  692. switch edbConf.XDateType {
  693. case 1: //最新值
  694. findDate = dataList[len(dataList)-1].DataTime
  695. case 2: //近期几天
  696. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[len(dataList)-1].DataTime, time.Local)
  697. if tmpErr != nil {
  698. err = tmpErr
  699. return
  700. }
  701. findDateTime = findDateTime.AddDate(0, 0, -edbConf.XDateValue)
  702. lenData := len(dataList) - 1
  703. for i := lenData; i >= 0; i-- {
  704. currDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
  705. if tmpErr != nil {
  706. err = tmpErr
  707. return
  708. }
  709. if currDateTime.Equal(findDateTime) || currDateTime.Before(findDateTime) {
  710. findDate = dataList[i].DataTime
  711. break
  712. }
  713. }
  714. case 3: // 固定日期
  715. //最早的日期
  716. minDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
  717. if tmpErr != nil {
  718. err = tmpErr
  719. return
  720. }
  721. //寻找固定日期的数据
  722. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, edbConf.XDate, time.Local)
  723. if tmpErr != nil {
  724. err = tmpErr
  725. return
  726. }
  727. for tmpDateTime := findDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
  728. tmpDate := tmpDateTime.Format(utils.FormatDate)
  729. if _, ok := edbDataMap[edbInfoId][tmpDate]; ok { //如果能找到数据,那么就返回
  730. findDate = tmpDate
  731. break
  732. }
  733. }
  734. default:
  735. err = errors.New(fmt.Sprint("日期类型异常,Type:", edbConf.XDate))
  736. return
  737. }
  738. findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
  739. if maxDate.IsZero() {
  740. maxDate = findDateTime
  741. } else {
  742. if findDateTime.After(maxDate) {
  743. maxDate = findDateTime
  744. }
  745. }
  746. if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
  747. tmpItem.XDate = findDate
  748. tmpItem.XValue = tmpValue
  749. } else {
  750. continue
  751. }
  752. }
  753. //Y轴的数据
  754. {
  755. edbInfoId := edbConf.YEdbInfoId //Y轴的指标
  756. edbMappingInfo, ok := edbMappingMap[edbInfoId]
  757. if !ok {
  758. continue
  759. }
  760. findDate := edbConf.YDate //需要的日期值
  761. dataList := edbDataListMap[edbInfoId] //指标的所有数据值
  762. if len(dataList) <= 0 {
  763. // 没有数据的指标id
  764. //findDataList = append(findDataList, 0)
  765. continue
  766. }
  767. tmpItem.YEdbInfoId = edbInfoId
  768. tmpItem.YName = edbMappingInfo.EdbName
  769. tmpItem.YNameEn = edbMappingInfo.EdbNameEn
  770. switch edbConf.YDateType {
  771. case 1: //最新值
  772. findDate = dataList[len(dataList)-1].DataTime
  773. case 2: //近期几天
  774. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[len(dataList)-1].DataTime, time.Local)
  775. if tmpErr != nil {
  776. err = tmpErr
  777. return
  778. }
  779. findDateTime = findDateTime.AddDate(0, 0, -edbConf.YDateValue)
  780. lenData := len(dataList) - 1
  781. for i := lenData; i >= 0; i-- {
  782. currDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
  783. if tmpErr != nil {
  784. err = tmpErr
  785. return
  786. }
  787. if currDateTime.Equal(findDateTime) || currDateTime.Before(findDateTime) {
  788. findDate = dataList[i].DataTime
  789. break
  790. }
  791. }
  792. case 3: // 固定日期
  793. //最早的日期
  794. minDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
  795. if tmpErr != nil {
  796. err = tmpErr
  797. return
  798. }
  799. //寻找固定日期的数据
  800. findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, edbConf.YDate, time.Local)
  801. if tmpErr != nil {
  802. err = tmpErr
  803. return
  804. }
  805. for tmpDateTime := findDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
  806. tmpDate := tmpDateTime.Format(utils.FormatDate)
  807. if _, ok := edbDataMap[edbInfoId][tmpDate]; ok { //如果能找到数据,那么就返回
  808. findDate = tmpDate
  809. break
  810. }
  811. }
  812. default:
  813. err = errors.New(fmt.Sprint("日期类型异常,Type:", edbConf.YDate))
  814. return
  815. }
  816. findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
  817. if maxDate.IsZero() {
  818. maxDate = findDateTime
  819. } else {
  820. if findDateTime.After(maxDate) {
  821. maxDate = findDateTime
  822. }
  823. }
  824. if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
  825. tmpItem.YDate = findDate
  826. tmpItem.YValue = tmpValue
  827. } else {
  828. continue
  829. }
  830. }
  831. // 获取当前系列的X轴的最大最小值
  832. {
  833. if tmpItem.XValue < minXVal {
  834. minXVal = tmpItem.XValue
  835. }
  836. if tmpItem.XValue > maxXVal {
  837. maxXVal = tmpItem.XValue
  838. }
  839. if tmpItem.YValue < minYVal {
  840. minYVal = tmpItem.YValue
  841. }
  842. if tmpItem.YValue > maxYVal {
  843. maxYVal = tmpItem.YValue
  844. }
  845. }
  846. tmpSeriesEdbInfoList = append(tmpSeriesEdbInfoList, tmpItem)
  847. }
  848. trendLimitData := make([]data_manage.CoordinatePoint, 0) //趋势线的前后坐标点
  849. var trendLine, rSquare string
  850. // 生成线性方程式
  851. var a, b float64
  852. {
  853. coordinateData := make([]utils.Coordinate, 0)
  854. for _, tmpSeriesEdbInfo := range tmpSeriesEdbInfoList {
  855. tmpCoordinate1 := utils.Coordinate{
  856. X: tmpSeriesEdbInfo.XValue,
  857. Y: tmpSeriesEdbInfo.YValue,
  858. }
  859. coordinateData = append(coordinateData, tmpCoordinate1)
  860. }
  861. // 只有存在两个坐标点的时候,才能去计算线性方程和R平方
  862. if len(coordinateData) >= 2 {
  863. a, b = utils.GetLinearResult(coordinateData)
  864. if !math.IsNaN(a) && !math.IsNaN(b) {
  865. if b > 0 {
  866. trendLine = fmt.Sprintf("y=%sx+%s", utils.SubFloatToString(a, 4), utils.SubFloatToString(b, 4))
  867. } else {
  868. trendLine = fmt.Sprintf("y=%sx%s", utils.SubFloatToString(a, 4), utils.SubFloatToString(b, 4))
  869. }
  870. minYVal, _ = decimal.NewFromFloat(a).Mul(decimal.NewFromFloat(minXVal)).Add(decimal.NewFromFloat(b)).Round(4).Float64()
  871. maxYVal, _ = decimal.NewFromFloat(a).Mul(decimal.NewFromFloat(maxXVal)).Add(decimal.NewFromFloat(b)).Round(4).Float64()
  872. }
  873. // 计算R平方
  874. rSquare = fmt.Sprint(utils.CalculationDecisive(coordinateData))
  875. }
  876. trendLimitData = append(trendLimitData, data_manage.CoordinatePoint{
  877. X: minXVal,
  878. Y: minYVal,
  879. }, data_manage.CoordinatePoint{
  880. X: maxXVal,
  881. Y: maxYVal,
  882. })
  883. }
  884. dataListResp = append(dataListResp, data_manage.SectionScatterSeriesItemResp{
  885. Name: seriesItem.Name,
  886. NameEn: seriesItem.NameEn,
  887. Color: seriesItem.Color,
  888. EdbInfoList: tmpSeriesEdbInfoList,
  889. ShowTrendLine: seriesItem.ShowTrendLine,
  890. ShowFitEquation: seriesItem.ShowFitEquation,
  891. ShowRSquare: seriesItem.ShowRSquare,
  892. TrendLine: trendLine,
  893. RSquare: rSquare,
  894. TrendLimitData: trendLimitData,
  895. })
  896. }
  897. chartDataResp = data_manage.SectionScatterInfoResp{
  898. XName: extraConfig.XName,
  899. XNameEn: extraConfig.XNameEn,
  900. XUnitName: extraConfig.XUnitName,
  901. XUnitNameEn: extraConfig.XUnitNameEn,
  902. YName: extraConfig.YName,
  903. YNameEn: extraConfig.YNameEn,
  904. YUnitName: extraConfig.YUnitName,
  905. YUnitNameEn: extraConfig.YUnitNameEn,
  906. XMinValue: extraConfig.XMinValue,
  907. XMaxValue: extraConfig.XMaxValue,
  908. YMinValue: extraConfig.YMinValue,
  909. YMaxValue: extraConfig.YMaxValue,
  910. DataList: dataListResp,
  911. }
  912. return
  913. }
  914. // BatchChartInfoRefreshV2 图表批量刷新
  915. // @author Roc
  916. // @datetime 2022-09-16 10:15:38
  917. // @description 将原来自己写的一套获取所有关联指标,然后刷新指标逻辑 改成 只获取使用的指标id,然后遍历去调用“指标刷新服务”
  918. func BatchChartInfoRefreshV2(chartInfoList []*data_manage.ChartInfo) (err error) {
  919. if len(chartInfoList) <= 0 {
  920. return
  921. }
  922. chartInfoIdSlice := make([]int, 0)
  923. for _, chartInfo := range chartInfoList {
  924. chartInfoIdSlice = append(chartInfoIdSlice, chartInfo.ChartInfoId)
  925. }
  926. var errmsg string
  927. defer func() {
  928. if err != nil {
  929. go alarm_msg.SendAlarmMsg("ChartInfoRefresh:"+errmsg, 3)
  930. //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "ChartInfoRefresh:"+errmsg, utils.EmailSendToUsers)
  931. fmt.Println("ChartInfoRefresh Err:" + errmsg)
  932. }
  933. }()
  934. edbIdList := make([]int, 0)
  935. edbInfoIdMap := make(map[int]int)
  936. edbMappingList, err := data_manage.GetChartEdbMappingListByIdList(chartInfoIdSlice)
  937. for _, v := range edbMappingList {
  938. if _, ok := edbInfoIdMap[v.EdbInfoId]; !ok {
  939. edbIdList = append(edbIdList, v.EdbInfoId)
  940. edbInfoIdMap[v.EdbInfoId] = v.EdbInfoId
  941. }
  942. }
  943. // 批量刷新
  944. err = EdbInfoRefreshAllFromBaseV3(edbIdList, false)
  945. if err != nil {
  946. return
  947. }
  948. return
  949. }