count.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. 'use strict';
  2. const assert = require('assert');
  3. const _ = require('lodash');
  4. const { ObjectId } = require('mongoose').Types;
  5. const moment = require('moment');
  6. const { CrudService } = require('naf-framework-mongoose/lib/service');
  7. const { BusinessError, ErrorCode } = require('naf-core').Error;
  8. class CountService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'count');
  11. this.smodel = this.ctx.model.Student;
  12. this.tmodel = this.ctx.model.Trainplan;
  13. this.lmodel = this.ctx.model.Leave;
  14. this.schmodel = this.ctx.model.School;
  15. this.setmodel = this.ctx.model.Setting;
  16. }
  17. // 查询
  18. async countstudent() {
  19. // levelexit:退出人数 √
  20. // levelqj:请假人数 √
  21. // notrainstu:上传名单,但是未培训人数 student表中的数据不稳,后加的可能没有了.被人绑定更换也可能没有了.所以 这个数字用 student.total - user(type=4&&openid) 的结果 √
  22. // schstu:上传名单人数 该年度计划下,的student.total √
  23. // trainstu:已参加培训人数 user(type==4&&openid).total √
  24. // planstu:年度计划人数(重算) 根据年度计划学校的分配计算 √
  25. // schs:[{schname 学校名称,schnum 学校人数}] 学校上传人数 试用聚合做 √
  26. // 取得当前年份计划信息
  27. const setting = await this.setmodel.findOne();
  28. if (!setting) {
  29. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认设置');
  30. }
  31. const { planid } = setting;
  32. if (!planid) {
  33. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划');
  34. }
  35. const trainPlan = await this.tmodel.findById(planid);
  36. if (!trainPlan) {
  37. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '没有找到默认年度计划');
  38. }
  39. let { termnum } = trainPlan;
  40. if (!_.isArray(termnum)) {
  41. throw new BusinessError(
  42. ErrorCode.DATA_INVALID,
  43. '默认年度计划的期数据格式不正确'
  44. );
  45. }
  46. // 转换下,因为之后用的期id不是ObjectId
  47. termnum = JSON.parse(JSON.stringify(termnum));
  48. const termids = termnum.map(i => i._id);
  49. const data = {};
  50. // 请假,退出
  51. const levelqj = await this.ctx.model.Leave.count({
  52. termid: { $in: termids },
  53. type: '0',
  54. status: '1',
  55. });
  56. const levelexit = await this.ctx.model.Leave.count({
  57. termid: { $in: termids },
  58. type: '1',
  59. status: '1',
  60. });
  61. data.levelqj = levelqj || 0;
  62. data.levelexit = levelexit || 0;
  63. // 参加培训的学生
  64. const trainstuRes = await this.ctx.model.Student.aggregate([
  65. { $addFields: { u_id: { $toString: '$_id' } } },
  66. { $match: { planid } },
  67. {
  68. $lookup: {
  69. from: 'user',
  70. localField: 'u_id',
  71. foreignField: 'uid',
  72. as: 'user',
  73. },
  74. },
  75. { $match: { 'user.type': '4', 'user.openid': { $exists: true } } },
  76. { $count: 'total' },
  77. ]);
  78. const h = _.head(trainstuRes);
  79. const { total: trainstu } = h;
  80. data.trainstu = trainstu;
  81. // 已上传的学生总数
  82. const schstu = await this.ctx.model.Student.count({ planid });
  83. data.schstu = schstu;
  84. // 未参加培训的学生
  85. const notrainstu = schstu - trainstu;
  86. data.notrainstu = notrainstu;
  87. // 年度计划实际人数 这个还没用聚合,不是很优雅
  88. const mid = await this.ctx.model.Schtime.find({ planid });
  89. const planstu = mid.reduce((p, n) => p + n.arrange.reduce((np, nn) => np + (nn.number * 1 || 0), 0), 0);
  90. data.planstu = planstu;
  91. // 各个学校上传的人数
  92. const schs = await this.ctx.model.Student.aggregate([
  93. { $match: { planid } },
  94. { $group: { _id: '$schid', sum: { $sum: 1 } } },
  95. { $lookup: {
  96. from: 'school',
  97. localField: '_id',
  98. foreignField: 'code',
  99. as: 'school',
  100. } },
  101. { $unwind: '$school' },
  102. { $project: { _id: 0, schname: '$school.name', schnum: '$sum' } },
  103. ]);
  104. data.schs = schs;
  105. return data;
  106. }
  107. // 按学校id统计查询
  108. async countschstu({ id }) {
  109. console.log(id);
  110. // 取得当前年份计划信息
  111. console.log(moment().format('YYYY'));
  112. const plan = await this.tmodel.findOne({ year: moment().format('YYYY') });
  113. if (!plan) {
  114. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '当前全年计划不存在');
  115. }
  116. // 根据计划取得当前年份下计划学校培训学生人数
  117. const school = await this.schmodel.findOne({ code: id });
  118. if (!school) {
  119. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '学校信息不存在');
  120. }
  121. const data = {};
  122. data.planstu = school.number;
  123. // 根据学校id取得学校上报的学生数
  124. const schstus = await this.smodel.find({ planid: plan.id, schid: id });
  125. data.schstu = schstus.length;
  126. // 取得已培训的学生数
  127. const trainstu = schstus.filter(item => item.openid);
  128. data.trainstu = trainstu.length;
  129. // 取得内未培训的学生数
  130. const notrainstu = schstus.filter(item => !item.openid);
  131. data.notrainstu = notrainstu.length;
  132. // 取得学生请假数和退出数
  133. const levelstus = [];
  134. // 循环取得所有请假和退出的学生信息
  135. for (const elm of trainstu) {
  136. const level = await this.lmodel.findOne({ studentid: elm.id, status: '1' });
  137. if (level) {
  138. levelstus.push(level);
  139. }
  140. }
  141. // 筛选出请假数和退出数
  142. const levelqj = levelstus.filter(item => item.type === '0');
  143. const levelexit = levelstus.filter(item => item.type === '1');
  144. data.levelqj = levelqj.length;
  145. data.levelexit = levelexit.length;
  146. return data;
  147. }
  148. }
  149. module.exports = CountService;