chart_info.go 31 KB

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