bedroom.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 BedroomService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'bedroom');
  10. this.model = this.ctx.model.Bedroom;
  11. this.smodel = this.ctx.model.Student;
  12. this.tmodel = this.ctx.model.Trainplan;
  13. this.cmodel = this.ctx.model.Class;
  14. this.umodel = this.ctx.model.User;
  15. this.ctmodel = this.ctx.model.Classtype;
  16. this.nmodel = this.ctx.model.Notice;
  17. }
  18. async query({ code, ...data } = {}, { skip = 0, limit = 0 } = {}) {
  19. const query = { ...data };
  20. if (code) {
  21. query.code = { $regex: code };
  22. }
  23. const res = await this.model.find(query).skip(parseInt(skip)).limit(parseInt(limit));
  24. return res;
  25. }
  26. async count({ code, ...data } = {}) {
  27. const query = { ...data };
  28. if (code) {
  29. query.code = { $regex: code };
  30. }
  31. const res = await this.model.count(query);
  32. return res;
  33. }
  34. // 根据班级id查找班级下所有寝室列表并查询出寝室下学生信息
  35. async roomstu({ id }) {
  36. // 通过班级id查询学生表信息
  37. const students = await this.smodel.find({ classid: id });
  38. const _bedrooms = _.map(students, 'bedroom');
  39. // 取得无重复的寝室号
  40. const bedrooms = _.uniq(_bedrooms);
  41. const data = [];
  42. // 根据寝室号 取得相应的学生信息
  43. for (const elm of bedrooms) {
  44. const stus = students.filter(item => item.bedroom === elm);
  45. const newdata = { bedroom: elm, stus };
  46. data.push(newdata);
  47. }
  48. return data;
  49. }
  50. async ibeacon(data) {
  51. assert(data.openid, '用户信息不能为空');
  52. // 通过openid取得学生信息
  53. const user = await this.ctx.service.user.findByOpenid(data.openid);
  54. if (!user) {
  55. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '用户不存在');
  56. }
  57. const student = await this.smodel.findById(user.uid);
  58. if (!student) {
  59. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '学生信息不存在');
  60. }
  61. const beedroom = await this.model.findOne({ code: student.bedroom });
  62. if (!beedroom) {
  63. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '寝室信息不存在');
  64. }
  65. return { data: { ibeacon: beedroom.ibeacon } };
  66. }
  67. // 一键分寝
  68. async apart(data) {
  69. const { trainplanid, termid, batchid } = data;
  70. assert(trainplanid, 'trainplanid不能为空');
  71. assert(termid, 'termid不能为空');
  72. assert(batchid, 'batchid不能为空');
  73. // 根据计划id取得当前计划
  74. const trainplan = await this.tmodel.findById(trainplanid);
  75. // 根据期id取得当前期信息
  76. const term = trainplan.termnum.find(p => p.id === termid);
  77. // 根据批次id查询批次信息
  78. const _batch = term.batchnum.find(p => p.id === batchid);
  79. // 查询所有寝室列表
  80. const bedroomList = await this.model
  81. .find({ batch: _batch.batch, status: '0' })
  82. .sort({ floor: -1 });
  83. // 循环所有当前批次下的寝室列表进行分寝处理
  84. const studentList = await this.getstudents(termid, batchid);
  85. for (const bedroom of bedroomList) {
  86. // 判断当前寝室号是否已有
  87. // 根据期id查找所有当期学生列表
  88. const _stu = _.filter(studentList, { bedroom: bedroom.code });
  89. if (bedroom.number !== _stu.length) {
  90. let i = 0;
  91. let _gender = '';
  92. for (const stud of studentList) {
  93. if (stud.bedroom) {
  94. if (stud.bedroom === bedroom.code) {
  95. i = i + 1;
  96. }
  97. continue;
  98. }
  99. if (i === 0) {
  100. if (!bedroom.gender) {
  101. stud.bedroomid = bedroom.id;
  102. stud.bedroom = bedroom.code;
  103. await stud.save();
  104. i = i + 1;
  105. _gender = stud.gender;
  106. } else {
  107. if (bedroom.gender === stud.gender) {
  108. stud.bedroomid = bedroom.id;
  109. stud.bedroom = bedroom.code;
  110. await stud.save();
  111. i = i + 1;
  112. _gender = stud.gender;
  113. }
  114. }
  115. } else if (i < bedroom.number) {
  116. if (_gender === stud.gender) {
  117. stud.bedroomid = bedroom.id;
  118. stud.bedroom = bedroom.code;
  119. await stud.save();
  120. i = i + 1;
  121. }
  122. } else if (i === bedroom.number) {
  123. i = 0;
  124. break;
  125. }
  126. }
  127. }
  128. }
  129. // 取得当前批次的所有班级
  130. const classes = await this.cmodel.find({ batchid });
  131. const detail = '班级学生名单与寝室安排已确认,请及时查收';
  132. const nres = await this.nmodel.create({
  133. planyearid: trainplan.planyearid,
  134. planid: trainplanid,
  135. termid,
  136. noticeid: 'system',
  137. content: detail,
  138. type: '5',
  139. });
  140. for (const _class of classes) {
  141. // 取得每个班级的班主任id
  142. const headteacherid = _class.headteacherid;
  143. const headteacher = await this.umodel.findOne({
  144. uid: headteacherid,
  145. type: '1',
  146. });
  147. if (headteacher && headteacher.openid) {
  148. const openid = headteacher.openid;
  149. const remark = '感谢您的使用';
  150. const date = await this.ctx.service.util.updatedate();
  151. this.ctx.service.weixin.sendTemplateMsg(
  152. this.ctx.app.config.REVIEW_TEMPLATE_ID,
  153. openid,
  154. '您有一个新的通知',
  155. detail,
  156. date,
  157. remark,
  158. _class.id
  159. );
  160. nres.notified.push({
  161. notifiedid: headteacher.uid,
  162. username: headteacher.name,
  163. });
  164. }
  165. await nres.save();
  166. }
  167. }
  168. // 取得符合条件的学生列表
  169. async getstudents(termid, batchid) {
  170. // 根据期id查找所有当期学生列表
  171. const cltype = await this.ctmodel.find({ bedroom: '0' });
  172. const types = _.map(cltype, 'code');
  173. const studentList = await this.smodel
  174. .find({ termid, batchid, type: { $in: types } })
  175. .sort({ gender: -1 });
  176. return studentList;
  177. }
  178. // 取得符合条件的学生列表
  179. async getbedroomstudents(termid, batchid, bedroom) {
  180. // 根据期id查找所有当期学生列表
  181. const studentList = await this.smodel.find({ termid, batchid, bedroom });
  182. return studentList;
  183. }
  184. // 新 分配寝室查询可以的列表
  185. async getAssignRoom({ termid }) {
  186. const bedroomList = await this.model.find();
  187. const stuList = await this.smodel.find({ termid });
  188. const stuBedIdGroup = _.groupBy(stuList, 'bedroomid');
  189. const keys = Object.keys(stuBedIdGroup);
  190. // 过滤出没有人的寝室
  191. let noperson = bedroomList.filter(f => !(keys.find(k => {
  192. if (k === undefined || k === 'undefined' || k === null || k === 'null') return false;
  193. return ObjectId(k).equals(f._id);
  194. })));
  195. noperson = JSON.parse(JSON.stringify(noperson));
  196. const nopersonList = [];
  197. for (const i of noperson) {
  198. const n = `${i.code}(${i.number}人)`;
  199. const obj = { ...i, name: n };
  200. nopersonList.push(obj);
  201. }
  202. const havepersonList = [];
  203. for (const key of keys) {
  204. if (key === undefined || key === 'undefined' || key === null || key === 'null') continue;
  205. // 取出分组后,以寝室id为key的学生列表
  206. const list = stuBedIdGroup[key];
  207. // 找到寝室obj
  208. const bedroom = bedroomList.find(f => ObjectId(key).equals(f._id));
  209. // 找不到寝室就算了,下一个吧
  210. if (!bedroom) continue;
  211. // 找到这个寝室人数限制
  212. const { number } = bedroom;
  213. // 超出,等于限制人数,继续下个寝室
  214. if (list.length >= number * 1) continue;
  215. // 这个寝室人没满,需要组织数据了
  216. const { _id, code, floor } = bedroom;
  217. const elsenum = number * 1 - list.length;
  218. const stu = _.head(list);
  219. const { gender } = stu;
  220. let ncode = `${code}(`;
  221. if (elsenum) ncode = `${ncode} 剩余${elsenum}人`;
  222. if (gender) ncode = `${ncode} ${gender}性`;
  223. if (floor)ncode = `${ncode} ${floor}楼`;
  224. ncode = `${ncode})`;
  225. const obj = { _id, code, name: ncode };
  226. havepersonList.push(obj);
  227. }
  228. return [ ...nopersonList, ...havepersonList ];
  229. }
  230. // 批量修改学生寝室(新) TODO,需要添加期id,然后找这个寝室,这期同学是否占满/性别错误的问题
  231. async updateStudent(data, body) {
  232. const { code, ids, bedroomid, termid } = body;
  233. const bedroom = await this.model.findById(bedroomid);
  234. if (!bedroom) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '不存在该寝室');
  235. let { number, gender } = bedroom;
  236. // 找到多少人在这个寝室
  237. const inRoom = await this.ctx.model.Student.find({ termid, bedroomid });
  238. const ifTotal = inRoom.length * 1 + ids.length;
  239. if (ifTotal > number * 1) throw new BusinessError(ErrorCode.BUSINESS, `超出人数,该寝室人最多为${number}人`);
  240. if (!gender) {
  241. // 寝室没设置性别,从这个寝室的学生中取出性别
  242. const stu = _.head(inRoom);
  243. gender = _.trim(_.get(stu, 'gender'));
  244. }
  245. const selectStuList = await this.ctx.model.Student.find({ _id: ids.map(i => ObjectId(i)) });
  246. for (const id of ids) {
  247. const r = await this.ctx.model.Student.findById(id);
  248. // 性别查询,是否有误
  249. const { gender: sg, name } = r;
  250. // 寝室或有已入住学生,产生的性别结果,
  251. if (!gender) {
  252. r.bedroom = code;
  253. r.bedroomid = bedroomid;
  254. await r.save();
  255. } else {
  256. if (sg && sg.includes(gender)) {
  257. // 有性别判断
  258. r.bedroom = code;
  259. r.bedroomid = bedroomid;
  260. await r.save();
  261. } else {
  262. throw new BusinessError(
  263. ErrorCode.BusinessError,
  264. `${name} 与该寝室已分配的学生性别不符!`
  265. );
  266. }
  267. }
  268. }
  269. }
  270. async restore({ id }) {
  271. await this.smodel.updateMany({ classid: id }, { bedroomid: undefined, bedroom: undefined });
  272. }
  273. }
  274. module.exports = BedroomService;