report.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. package model
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strconv"
  6. "time"
  7. "go-common/app/admin/main/aegis/model/common"
  8. modtask "go-common/app/admin/main/aegis/model/task"
  9. "go-common/library/log"
  10. xtime "go-common/library/time"
  11. )
  12. //hash fields
  13. const (
  14. Dispatch = "ds"
  15. Delay = "dy"
  16. Submit = "st_%d_%d" // 参数1:提交状态(任务提交,资源提交,任务关闭) 参数2:提交前属于谁
  17. Release = "rl"
  18. RscState = "rs_%d"
  19. UseTime = "ut"
  20. SetKey = "report_set"
  21. In = "in"
  22. Out = "out"
  23. //type
  24. TypeMeta = int8(0)
  25. TypeTotal = int8(1)
  26. TypeCreate = int8(2) //每日任务增量
  27. TypeDaySubmit = int8(3) //每日任务提交信息
  28. TypeDayUserSubmit = int8(4) //每日审核人员提交信息
  29. )
  30. //TaskReport 任务报表
  31. type TaskReport struct {
  32. ID int64 `json:"id"`
  33. BusinessID int64 `json:"business_id"`
  34. FlowID int64 `json:"flow_id"`
  35. Type int8 `json:"type"`
  36. UID int64 `json:"uid" gorm:"column:uid"`
  37. StatDate time.Time `json:"stat_date"`
  38. Content string `json:"content"`
  39. }
  40. func (t *TaskReport) TableName() string {
  41. return "task_report"
  42. }
  43. //DayPager 按天分页
  44. type DayPager struct {
  45. Pn string `json:"pn"`
  46. IsFirst bool `json:"is_first"` //第一页
  47. IsLast bool `json:"is_last"` //最后一页
  48. }
  49. //ReportSubmitRes .
  50. type ReportSubmitRes struct {
  51. Order []string `json:"order"` //表格列顺序
  52. Header map[string]string `json:"header"` //表格头
  53. Rows [][]map[string]string `json:"rows"` //表格内容体
  54. }
  55. //ReportSubmitItem .
  56. type ReportSubmitItem struct {
  57. StatDate string `json:"stat_date"`
  58. CreateCnt int64 `json:"create_cnt"`
  59. UID int64 `json:"uid"`
  60. Username string `json:"username"`
  61. AvgDur string `json:"avg_dur"`
  62. AvgUtime string `json:"avg_utime"`
  63. FlowID int64 `json:"flow_id"`
  64. SubmitCnt int64 `json:"submit_cnt"`
  65. StateCnt map[string]*ReportSubmitState `json:"state_cnt"`
  66. }
  67. //ReportSubmitState .
  68. type ReportSubmitState struct {
  69. Cnt int64 `json:"cnt"`
  70. Ratio string `json:"ratio"`
  71. }
  72. type ReportSubmitContent struct {
  73. RscStates map[string]int64 `json:"rsc_states"`
  74. AvgDur int64 `json:"avg_dur"`
  75. AvgUtime int64 `json:"avg_utime"`
  76. TotalDur int64 `json:"omitempty,total_dur"`
  77. TotalUtime int64 `json:"omitempty,total_utime"`
  78. }
  79. //OptReport 参数
  80. type OptReport struct {
  81. BizID int64 `form:"business_id" validate:"required"`
  82. FlowID int64 `form:"flow_id"`
  83. UName string `form:"username"`
  84. Bt string `form:"bt"`
  85. Btime time.Time
  86. Et string `form:"et"`
  87. Etime time.Time
  88. Type int8 `form:"type"`
  89. }
  90. //OptReportSubmit 参数
  91. type OptReportSubmit struct {
  92. BizID int64 `form:"business_id" validate:"required"`
  93. FlowID int64 `form:"flow_id"`
  94. Bt string `form:"bt"`
  95. Et string `form:"et"`
  96. Pn string `form:"pn"`
  97. }
  98. //ReportFlowItem 流量
  99. type ReportFlowItem struct {
  100. Hour string `json:"hour"`
  101. In int64 `json:"in"`
  102. Out int64 `json:"out"`
  103. }
  104. //MetaItem .
  105. type MetaItem struct {
  106. DS int64 // 领取
  107. RL int64 // 释放
  108. RP int64 // 通过
  109. ST int64 // 提交
  110. UT int64 // 时长
  111. }
  112. //ReportMeta .
  113. type ReportMeta struct {
  114. Mtime xtime.Time
  115. Content string
  116. UID int64
  117. Type int8
  118. Uname string
  119. }
  120. //Genform 元数据的加工函数,进出审核表格
  121. func Genform(res map[string][]*ReportFlowItem) (form map[string][24]*ReportFlowItem) {
  122. form = make(map[string][24]*ReportFlowItem)
  123. date := func(hour string) (d string, h string) {
  124. d, h = hour[:10], hour[11:]
  125. return
  126. }
  127. emptyflow := func() (res [24]*ReportFlowItem) {
  128. res = [24]*ReportFlowItem{}
  129. for i := 0; i < 24; i++ {
  130. res[i] = &ReportFlowItem{Hour: fmt.Sprintf("%.2d", i)}
  131. }
  132. return res
  133. }
  134. mapcheck := make(map[string]int64) //完全没数据的就不展示了
  135. for uname, arr := range res {
  136. for _, item := range arr {
  137. d, h := date(item.Hour)
  138. hi, _ := strconv.Atoi(h)
  139. key := fmt.Sprintf("%s %s", uname, d)
  140. if arr, ok := form[key]; ok {
  141. arr[hi].In = item.In
  142. arr[hi].Out = item.Out
  143. form[key] = arr
  144. } else {
  145. data := emptyflow()
  146. data[hi].In = item.In
  147. data[hi].Out = item.Out
  148. form[key] = data
  149. }
  150. mapcheck[key] += (item.In + item.Out)
  151. }
  152. }
  153. for k, v := range mapcheck {
  154. if v == 0 {
  155. delete(form, k)
  156. }
  157. }
  158. return
  159. }
  160. //Gentempres 元数据的加工函数,进出审核柱状图1
  161. func Gentempres(opt *OptReport, mnames map[int64]string, metas []*ReportMeta) (tempres map[string]map[int64]*ReportFlowItem) {
  162. var funcin, funcout caculate
  163. if opt.Type == TypeMeta {
  164. funcin = metaIn
  165. funcout = metaOut
  166. } else {
  167. funcin = totalIn
  168. funcout = totalOut
  169. }
  170. tempres = make(map[string]map[int64]*ReportFlowItem)
  171. for _, meta := range metas {
  172. metaM := make(map[string]int64)
  173. if err := json.Unmarshal([]byte(meta.Content), &metaM); err != nil {
  174. log.Error("json.Unmarshal (%s) error(%v)", meta.Content, err)
  175. continue
  176. }
  177. var in, out int64
  178. in += funcin(metaM, meta)
  179. out += funcout(metaM, meta)
  180. hour := meta.Mtime.Time().Format("2006-01-02 15")
  181. item := &ReportFlowItem{
  182. Hour: hour,
  183. In: in,
  184. Out: out,
  185. }
  186. if val, ok := tempres[hour]; ok {
  187. if v, ok := val[meta.UID]; ok {
  188. v.In += in
  189. v.Out += out
  190. tempres[hour][meta.UID] = v
  191. } else {
  192. tempres[hour][meta.UID] = item
  193. }
  194. } else {
  195. tempres[hour] = map[int64]*ReportFlowItem{
  196. meta.UID: item,
  197. }
  198. }
  199. }
  200. return
  201. }
  202. type caculate func(map[string]int64, *ReportMeta) int64
  203. func totalIn(metaM map[string]int64, meta *ReportMeta) (in int64) {
  204. return metaM[In]
  205. }
  206. func totalOut(metaM map[string]int64, meta *ReportMeta) (in int64) {
  207. return metaM[Out]
  208. }
  209. func metaIn(metaM map[string]int64, meta *ReportMeta) (in int64) {
  210. if ds, ok := metaM[Dispatch]; ok { //领取到的
  211. in += ds
  212. }
  213. if rl, ok := metaM[Release]; ok { //释放的
  214. in -= rl
  215. }
  216. return
  217. }
  218. func metaOut(metaM map[string]int64, meta *ReportMeta) (out int64) {
  219. if st, ok := metaM[fmt.Sprintf(Submit, modtask.TaskStateSubmit, meta.UID)]; ok { //本人提交的
  220. out = st
  221. }
  222. return
  223. }
  224. //Genres 元数据的加工函数,进出审核柱状图2
  225. func Genres(opt *OptReport, tempres map[string]map[int64]*ReportFlowItem, mnames map[int64]string) (res map[string][]*ReportFlowItem) {
  226. res = make(map[string][]*ReportFlowItem)
  227. for i := opt.Btime; i.Format("2006-01-02 15") != opt.Etime.Format("2006-01-02 15"); i = i.Add(+1 * time.Hour) {
  228. hour := i.Format("2006-01-02 15")
  229. rt := &ReportFlowItem{
  230. Hour: hour,
  231. }
  232. if val, ok := tempres[hour]; ok {
  233. var tin, tout int64
  234. if opt.Type == TypeMeta {
  235. for uid, uname := range mnames {
  236. if item, ok := val[uid]; ok {
  237. rt = item
  238. tin += item.In
  239. tout += item.Out
  240. } else {
  241. rt.In = 0
  242. rt.Out = 0
  243. }
  244. addtores(res, uname, *rt)
  245. }
  246. } else {
  247. if item, ok := val[0]; ok {
  248. rt = item
  249. tin += item.In
  250. tout += item.Out
  251. }
  252. }
  253. rt.In = tin
  254. rt.Out = tout
  255. addtores(res, "total", *rt)
  256. } else {
  257. addtores(res, "total", *rt)
  258. for _, uname := range mnames {
  259. addtores(res, uname, *rt)
  260. }
  261. }
  262. }
  263. for k, v := range res {
  264. if opt.UName != "" && k != opt.UName {
  265. delete(res, k)
  266. continue
  267. }
  268. var (
  269. insum, outsum = int64(0), int64(0)
  270. )
  271. for _, item := range v {
  272. insum += item.In
  273. outsum += item.Out
  274. }
  275. if insum == 0 && outsum == 0 {
  276. delete(res, k)
  277. }
  278. }
  279. return
  280. }
  281. func addtores(res map[string][]*ReportFlowItem, key string, val ReportFlowItem) {
  282. if total, ok := res[key]; ok {
  283. res[key] = append(total, &val)
  284. } else {
  285. res[key] = []*ReportFlowItem{&val}
  286. }
  287. }
  288. //GenMemberStat 个人24小时统计报表
  289. func GenMemberStat(metas []*ReportMeta, passState int64) (res map[int64][]interface{}, err error) {
  290. tempres := make(map[int64]*MetaItem)
  291. for _, meta := range metas {
  292. metaM := make(map[string]int64)
  293. if err = json.Unmarshal([]byte(meta.Content), &metaM); err != nil {
  294. log.Error("json.Unmarshal (%s) error(%v)", meta.Content, err)
  295. err = nil
  296. continue
  297. }
  298. tmt := &MetaItem{
  299. DS: metaM[Dispatch],
  300. RL: metaM[Release],
  301. RP: metaM[fmt.Sprintf(RscState, passState)],
  302. ST: metaM[fmt.Sprintf(Submit, modtask.TaskStateSubmit, meta.UID)],
  303. UT: metaM[UseTime],
  304. }
  305. if val, ok := tempres[meta.UID]; ok {
  306. val.DS += tmt.DS
  307. val.RL += tmt.RL
  308. val.RP += tmt.RP
  309. val.ST += tmt.ST
  310. val.UT += tmt.UT
  311. } else {
  312. tempres[meta.UID] = tmt
  313. }
  314. }
  315. for uid, v := range tempres {
  316. fmt.Printf("uid:%d v:%+v\n", uid, v)
  317. }
  318. res = make(map[int64][]interface{})
  319. for uid, meta := range tempres {
  320. var (
  321. completerate, passrate, avgtime = "", "", ""
  322. )
  323. total := meta.DS - meta.RL
  324. if total <= 0 {
  325. total = 0
  326. completerate, passrate, avgtime = "0%", "0%", "00:00:00"
  327. } else {
  328. cRate := float32(meta.ST) / float32(total)
  329. pRate := float32(meta.RP) / float32(total)
  330. at := int64(0)
  331. if meta.ST > 0 {
  332. at = meta.UT / meta.ST
  333. }
  334. if cRate < 0.0 || cRate > 1.0 {
  335. completerate = "100%"
  336. } else {
  337. completerate = fmt.Sprintf("%.2f%%", cRate*100)
  338. }
  339. if pRate < 0.0 || pRate > 1.0 {
  340. passrate = "100%"
  341. } else {
  342. passrate = fmt.Sprintf("%.2f%%", pRate*100)
  343. }
  344. if at < 0 {
  345. avgtime = "00:00:00"
  346. } else {
  347. avgtime = common.ParseWaitTime(at)
  348. }
  349. }
  350. res[uid] = []interface{}{total, completerate, passrate, avgtime}
  351. }
  352. return
  353. }