statistics.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. package api
  2. import (
  3. "context"
  4. "copter-train/db/model"
  5. "copter-train/db/repo"
  6. "errors"
  7. "fmt"
  8. "strconv"
  9. "time"
  10. "github.com/gin-gonic/gin"
  11. "go.mongodb.org/mongo-driver/bson"
  12. "go.mongodb.org/mongo-driver/mongo"
  13. )
  14. // 本年每月学习时长
  15. func StatisticsLearnProcess(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  16. db := c.Param("scope")
  17. if len(db) == 0 {
  18. return nil, errors.New("scope不能为空")
  19. }
  20. // 如果没有uid参数,则查询当前用户的
  21. uid := c.Query("uid")
  22. if len(uid) == 0 {
  23. uid = apictx.User.ID
  24. }
  25. _type := c.Query("type")
  26. // 如果没有年份参数,则查询当前年份的
  27. _year := c.Query("year")
  28. year := 2024
  29. if len(_year) == 0 {
  30. year = time.Now().Year()
  31. } else {
  32. year_, err := strconv.Atoi(_year)
  33. if err != nil {
  34. return nil, errors.New("year参数错误")
  35. }
  36. year = year_
  37. }
  38. fmt.Println("year:", year)
  39. colls := apictx.CreateRepoCtx().Client.GetDbCollection(db, repo.CollectionLearnLog)
  40. return AggregateMonthlyLearnTime(colls, uid, _type, year)
  41. }
  42. // 整个模块的学习时长 不需要cid约束
  43. func AggregateMonthlyLearnTime(colls *mongo.Collection, uid string, learnType string, year int) ([]bson.M, error) {
  44. chinaTimeZone := time.FixedZone("CST", 8*60*60) // 中国时区
  45. pipeline := mongo.Pipeline{
  46. // {
  47. // {Key: "$addFields", Value: bson.D{
  48. // {Key: "dateParts", Value: bson.D{
  49. // {Key: "$dateToParts", Value: bson.M{
  50. // "date": "$createTime",
  51. // "timezone": "Asia/Shanghai",
  52. // }},
  53. // }},
  54. // }},
  55. // },
  56. // {
  57. // {Key: "$match", Value: bson.D{
  58. // {Key: "uid", Value: uid},
  59. // {Key: "dateParts.year", Value: year},
  60. // // {Key: "dateParts.month", Value: bson.D{
  61. // // {Key: "$gte", Value: 1},
  62. // // {Key: "$lt", Value: 13},
  63. // // }},
  64. // }},
  65. // },
  66. // {
  67. // {Key: "$project", Value: bson.D{
  68. // {Key: "month", Value: bson.D{
  69. // {Key: "$month", Value: "$createTime"},
  70. // }},
  71. // {Key: "learnTime", Value: 1},
  72. // }},
  73. // },
  74. // {
  75. // {Key: "$group", Value: bson.D{
  76. // {Key: "_id", Value: "$month"},
  77. {
  78. {Key: "$match", Value: bson.D{
  79. {Key: "createTime", Value: bson.D{
  80. {Key: "$gte", Value: time.Date(year, time.January, 1, 0, 0, 0, 0, chinaTimeZone)},
  81. {Key: "$lt", Value: time.Date(year+1, time.January, 1, 0, 0, 0, 0, chinaTimeZone)},
  82. }},
  83. }},
  84. },
  85. // 将 createTime 字段分解为年和月
  86. {
  87. {Key: "$addFields", Value: bson.D{
  88. // {"year", bson.D{{"$year", bson.D{{"$add", []interface{}{"$createTime", 8 * 60 * 60 * 1000}}}}}},
  89. {Key: "month", Value: bson.D{{Key: "$month", Value: bson.D{{Key: "$add", Value: []interface{}{"$createTime", 8 * 60 * 60 * 1000}}}}}},
  90. }},
  91. },
  92. // 按年和月分组,并计算每个月的正确和错误数量
  93. {
  94. {Key: "$group", Value: bson.D{
  95. {Key: "_id", Value: "$month"},
  96. {Key: "totalLearnTime", Value: bson.D{
  97. {Key: "$sum", Value: "$learnTime"},
  98. }},
  99. }},
  100. },
  101. {
  102. {Key: "$sort", Value: bson.D{
  103. {Key: "_id", Value: 1},
  104. }},
  105. },
  106. }
  107. cursor, err := colls.Aggregate(context.TODO(), pipeline)
  108. if err != nil {
  109. return nil, err
  110. }
  111. var results []bson.M
  112. if err = cursor.All(context.TODO(), &results); err != nil {
  113. return nil, err
  114. }
  115. return results, nil
  116. }
  117. // 个人:上次学习时长
  118. // 获取最新一条数据
  119. func StatisticsLastLearnTime(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  120. db := c.Param("scope")
  121. if len(db) == 0 {
  122. return nil, errors.New("scope不能为空")
  123. }
  124. // 如果没有uid参数,则查询当前用户的
  125. uid := c.Query("uid")
  126. if len(uid) == 0 {
  127. uid = apictx.User.ID
  128. }
  129. learnLog := &model.LearnLog{}
  130. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  131. Db: db,
  132. CollectName: repo.CollectionLearnLog,
  133. Query: repo.Map{"uid": uid},
  134. Sort: bson.M{"createTime": -1},
  135. }, learnLog)
  136. if err != nil {
  137. return nil, err
  138. }
  139. if !found {
  140. return 0, nil
  141. }
  142. return learnLog.LearnTime, nil
  143. }
  144. // 个人:用户总学习时长
  145. func StatisticsTotalLearnTime(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  146. db := c.Param("scope")
  147. if len(db) == 0 {
  148. return nil, errors.New("scope不能为空")
  149. }
  150. // 如果没有uid参数,则查询当前用户的
  151. uid := c.Query("uid")
  152. if len(uid) == 0 {
  153. uid = apictx.User.ID
  154. }
  155. colls := apictx.CreateRepoCtx().Client.GetDbCollection(db, repo.CollectionLearnLog)
  156. return AggregateTotalLearnTime(colls, uid)
  157. }
  158. // 查询用户学习总时长
  159. func AggregateTotalLearnTime(colls *mongo.Collection, uid string) (int, error) {
  160. pipeline := mongo.Pipeline{
  161. {
  162. {Key: "$match", Value: bson.D{
  163. {Key: "uid", Value: uid},
  164. }},
  165. },
  166. {
  167. {Key: "$group", Value: bson.D{
  168. {Key: "_id", Value: "$uid"},
  169. {Key: "totalLearnTime", Value: bson.D{
  170. {Key: "$sum", Value: "$learnTime"},
  171. }},
  172. }},
  173. },
  174. }
  175. cursor, err := colls.Aggregate(context.TODO(), pipeline)
  176. if err != nil {
  177. return 0, err
  178. }
  179. var results []bson.M
  180. if err = cursor.All(context.TODO(), &results); err != nil {
  181. return 0, err
  182. }
  183. if len(results) > 0 {
  184. if v, ok := results[0]["totalLearnTime"].(int32); ok {
  185. return int(v), nil
  186. }
  187. return 0, nil
  188. }
  189. return 0, nil
  190. }
  191. // 个人: 获取最后一场考试的成绩
  192. func StatisticsLastExeamScore(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  193. db := c.Param("scope")
  194. if len(db) == 0 {
  195. return nil, errors.New("scope不能为空")
  196. }
  197. // 如果没有uid参数,则查询当前用户的
  198. uid := c.Query("uid")
  199. if len(uid) == 0 {
  200. uid = apictx.User.ID
  201. }
  202. exeamLog := &model.ExeamLog{}
  203. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  204. Db: db,
  205. CollectName: repo.CollectionExeamLog,
  206. Query: repo.Map{"uid": uid},
  207. Sort: bson.M{"createTime": -1},
  208. }, exeamLog)
  209. if err != nil {
  210. return nil, err
  211. }
  212. if !found {
  213. return 0, nil
  214. }
  215. fmt.Println(exeamLog)
  216. return exeamLog.Score, nil
  217. }
  218. // 个人: 获取历史最好成绩
  219. func StatisticsBestExeamScore(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  220. db := c.Param("scope")
  221. if len(db) == 0 {
  222. return nil, errors.New("scope不能为空")
  223. }
  224. // 如果没有uid参数,则查询当前用户的
  225. uid := c.Query("uid")
  226. if len(uid) == 0 {
  227. uid = apictx.User.ID
  228. }
  229. exeamLog := &model.ExeamLog{}
  230. found, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  231. Db: db,
  232. CollectName: repo.CollectionExeamLog,
  233. Query: repo.Map{"uid": uid},
  234. Sort: bson.M{"score": -1},
  235. }, exeamLog)
  236. if err != nil {
  237. return nil, err
  238. }
  239. if !found {
  240. return 0, nil
  241. }
  242. return exeamLog.Score, nil
  243. }
  244. // 个人: 已学习模块数
  245. // 统计各个模块的学习总时长,根据总时长时间判断是否已学习
  246. // 只需要返回统计各个模块的时长汇总,cid相同的为同一个模块
  247. func StatisticsLearnedModules(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  248. db := c.Param("scope")
  249. if len(db) == 0 {
  250. return nil, errors.New("scope不能为空")
  251. }
  252. // 如果没有uid参数,则查询当前用户的
  253. uid := c.Query("uid")
  254. if len(uid) == 0 {
  255. uid = apictx.User.ID
  256. }
  257. colls := apictx.CreateRepoCtx().Client.GetDbCollection(db, repo.CollectionLearnLog)
  258. pipeline := mongo.Pipeline{
  259. {
  260. {Key: "$match", Value: bson.D{
  261. {Key: "uid", Value: uid},
  262. }},
  263. },
  264. {
  265. {Key: "$group", Value: bson.D{
  266. {Key: "_id", Value: "$cid"},
  267. {Key: "totalLearnTime", Value: bson.D{{Key: "$sum", Value: "$learnTime"}}},
  268. }},
  269. },
  270. }
  271. cursor, err := colls.Aggregate(apictx.CreateRepoCtx().Ctx, pipeline)
  272. if err != nil {
  273. return nil, err
  274. }
  275. var results []bson.M
  276. if err = cursor.All(apictx.CreateRepoCtx().Ctx, &results); err != nil {
  277. return nil, err
  278. }
  279. return results, nil
  280. }
  281. // 个人: 统计用户本年每月考核正确和错误数
  282. func StatisticsExeamTFRate(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  283. db := c.Param("scope")
  284. if len(db) == 0 {
  285. return nil, errors.New("scope不能为空")
  286. }
  287. // 如果没有uid参数,则查询当前用户的
  288. uid := c.Query("uid")
  289. if len(uid) == 0 {
  290. uid = apictx.User.ID
  291. }
  292. _year := c.Query("year")
  293. year := 2024
  294. if len(_year) == 0 {
  295. year = time.Now().Year()
  296. } else {
  297. year_, err := strconv.Atoi(_year)
  298. if err != nil {
  299. return nil, errors.New("year参数错误")
  300. }
  301. year = year_
  302. }
  303. fmt.Println(year)
  304. colls := apictx.CreateRepoCtx().Client.GetDbCollection(db, repo.CollectionExeamLog)
  305. chinaTimeZone := time.FixedZone("CST", 8*60*60) // 中国时区
  306. fmt.Println(uid)
  307. pipeline := mongo.Pipeline{
  308. // 筛选出特定时间范围的记录
  309. {
  310. {Key: "$match", Value: bson.D{
  311. {Key: "createTime", Value: bson.D{
  312. {Key: "$gte", Value: time.Date(year, time.January, 1, 0, 0, 0, 0, chinaTimeZone)},
  313. {Key: "$lt", Value: time.Date(year+1, time.January, 1, 0, 0, 0, 0, chinaTimeZone)},
  314. }},
  315. }},
  316. },
  317. // 将 createTime 字段分解为年和月
  318. {
  319. {Key: "$addFields", Value: bson.D{
  320. // {"year", bson.D{{"$year", bson.D{{"$add", []interface{}{"$createTime", 8 * 60 * 60 * 1000}}}}}},
  321. {Key: "month", Value: bson.D{{Key: "$month", Value: bson.D{{Key: "$add", Value: []interface{}{"$createTime", 8 * 60 * 60 * 1000}}}}}},
  322. }},
  323. },
  324. // 按年和月分组,并计算每个月的正确和错误数量
  325. {
  326. {Key: "$group", Value: bson.D{
  327. {Key: "_id", Value: "$month"},
  328. {Key: "correct", Value: bson.D{{Key: "$sum", Value: "$correct"}}},
  329. {Key: "error", Value: bson.D{{Key: "$sum", Value: "$error"}}},
  330. }},
  331. },
  332. // 排序结果
  333. {
  334. {Key: "$sort", Value: bson.D{{Key: "_id", Value: 1}}},
  335. },
  336. }
  337. cursor, err := colls.Aggregate(context.TODO(), pipeline)
  338. if err != nil {
  339. return nil, err
  340. }
  341. var results []bson.M
  342. if err = cursor.All(apictx.CreateRepoCtx().Ctx, &results); err != nil {
  343. return nil, err
  344. }
  345. return results, nil
  346. }