archive_stat.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. package service
  2. import (
  3. "context"
  4. "sort"
  5. "time"
  6. "go-common/app/admin/main/laser/model"
  7. )
  8. const (
  9. // ALLNAME is specific name video_audit overview
  10. ALLNAME = "ALL全体总览"
  11. // ALLUID is specific uid for video_audit overview
  12. ALLUID = -1
  13. )
  14. // ArchiveRecheck is stat recheck flow data node.
  15. func (s *Service) ArchiveRecheck(c context.Context, typeIDS []int64, unames string, startDate int64, endDate int64) (recheckViews []*model.StatView, err error) {
  16. start := time.Unix(startDate, 0)
  17. end := time.Unix(endDate, 0)
  18. var uids []int64
  19. var res map[string]int64
  20. if len(unames) != 0 {
  21. res, err = s.dao.GetUIDByNames(c, unames)
  22. if err != nil {
  23. return
  24. }
  25. for _, uid := range res {
  26. uids = append(uids, uid)
  27. }
  28. }
  29. statTypes := []int64{model.TotalArchive, model.TotalOper, model.ReCheck, model.Lock,
  30. model.ThreeLimit, model.FirstCheck, model.SecondCheck, model.ThirdCheck, model.NoRankArchive, model.NoIndexArchive, model.NoRecommendArchive, model.NoPushArchive,
  31. model.FirstCheckOper, model.FirstCheckTime, model.SecondCheckOper,
  32. model.SecondCheckTime, model.ThirdCheckOper, model.ThirdCheckTime}
  33. var statViews []*model.StatView
  34. for !start.After(end) {
  35. statViews, err = s.dailyStatArchiveRecheck(c, model.ArchiveRecheck, typeIDS, statTypes, uids, start)
  36. if err != nil {
  37. return
  38. }
  39. recheckViews = append(recheckViews, statViews...)
  40. start = start.AddDate(0, 0, 1)
  41. }
  42. return
  43. }
  44. // UserRecheck is stat user recheck data node.
  45. func (s *Service) UserRecheck(c context.Context, typeIDS []int64, unames string, startDate int64, endDate int64) (
  46. recheckViews []*model.StatView, err error) {
  47. start := time.Unix(startDate, 0)
  48. end := time.Unix(endDate, 0)
  49. var uids []int64
  50. var res map[string]int64
  51. if len(unames) != 0 {
  52. res, err = s.dao.GetUIDByNames(c, unames)
  53. if err != nil {
  54. return
  55. }
  56. for _, uid := range res {
  57. uids = append(uids, uid)
  58. }
  59. }
  60. statTypes := []int64{model.TotalOperFrequency, model.FirstCheckOper, model.SecondCheckOper, model.ThirdCheckOper,
  61. model.FirstCheckOper, model.FirstCheckTime, model.SecondCheckOper,
  62. model.SecondCheckTime, model.ThirdCheckOper, model.ThirdCheckTime}
  63. var statViews []*model.StatView
  64. for !start.After(end) {
  65. statViews, err = s.dailyStatArchiveRecheck(c, model.ArchiveRecheck, typeIDS, statTypes, uids, start)
  66. if err != nil {
  67. return
  68. }
  69. recheckViews = append(recheckViews, statViews...)
  70. start = start.AddDate(0, 0, 1)
  71. }
  72. return
  73. }
  74. func (s *Service) dailyStatArchiveRecheck(c context.Context, business int, typeIDS []int64, statTypes []int64, uids []int64, statDate time.Time) (statViews []*model.StatView, err error) {
  75. mediateView, err := s.dailyArchiveStat(c, business, typeIDS, statTypes, uids, statDate)
  76. if err != nil || len(mediateView) == 0 {
  77. return
  78. }
  79. statViews = makeUpArchiveRecheck(mediateView)
  80. return
  81. }
  82. func makeUpArchiveRecheck(mediateView map[int64]map[int]int64) (statViews []*model.StatView) {
  83. items := make(map[int64][]*model.StatItem)
  84. for k1, v1 := range mediateView {
  85. var recheckItems []*model.StatItem
  86. denominatorValue, ok1 := v1[model.FirstCheckOper]
  87. numeratorValue, ok2 := v1[model.FirstCheckTime]
  88. if ok1 && ok2 {
  89. if denominatorValue == 0 {
  90. recheckItems = append(recheckItems, &model.StatItem{
  91. DataCode: model.FirstAvgTime,
  92. Value: 0,
  93. })
  94. } else {
  95. recheckItems = append(recheckItems, &model.StatItem{
  96. DataCode: model.FirstAvgTime,
  97. Value: numeratorValue / denominatorValue,
  98. })
  99. }
  100. }
  101. denominatorValue, ok1 = v1[model.SecondCheckOper]
  102. numeratorValue, ok2 = v1[model.SecondCheckTime]
  103. if ok1 && ok2 {
  104. if denominatorValue == 0 {
  105. recheckItems = append(recheckItems, &model.StatItem{
  106. DataCode: model.SecondAvgTime,
  107. Value: 0,
  108. })
  109. } else {
  110. recheckItems = append(recheckItems, &model.StatItem{
  111. DataCode: model.SecondAvgTime,
  112. Value: numeratorValue / denominatorValue,
  113. })
  114. }
  115. }
  116. denominatorValue, ok1 = v1[model.ThirdCheckOper]
  117. numeratorValue, ok2 = v1[model.ThirdCheckTime]
  118. if ok1 && ok2 {
  119. if denominatorValue == 0 {
  120. recheckItems = append(recheckItems, &model.StatItem{
  121. DataCode: model.ThirdAvgTime,
  122. Value: 0,
  123. })
  124. } else {
  125. recheckItems = append(recheckItems, &model.StatItem{
  126. DataCode: model.ThirdAvgTime,
  127. Value: numeratorValue / denominatorValue,
  128. })
  129. }
  130. }
  131. for k2, v2 := range v1 {
  132. recheckItems = append(recheckItems, &model.StatItem{DataCode: k2, Value: v2})
  133. }
  134. items[k1] = recheckItems
  135. }
  136. for k, v := range items {
  137. statViews = append(statViews, &model.StatView{Date: k, Stats: v})
  138. }
  139. return
  140. }
  141. func (s *Service) dailyArchiveStat(c context.Context, business int, typeIDS []int64, statTypes []int64, uids []int64, statDate time.Time) (mediateView map[int64]map[int]int64, err error) {
  142. statNodes, err := s.dao.StatArchiveStat(c, business, typeIDS, uids, statTypes, statDate)
  143. if err != nil || len(statNodes) == 0 {
  144. return
  145. }
  146. mediateView = make(map[int64]map[int]int64)
  147. for _, node := range statNodes {
  148. k1 := node.StatDate.Time().Unix()
  149. k2 := node.StatType
  150. newValue := node.StatValue
  151. if v1, ok := mediateView[k1]; ok {
  152. if v2, ok := v1[k2]; ok {
  153. mediateView[k1][k2] = v2 + newValue
  154. } else {
  155. mediateView[k1][k2] = newValue
  156. }
  157. } else {
  158. mediateView[k1] = map[int]int64{k2: newValue}
  159. }
  160. }
  161. return
  162. }
  163. // TagRecheck is stat archive tag recheck.
  164. func (s *Service) TagRecheck(c context.Context, startDate int64, endDate int64, unames string) (tagViews []*model.StatView, err error) {
  165. start := time.Unix(startDate, 0)
  166. end := time.Unix(endDate, 0)
  167. var uids []int64
  168. var uname2uid map[string]int64
  169. if len(unames) != 0 {
  170. uname2uid, err = s.dao.GetUIDByNames(c, unames)
  171. if err != nil {
  172. return
  173. }
  174. for _, uid := range uname2uid {
  175. uids = append(uids, uid)
  176. }
  177. }
  178. statTypes := []int64{model.TagRecheckTotalTime, model.TagRecheckTotalCount, model.TagChangeCount, model.TagRecheckTotalCount, model.TagRecheckTotalTime}
  179. var statViews []*model.StatView
  180. for !start.After(end) {
  181. statViews, err = s.dailyStatTagRecheck(c, model.TagRecheck, statTypes, uids, start)
  182. if err != nil {
  183. return
  184. }
  185. tagViews = append(tagViews, statViews...)
  186. start = start.AddDate(0, 0, 1)
  187. }
  188. return
  189. }
  190. func (s *Service) dailyStatTagRecheck(c context.Context, business int, statTypes []int64, uids []int64, statDate time.Time) (statViews []*model.StatView, err error) {
  191. mediateView, err := s.dailyArchiveStat(c, business, []int64{}, statTypes, uids, statDate)
  192. if err != nil || len(mediateView) == 0 {
  193. return
  194. }
  195. statViews = makeUpTagRecheck(mediateView)
  196. return
  197. }
  198. func makeUpTagRecheck(mediateView map[int64]map[int]int64) (statViews []*model.StatView) {
  199. items := make(map[int64][]*model.StatItem)
  200. for k1, v1 := range mediateView {
  201. var recheckItems []*model.StatItem
  202. denominatorValue, ok1 := v1[model.TagRecheckTotalCount]
  203. numeratorValue, ok2 := v1[model.TagRecheckTotalTime]
  204. if ok1 && ok2 {
  205. if denominatorValue == 0 {
  206. recheckItems = append(recheckItems, &model.StatItem{
  207. DataCode: model.TagRecheckAvgTime,
  208. Value: 0,
  209. })
  210. } else {
  211. recheckItems = append(recheckItems, &model.StatItem{
  212. DataCode: model.TagRecheckAvgTime,
  213. Value: numeratorValue / denominatorValue,
  214. })
  215. }
  216. }
  217. for k2, v2 := range v1 {
  218. recheckItems = append(recheckItems, &model.StatItem{DataCode: k2, Value: v2})
  219. }
  220. items[k1] = recheckItems
  221. }
  222. for k, v := range items {
  223. statViews = append(statViews, &model.StatView{Date: k, Stats: v})
  224. }
  225. return
  226. }
  227. // Recheck123 is stat 123 recheck.
  228. func (s *Service) Recheck123(c context.Context, startDate int64, endDate int64, typeIDS []int64) (recheckView []*model.StatView, err error) {
  229. start := time.Unix(startDate, 0)
  230. end := time.Unix(endDate, 0)
  231. emptyUids := []int64{}
  232. statTypes := []int64{model.FIRST_RECHECK_IN, model.FIRST_RECHECK_OUT, model.SECOND_RECHECK_IN, model.SECOND_RECHECK_OUT, model.THIRD_RECHECK_IN, model.THIRD_RECHECK_OUT}
  233. var statViews []*model.StatView
  234. for !start.After(end) {
  235. statViews, err = s.dailyStatArchiveStreamStat(c, model.Recheck123, typeIDS, emptyUids, statTypes, start)
  236. if err != nil {
  237. return
  238. }
  239. recheckView = append(recheckView, statViews...)
  240. start = start.AddDate(0, 0, 1)
  241. }
  242. return
  243. }
  244. func (s *Service) dailyStatArchiveStreamStat(c context.Context, business int, typeIDS []int64, uids []int64, statTypes []int64, statDate time.Time) (statViews []*model.StatView, err error) {
  245. statNodes, err := s.dao.StatArchiveStatStream(c, model.Recheck123, typeIDS, uids, statTypes, statDate)
  246. if err != nil || len(statNodes) == 0 {
  247. return
  248. }
  249. mediateView := make(map[int64]map[int]int64)
  250. for _, v := range statNodes {
  251. k1 := v.StatDate.Time().Unix()
  252. k2 := v.StatType
  253. newValue := v.StatValue
  254. if v1, ok := mediateView[k1]; ok {
  255. if v2, ok := v1[k2]; ok {
  256. mediateView[k1][k2] = newValue + v2
  257. } else {
  258. mediateView[k1][k2] = newValue
  259. }
  260. } else {
  261. mediateView[k1] = map[int]int64{k2: newValue}
  262. }
  263. }
  264. for k1, v1 := range mediateView {
  265. var statItems []*model.StatItem
  266. for k2, v2 := range v1 {
  267. statItems = append(statItems, &model.StatItem{DataCode: k2, Value: v2})
  268. }
  269. statViews = append(statViews, &model.StatView{Date: k1, Stats: statItems})
  270. }
  271. return
  272. }
  273. func wrap(cargoMap map[int64]*model.CargoItem) (views []*model.CargoView) {
  274. // 适配返回的JSON结构,减少前端工作量, cargoMap 2 views.
  275. mediateView := make(map[string]map[int]*model.CargoItem)
  276. for k, v := range cargoMap {
  277. statDate := time.Unix(k, 0)
  278. k1 := statDate.Format("2006-01-02")
  279. k2 := statDate.Hour()
  280. if value1, ok := mediateView[k1]; ok {
  281. if value2, ok := value1[k2]; ok {
  282. value2.AuditValue = value2.AuditValue + v.AuditValue
  283. value2.ReceiveValue = value2.ReceiveValue + v.ReceiveValue
  284. mediateView[k1][k2] = value2
  285. } else {
  286. mediateView[k1][k2] = &model.CargoItem{
  287. ReceiveValue: v.ReceiveValue,
  288. AuditValue: v.AuditValue,
  289. }
  290. }
  291. } else {
  292. mediateView[k1] = map[int]*model.CargoItem{
  293. k2: {
  294. ReceiveValue: v.ReceiveValue,
  295. AuditValue: v.AuditValue,
  296. },
  297. }
  298. }
  299. }
  300. for k, v := range mediateView {
  301. views = append(views, &model.CargoView{
  302. Date: k,
  303. Data: v,
  304. })
  305. }
  306. return
  307. }
  308. // CsvAuditCargo is download archive cargo audit data by csv file type.
  309. func (s *Service) CsvAuditCargo(c context.Context, startDate int64, endDate int64, unames string) (res []byte, err error) {
  310. wrappers, lineWidth, err := s.AuditorCargoList(c, startDate, endDate, unames)
  311. if err != nil {
  312. return
  313. }
  314. data := formatAuditCargo(wrappers, lineWidth)
  315. return FormatCSV(data)
  316. }
  317. // AuditorCargoList is query archive audit cargo by uname respectively with stat_date condition.
  318. func (s *Service) AuditorCargoList(c context.Context, startDate int64, endDate int64, unames string) (wrappers []*model.CargoViewWrapper, lineWidth int, err error) {
  319. start := time.Unix(startDate, 0)
  320. end := time.Unix(endDate, 0)
  321. var uids []int64
  322. var name2uid map[string]int64
  323. uid2name := make(map[int64]string)
  324. if len(unames) != 0 {
  325. name2uid, err = s.dao.GetUIDByNames(c, unames)
  326. if err != nil {
  327. return
  328. }
  329. for name, uid := range name2uid {
  330. uids = append(uids, uid)
  331. uid2name[uid] = name
  332. }
  333. }
  334. var items, itemsBlock []*model.CargoDetail
  335. for !start.After(end) {
  336. itemsBlock, err = s.dao.QueryArchiveCargo(c, start, uids)
  337. if err != nil {
  338. return
  339. }
  340. items = append(items, itemsBlock...)
  341. start = start.Add(time.Hour * 1)
  342. }
  343. if len(items) == 0 {
  344. return
  345. }
  346. mediateViews := make(map[int64]map[int64]*model.CargoItem)
  347. uidMap := make(map[int64]bool)
  348. for _, v := range items {
  349. k1 := v.UID
  350. k2 := v.StatDate.Time().Unix()
  351. uidMap[k1] = true
  352. if v1, ok := mediateViews[k1]; ok {
  353. if v2, ok := v1[k2]; ok {
  354. v2.ReceiveValue = v2.ReceiveValue + v.ReceiveValue
  355. v2.AuditValue = v2.AuditValue + v.AuditValue
  356. mediateViews[k1][k2] = v2
  357. } else {
  358. lineWidth = lineWidth + 1
  359. mediateViews[k1][k2] = &model.CargoItem{
  360. ReceiveValue: v.ReceiveValue,
  361. AuditValue: v.AuditValue,
  362. }
  363. }
  364. } else {
  365. lineWidth = lineWidth + 1
  366. mediateViews[k1] = map[int64]*model.CargoItem{
  367. k2: {
  368. ReceiveValue: v.ReceiveValue,
  369. AuditValue: v.AuditValue,
  370. },
  371. }
  372. }
  373. }
  374. if len(unames) == 0 {
  375. for uid := range uidMap {
  376. uids = append(uids, uid)
  377. }
  378. uid2name, err = s.dao.GetUNamesByUids(c, uids)
  379. if err != nil {
  380. return
  381. }
  382. }
  383. for k, v := range mediateViews {
  384. cargoViews := wrap(v)
  385. for _, v := range cargoViews {
  386. wrappers = append(wrappers, &model.CargoViewWrapper{
  387. Username: uid2name[k],
  388. CargoView: v,
  389. })
  390. }
  391. }
  392. return
  393. }
  394. // CsvRandomVideoAudit is download random video audit statistic data by csv file type.
  395. func (s *Service) CsvRandomVideoAudit(c context.Context, startDate int64, endDate int64, unames string, typeIDS []int64) (res []byte, err error) {
  396. statViewExts, lineWidth, err := s.RandomVideo(c, startDate, endDate, typeIDS, unames)
  397. if err != nil {
  398. return
  399. }
  400. sort.Slice(statViewExts, func(i, j int) bool {
  401. return statViewExts[i].Date > statViewExts[j].Date
  402. })
  403. data := formatVideoAuditStat(statViewExts, lineWidth)
  404. return FormatCSV(data)
  405. }
  406. // CsvFixedVideoAudit is download fixed video audit statistic data by csv file type.
  407. func (s *Service) CsvFixedVideoAudit(c context.Context, startDate int64, endDate int64, unames string, typeIDS []int64) (res []byte, err error) {
  408. statViewExts, lineWidth, err := s.FixedVideo(c, startDate, endDate, typeIDS, unames)
  409. if err != nil {
  410. return
  411. }
  412. sort.Slice(statViewExts, func(i, j int) bool {
  413. return statViewExts[i].Date > statViewExts[j].Date
  414. })
  415. data := formatVideoAuditStat(statViewExts, lineWidth)
  416. return FormatCSV(data)
  417. }
  418. // RandomVideo is stat random video type.
  419. func (s *Service) RandomVideo(c context.Context, startDate int64, endDate int64, typeIDS []int64, uname string) (statViewExts []*model.StatViewExt, lineWidth int, err error) {
  420. start := time.Unix(startDate, 0)
  421. end := time.Unix(endDate, 0)
  422. var viewExts []*model.StatViewExt
  423. var width int
  424. for !start.After(end) {
  425. viewExts, width, err = s.videoAudit(c, model.RandomVideoAudit, start, typeIDS, uname)
  426. if err != nil {
  427. return
  428. }
  429. lineWidth = lineWidth + width
  430. statViewExts = append(statViewExts, viewExts...)
  431. start = start.AddDate(0, 0, 1)
  432. }
  433. return
  434. }
  435. // FixedVideo is stat fixed video type.
  436. func (s *Service) FixedVideo(c context.Context, startDate int64, endDate int64, typeIDS []int64, uname string) (statViewExts []*model.StatViewExt, lineWidth int, err error) {
  437. start := time.Unix(startDate, 0)
  438. end := time.Unix(endDate, 0)
  439. var viewExts []*model.StatViewExt
  440. var width int
  441. for !start.After(end) {
  442. viewExts, width, err = s.videoAudit(c, model.FixedVideoAudit, start, typeIDS, uname)
  443. if err != nil {
  444. return
  445. }
  446. lineWidth = lineWidth + width
  447. statViewExts = append(statViewExts, viewExts...)
  448. start = start.AddDate(0, 0, 1)
  449. }
  450. return
  451. }
  452. func (s *Service) videoAudit(c context.Context, business int, statDate time.Time, typeIDS []int64, unames string) (viewExts []*model.StatViewExt, lineWidth int, err error) {
  453. var uids []int64
  454. var res map[string]int64
  455. needAll := true
  456. if len(unames) != 0 {
  457. needAll = false
  458. res, err = s.dao.GetUIDByNames(c, unames)
  459. if err != nil {
  460. return
  461. }
  462. for _, uid := range res {
  463. uids = append(uids, uid)
  464. }
  465. }
  466. statNodes, err := s.dao.StatArchiveStat(c, business, typeIDS, uids, []int64{}, statDate)
  467. if err != nil || len(statNodes) == 0 {
  468. return
  469. }
  470. return s.statNode2ViewExt(c, statNodes, needAll)
  471. }
  472. func (s *Service) statNode2ViewExt(c context.Context, statNodes []*model.StatNode, needAll bool) (statViewsExts []*model.StatViewExt, lineWidth int, err error) {
  473. mediateViews := make(map[int64]map[int64]map[int]int64)
  474. uidMap := make(map[int64]bool)
  475. var uids []int64
  476. for _, v := range statNodes {
  477. k1 := v.StatDate.Time().Unix()
  478. k2 := v.UID
  479. k3 := v.StatType
  480. newValue := v.StatValue
  481. uidMap[k2] = true
  482. if v1, ok := mediateViews[k1]; ok {
  483. if needAll {
  484. if allV2, ok := v1[ALLUID]; ok {
  485. if allV3, ok := allV2[k3]; ok {
  486. mediateViews[k1][ALLUID][k3] = allV3 + newValue
  487. } else {
  488. mediateViews[k1][ALLUID][k3] = newValue
  489. }
  490. } else {
  491. lineWidth = lineWidth + 1
  492. mediateViews[k1][ALLUID] = map[int]int64{k3: newValue}
  493. }
  494. }
  495. if v2, ok := v1[k2]; ok {
  496. if v3, ok := v2[k3]; ok {
  497. mediateViews[k1][k2][k3] = v3 + newValue
  498. } else {
  499. mediateViews[k1][k2][k3] = newValue
  500. }
  501. } else {
  502. lineWidth = lineWidth + 1
  503. mediateViews[k1][k2] = map[int]int64{k3: newValue}
  504. }
  505. } else {
  506. lineWidth = lineWidth + 1
  507. mediateViews[k1] = map[int64]map[int]int64{k2: {k3: newValue}}
  508. if needAll {
  509. lineWidth = lineWidth + 1
  510. mediateViews[k1] = map[int64]map[int]int64{ALLUID: {k3: newValue}}
  511. }
  512. }
  513. }
  514. //fetch uid map uname
  515. for uid := range uidMap {
  516. uids = append(uids, uid)
  517. }
  518. uid2name, err := s.dao.GetUNamesByUids(c, uids)
  519. if err != nil {
  520. return
  521. }
  522. if needAll {
  523. uid2name[ALLUID] = ALLNAME
  524. }
  525. for k1, v1 := range mediateViews {
  526. for k2, v2 := range v1 {
  527. var numeratorValue int64
  528. var denominatorValue int64
  529. for k3, v3 := range v2 {
  530. if k3 == model.WaitAuditDuration {
  531. numeratorValue = v3
  532. }
  533. if k3 == model.WaitAuditOper {
  534. denominatorValue = v3
  535. }
  536. }
  537. if denominatorValue == 0 {
  538. mediateViews[k1][k2][model.WaitAuditAvgTime] = 0
  539. } else {
  540. mediateViews[k1][k2][model.WaitAuditAvgTime] = numeratorValue / denominatorValue
  541. }
  542. }
  543. }
  544. for k1, v1 := range mediateViews {
  545. var wraps []*model.StatItemExt
  546. for k2, v2 := range v1 {
  547. var statItems []*model.StatItem
  548. for k3, v3 := range v2 {
  549. statItems = append(statItems, &model.StatItem{
  550. DataCode: k3,
  551. Value: v3,
  552. })
  553. }
  554. wraps = append(wraps, &model.StatItemExt{
  555. Uname: uid2name[k2],
  556. Stats: statItems,
  557. })
  558. }
  559. // uname排序
  560. sort.Slice(wraps, func(i, j int) bool {
  561. if wraps[i].Uname == ALLNAME {
  562. return true
  563. }
  564. if wraps[j].Uname == ALLNAME {
  565. return false
  566. }
  567. return wraps[i].Uname < wraps[j].Uname
  568. })
  569. statViewsExts = append(statViewsExts, &model.StatViewExt{
  570. Date: k1,
  571. Wraps: wraps,
  572. })
  573. }
  574. return
  575. }