student.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. 'use strict';
  2. const assert = require('assert');
  3. const _ = require('lodash');
  4. const { ObjectId } = require('mongoose').Types;
  5. const { CrudService } = require('naf-framework-mongoose/lib/service');
  6. const { BusinessError, ErrorCode } = require('naf-core').Error;
  7. class StudentService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'student');
  10. this.model = this.ctx.model.Student;
  11. this.umodel = this.ctx.model.User;
  12. this.tmodel = this.ctx.model.Trainplan;
  13. this.clamodel = this.ctx.model.Class;
  14. this.upmodel = this.ctx.model.Uploadtask;
  15. this.gmodel = this.ctx.model.Group;
  16. this.psmodel = this.ctx.model.Personalscore;
  17. this.gsmodel = this.ctx.model.Groupscore;
  18. }
  19. async create(data) {
  20. const { name, phone: mobile, gender } = data;
  21. const res = await this.model.create(data);
  22. if (res) {
  23. const obj = { name, mobile, gender, type: '4', passwd: '12345678', uid: res._id };
  24. const user = await this.ctx.service.user.create(obj);
  25. }
  26. return res;
  27. }
  28. // 查询
  29. async query({ skip, limit, ...info }) {
  30. const total = await this.model.count(info);
  31. const res = await this.model
  32. .find(info)
  33. .skip(Number(skip))
  34. .limit(Number(limit));
  35. const data = [];
  36. for (const elm of res) {
  37. const plan = await this.tmodel.findOne({
  38. 'termnum._id': ObjectId(elm.termid),
  39. });
  40. const newdata = { ...JSON.parse(JSON.stringify(elm)) };
  41. if (plan) {
  42. const term = await plan.termnum.id(elm.termid);
  43. newdata.termname = term.term;
  44. if (elm.batchid) {
  45. const _batch = await term.batchnum.id(elm.batchid);
  46. newdata.batchname = _batch.batch;
  47. }
  48. }
  49. if (elm.classid) {
  50. const classs = await this.clamodel.findById(elm.classid);
  51. if (classs) {
  52. newdata.classname = classs.name;
  53. }
  54. }
  55. data.push(newdata);
  56. }
  57. const result = { total, data };
  58. return result;
  59. }
  60. // 查询
  61. async seek({ termid, type, batchid, skip, limit }) {
  62. const total = await this.model.count({
  63. termid,
  64. type,
  65. batchid,
  66. $or: [{ classid: null }, { classid: '' }],
  67. });
  68. const data = await this.model
  69. .find({ termid, type, batchid, $or: [{ classid: null }, { classid: '' }] })
  70. .skip(Number(skip))
  71. .limit(Number(limit));
  72. const result = { total, data };
  73. return result;
  74. }
  75. async findbedroom(data) {
  76. const { batchid, classid } = data;
  77. const result = [];
  78. // 如果传的是批次id
  79. if (batchid) {
  80. // 查询该批次下的所有学生
  81. const students = await this.model.find({ batchid });
  82. const bedroomList = new Set();
  83. // 查询该批次的所有寝室号
  84. for (const student of students) {
  85. bedroomList.add(student.bedroom);
  86. }
  87. let studentList = [];
  88. // 查询该批次所有寝室下的学生名单
  89. for (const bedroom of bedroomList) {
  90. const newstudents = await this.model.find({ bedroom });
  91. for (const newstudent of newstudents) {
  92. studentList.push(newstudent.name);
  93. }
  94. result.push({ bedroom, studentList });
  95. studentList = [];
  96. }
  97. }
  98. // 如果传的是班级id
  99. if (classid) {
  100. // 查询该班级所有学生
  101. const students = await this.model.find({ classid });
  102. const bedroomList = new Set();
  103. // 查询该班级所有寝室号
  104. for (const student of students) {
  105. bedroomList.add(student.bedroom);
  106. }
  107. let studentList = [];
  108. // 查询该班级所有寝室的学生名单
  109. for (const bedroom of bedroomList) {
  110. const newstudents = await this.model.find({ bedroom });
  111. for (const newstudent of newstudents) {
  112. // 如果寝室中有非本班级学生(混寝),则过滤掉不予显示
  113. if (newstudent.classid === classid) {
  114. studentList.push(newstudent.name);
  115. }
  116. }
  117. result.push({ bedroom, studentList });
  118. studentList = [];
  119. }
  120. }
  121. return result;
  122. }
  123. async upjob(data) {
  124. const { stuid, job } = data;
  125. const student = await this.model.findById(stuid);
  126. student.job = job;
  127. if (job === '班长' || job === '学委') {
  128. const user = await this.umodel.findOne({ uid: stuid, type: '4' });
  129. const date = await this.ctx.service.util.updatedate();
  130. const openid = user.openid;
  131. const detail = '你已被班主任设置为' + job + ',请及时登录查看';
  132. const remark = '感谢您的使用';
  133. if (openid) {
  134. this.ctx.service.weixin.sendTemplateMsg(
  135. this.ctx.app.config.REVIEW_TEMPLATE_ID,
  136. openid,
  137. '您有一个新的通知',
  138. detail,
  139. date,
  140. remark
  141. );
  142. }
  143. }
  144. return await student.save();
  145. }
  146. // 根据学生id删除班级
  147. async deleteclass(data) {
  148. for (const el of data) {
  149. const student = await this.model.findById(el);
  150. if (student) {
  151. student.classid = '';
  152. await student.save();
  153. }
  154. }
  155. }
  156. // 根据班级id查出班级各个学生的分数
  157. async findscore({ skip, limit, ...info }) {
  158. const { classid } = info;
  159. const total = await this.model.count(info);
  160. const students = await this.model
  161. .find(info)
  162. .skip(Number(skip))
  163. .limit(Number(limit));
  164. const data = [];
  165. const groups = await this.gmodel.find({ classid });
  166. for (const student of students) {
  167. const _student = JSON.parse(JSON.stringify(student));
  168. const group = groups.find(item =>
  169. item.students.find(stuinfo => stuinfo.stuid === _student.id)
  170. );
  171. console.log(group);
  172. if (group) {
  173. _student.groupscore = group.score;
  174. }
  175. const tasks = await this.upmodel.find({ studentid: _student.id });
  176. _student.tasks = tasks;
  177. data.push(_student);
  178. }
  179. return { total, data };
  180. }
  181. async findbystuids({ data }) {
  182. const res = [];
  183. for (const stuid of data) {
  184. const stu = await this.model.findById(stuid);
  185. if (stu)res.push(stu);
  186. }
  187. return res;
  188. }
  189. // 根据学生id删除学生
  190. async deletestus(data) {
  191. for (const el of data) {
  192. await this.model.deleteOne({ _id: ObjectId(el) });
  193. }
  194. }
  195. // 批量更新寝室号
  196. async updatabedroom(data) {
  197. for (const el of data) {
  198. const student = await this.model.findById(el.id);
  199. if (student) {
  200. student.bedroom = el.bedroom;
  201. await student.save();
  202. }
  203. }
  204. }
  205. /**
  206. * 计算班级的优秀学生
  207. * 规则:班级干部(学生的job!=='普通学生'),检查是否有评优资格(is_fine_status==='0'可以评优),全部评优;
  208. * 普通学生取总成绩前10的人评优(非10位并列时,名额该占用就占用;第10名若有并列,就全都要)
  209. * @param {String} param0 {id=>班级id}
  210. */
  211. async getFineStudent({ id: classid }) {
  212. // 获取班级学生列表
  213. let studentList = await this.model.find({ classid });
  214. // 重置评优,干部全优秀
  215. studentList = studentList.map(i => {
  216. if (i.job.includes('普通')) i.is_fine = '1';
  217. else i.is_fine = '0';
  218. return i;
  219. });
  220. // 初始化后取出不需要算的人,他们就这样,没必要算
  221. const reverseList = studentList.filter(f => !(f.is_fine !== '2' && f.job.includes('普通')));
  222. // 过滤出取消评优资格的学生和干部;干部就是优秀;被取消资格就别凑热闹了
  223. studentList = studentList.filter(f => f.is_fine !== '2' && f.job.includes('普通'));
  224. // 获取平时分
  225. const dailyScoreList = await this.psmodel.find({ classid });
  226. studentList = this.dealScoreList(dailyScoreList, studentList);
  227. // 获取作业分
  228. const taskScoreList = await this.upmodel.find({ classid });
  229. studentList = this.dealScoreList(taskScoreList, studentList);
  230. // 获取小组分,小组
  231. const groupList = await this.gmodel.find({ classid });
  232. const groupScoreList = await this.gsmodel.find({ classid });
  233. studentList = this.dealGroupScoreList(groupList, groupScoreList, studentList);
  234. studentList = studentList.sort((a, b) => (b.score * 1 || 0) - (a.score * 1 || 0));
  235. // 排名
  236. // eslint-disable-next-line no-unused-vars
  237. let num = 0;
  238. for (const student of studentList) {
  239. // 先判断是否超过第10位,超过就跳出
  240. if (num > 10) break;
  241. const { score, is_fine } = student;
  242. // 最开始初始化过所有人的状态,并且将干部和不能评优的人都过滤出去,所以正常学生应该都是没有评优,如果此处已经是优秀,那么就是和前人同分改的,直接跳过就好
  243. if (is_fine === '1') continue;
  244. // 没有分凑什么热闹
  245. if (!score) continue;
  246. let plus = 1; // 这轮有多少人,到这了,这个人肯定是要改了,所以默认1
  247. // 评优
  248. student.is_fine = '1';
  249. const rlist = studentList.filter(f => f.score === score);
  250. // 处理同分的人也都变成is_fine
  251. for (const stud of rlist) {
  252. stud.is_fine = '1';
  253. const sindex = studentList.findIndex(f => ObjectId(stud._id).equals(f._id));
  254. if (sindex >= 0) {
  255. studentList[sindex] = stud;
  256. plus++;
  257. }
  258. }
  259. // num+plus,算下num
  260. num = num + plus;
  261. }
  262. // 算完的和不用算的合并,提交
  263. const lastList = [ ...studentList, ...reverseList ];
  264. for (const student of lastList) {
  265. const res = await student.save();
  266. // const { meta, ...data } = student;
  267. // const r = await this.model.findByIdAndUpdate(
  268. // { _id: ObjectId(student._id) },
  269. // data
  270. // );
  271. console.log(res);
  272. }
  273. }
  274. /**
  275. * 将分数放到学生身上
  276. * @param {Array} scoreList 班级的分数列表
  277. * @param {Array} studentList 学生列表
  278. */
  279. dealScoreList(scoreList, studentList) {
  280. scoreList = _.groupBy(scoreList, 'studentid');
  281. studentList = studentList.map(i => {
  282. const slist = scoreList[i._id];
  283. if (slist)i.score = (i.score * 1 || 0) + slist.reduce((p, n) => p + (n.score * 1 || 0), 0);
  284. return i;
  285. });
  286. return studentList;
  287. }
  288. /**
  289. * 将 学生所在 组的 团队平均分 + 到学生身上
  290. * @param {Array} groupList 班级的小组的列表
  291. * @param {Array} scoreList 所有小组的分数列表
  292. * @param {Array} studentList 学生列表
  293. */
  294. dealGroupScoreList(groupList, scoreList, studentList) {
  295. // console.log(groupList);
  296. scoreList = _.groupBy(scoreList, 'groupid');
  297. // 算出每组的平均分,之后加给学生
  298. groupList = groupList.map(i => {
  299. const { students } = i;
  300. if (students.length > 0) {
  301. const slist = scoreList[i._id];
  302. if (slist) {
  303. i.score = slist.reduce((p, n) => p + (n.score * 1 || 0), 0);
  304. i.score = _.floor(_.divide(i.score, students.length), 2);
  305. }
  306. }
  307. return i;
  308. });
  309. // 每个学生加自己的组的平均分
  310. studentList = studentList.map(i => {
  311. const r = groupList.find(f => f.students.find(sf => ObjectId(sf.stuid).equals(i._id)));
  312. if (r) i.score = (i.score * 1 || 0) + (r.score * 1 || 0);
  313. return i;
  314. });
  315. return studentList;
  316. }
  317. }
  318. module.exports = StudentService;