class.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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 ClassService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'class');
  10. this.model = this.ctx.model.Class;
  11. this.stumodel = this.ctx.model.Student;
  12. this.lessmodel = this.ctx.model.Lesson;
  13. this.umodel = this.ctx.model.User;
  14. this.tmodel = this.ctx.model.Trainplan;
  15. this.gmodel = this.ctx.model.Group;
  16. this.heamodel = this.ctx.model.Headteacher;
  17. this.teamodel = this.ctx.model.Teacher;
  18. this.locamodel = this.ctx.model.Location;
  19. }
  20. async divide(data) {
  21. // 21-04-27重做
  22. const { planid, termid } = data;
  23. assert(planid, '计划id为必填项');
  24. assert(termid, '期id为必填项');
  25. // 先自动生成班级 TODO:之后放开
  26. await this.autoclass(planid, termid);
  27. // 根据计划id与期id查询所有批次下的班级
  28. const newclass = await this.model.find({ planid, termid });
  29. if (!newclass) {
  30. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '班级信息不存在');
  31. }
  32. // 根据计划和期查询所有上报的学生 并按照学校排序
  33. const newstudent = await this.stumodel.find({ termid }).sort({ schid: 1 });
  34. if (!newstudent) {
  35. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '学生信息不存在');
  36. }
  37. // 按批次分组,每个批次处理自己的
  38. const claGroup = _.groupBy(newclass, 'batchid');
  39. const keys = Object.keys(claGroup);
  40. const result = {}; // key:班级id;value:学生id数组
  41. const pList = []; // 补人结果
  42. // 循环批次
  43. for (const bkey of keys) {
  44. const classList = claGroup[bkey]; // 该批次下的班级列表
  45. const batchStudentList = _.shuffle(newstudent.filter(f => f.batchid === bkey)); // shuffle:打乱顺序 该批次下的学生列表
  46. // 分为多个学校 男/女 数组
  47. // 按学校分组
  48. const sgroup = _.groupBy(batchStudentList, 'schid');
  49. // 学校代码key
  50. const schKeys = Object.keys(sgroup);
  51. let solve = {};
  52. const studentGroup = {}; // key:学校id-boy/girl;value:对应学校,性别的学生列表
  53. const classnum = classList.length; // 班级数
  54. const minClass = _.minBy(classList, i => parseInt(i.number)); // 该批次人数最少的班级
  55. let minNumber = 0;
  56. if (minClass) minNumber = parseInt(minClass.number);
  57. for (const skey of schKeys) {
  58. const schstus = sgroup[skey];
  59. // 获得每个学校的男/女人数
  60. const boys = schstus.filter(f => f.gender.includes('男'));
  61. const girls = schstus.filter(f => f.gender.includes('女'));
  62. studentGroup[`${skey}-boy`] = boys;
  63. studentGroup[`${skey}-girl`] = girls;
  64. // 算出平均分配解:每个 学校 固定向 每个班 派多少 男/女生
  65. // 需要验证最少的班级人数:因为平均后,可能造成人多了,要吐出来的
  66. const br = this.numDivide(boys.length, classnum);
  67. const gr = this.numDivide(girls.length, classnum);
  68. // 存入最佳计算结果,但是需要验证,看看这批次的计算结果是否<=班级最少人数;多了可是要吐人的.吐人的写法代码更多
  69. solve[`${skey}-boy`] = br;
  70. solve[`${skey}-girl`] = gr;
  71. }
  72. // 验证最佳结果是否超出班级的最少人数,不是,则处理
  73. solve = this.checkSolve(solve, minNumber, classnum);
  74. console.log(solve);
  75. // 塞人
  76. for (const c of classList) {
  77. const { _id } = c;
  78. if (!(result[_id] && _.isArray(result[_id]))) result[_id] = [];
  79. for (const key in solve) {
  80. const { res } = solve[key];
  81. let sList = studentGroup[key];
  82. // 取出指定人数
  83. const inputs = _.take(sList, res);
  84. // 放进结果里
  85. // .map(i => i._id)
  86. result[_id].push(...inputs);
  87. // 删除指定人数
  88. sList = _.drop(sList, res);
  89. // 赋值回去
  90. studentGroup[key] = sList;
  91. }
  92. }
  93. // 补人
  94. for (const c of classList) {
  95. const { _id, number, name } = c;
  96. let nowNum = result[_id].length;
  97. const soldup = _.cloneDeep(solve);
  98. while (nowNum < number) {
  99. // 补人,根据solve,获取补人的选择列表
  100. const res = this.getSelects(soldup);
  101. for (const r of res) {
  102. const { schid, gender } = r;
  103. // 获取学生列表
  104. const sList = studentGroup[`${schid}-${gender}`];
  105. const head = _.head(sList);
  106. if (head) {
  107. // 有学生,往班级里推,备选中删除,重新计算当前分配的班级人数,修改solve副本
  108. // result[_id].push(head._id);
  109. result[_id].push(head);
  110. studentGroup[`${schid}-${gender}`] = _.drop(sList);
  111. nowNum = result[_id].length;
  112. soldup[`${schid}-${gender}`].res++;
  113. pList.push(`${name}班用${schid}-${gender}补人:当前人数为${nowNum};要求${number}`);
  114. break;
  115. } else continue;
  116. }
  117. }
  118. }
  119. }
  120. // console.log(pList);
  121. // for (const key in result) {
  122. // console.group(key);
  123. // const list = result[key];
  124. // const b = list.filter(f => f.gender === '男');
  125. // const g = list.filter(f => f.gender === '女');
  126. // console.log(b.length, g.length);
  127. // console.groupEnd();
  128. // }
  129. // 更新学生的班级
  130. const ckeys = Object.keys(result);
  131. for (const classid of ckeys) {
  132. await this.stumodel.updateMany({ _id: result[classid] }, { classid });
  133. }
  134. // 新添,给学生排序号
  135. const claList = await this.model.find({ termid });
  136. for (const cla of claList) {
  137. await this.ctx.service.student.arrangeNumber({ classid: cla._id });
  138. }
  139. }
  140. /**
  141. * 算整除和取余
  142. * @param {Any} num1 性别人数
  143. * @param {Any} num2 班级人数
  144. * @property {Number} res 整除结果
  145. * @property {Number} el 余数
  146. */
  147. numDivide(num1, num2) {
  148. num1 = _.isNaN(parseInt(num1)) ? 0 : parseInt(num1);
  149. num2 = _.isNaN(parseInt(num2)) ? 0 : parseInt(num2);
  150. const res = _.floor(num1 / num2, 0);
  151. const el = num1 % num2;
  152. return { res, el };
  153. }
  154. /**
  155. * 验证计算结果是否 不超过 最少人数班级的人数
  156. * @param {Object} solve 计算结果:key:${schid}-${gender}
  157. * @param {Number} number 最少人数班级的人数
  158. * @param {Number} classnum 班级数量,如果需要减人数的话,是要将每班的人数减1,-1就意味着要 - 班级数 *1;余数+班级数*1
  159. */
  160. checkSolve(solve, number, classnum) {
  161. let countClassNum = 0;
  162. let ns = [];
  163. for (const key in solve) {
  164. const { res = 0, el = 0 } = _.get(solve, key, {});
  165. countClassNum += res;
  166. ns.push({ res, el, key });
  167. }
  168. if (countClassNum <= number) return solve;
  169. do {
  170. ns = _.orderBy(ns, [ 'res' ], [ 'desc' ]);
  171. const head = _.head(ns);
  172. head.res--;
  173. head.el += classnum;
  174. ns[0] = head;
  175. countClassNum = ns.reduce((p, n) => p + n.res, 0);
  176. } while (countClassNum > number);
  177. for (const i of ns) {
  178. const { key, ...others } = i;
  179. solve[key] = { ...others };
  180. }
  181. return solve;
  182. }
  183. // 获取选择结果
  184. getSelects(solve) {
  185. // 做出补人选项的集合:按学校人数,性别人数来看
  186. const keys = Object.keys(solve);
  187. let schids = keys.map(i => {
  188. const arr = i.split('-');
  189. let res;
  190. if (arr[0] && parseInt(arr[0])) res = arr[0];
  191. return res;
  192. });
  193. schids = _.compact(_.uniq(schids));
  194. let genders = keys.map(i => {
  195. const arr = i.split('-');
  196. return arr[1];
  197. });
  198. genders = _.compact(_.uniq(genders));
  199. let schArr = [];
  200. for (const schid of schids) {
  201. const midKeys = keys.filter(f => f.includes(schid));
  202. let count = 0;
  203. for (const k of midKeys) {
  204. count += solve[k].res;
  205. }
  206. const obj = { schid, count };
  207. schArr.push(obj);
  208. }
  209. let genArr = [];
  210. for (const gen of genders) {
  211. const midKeys = keys.filter(f => f.includes(gen));
  212. let count = 0;
  213. for (const k of midKeys) {
  214. count += solve[k].res;
  215. }
  216. const obj = { gender: gen, count };
  217. genArr.push(obj);
  218. }
  219. // 2个数组升序排序
  220. schArr = _.orderBy(schArr, [ 'count' ], [ 'asc' ]);
  221. genArr = _.orderBy(genArr, [ 'count' ], [ 'asc' ]);
  222. const arr = [];
  223. // 优先性别
  224. // for (const gen of genArr) {
  225. // for (const sch of schArr) {
  226. // const { schid } = sch;
  227. // const { gender } = gen;
  228. // arr.push({ schid, gender });
  229. // }
  230. // }
  231. // 优先学校
  232. for (const sch of schArr) {
  233. for (const gen of genArr) {
  234. const { schid } = sch;
  235. const { gender } = gen;
  236. arr.push({ schid, gender });
  237. }
  238. }
  239. return arr;
  240. }
  241. // 取得同样类型的学生
  242. async getstutype(_students, type) {
  243. const data = [];
  244. for (const stuid of _students) {
  245. const student = await this.stumodel.findById(stuid);
  246. if (student && student.type === type) {
  247. data.push(stuid);
  248. }
  249. }
  250. return data;
  251. }
  252. // 自动生成班级私有方法
  253. async autoclass(planid, termid) {
  254. // 删除所有计划下的班级
  255. await this.model.deleteMany({ planid, termid });
  256. // 删除该期课表
  257. await this.lessmodel.deleteMany({ termid });
  258. // 根据批次id取得当前批次具体信息
  259. const res = await this.tmodel.findById(planid);
  260. if (!res) {
  261. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在');
  262. }
  263. // 循环出所有班级进行添加操作
  264. const term = await res.termnum.id(termid);
  265. for (const batch of term.batchnum) {
  266. const classs = await batch.class;
  267. for (const cla of classs) {
  268. const newdata = { name: cla.name, number: cla.number, batchid: batch.id, termid: term.id, planid: res.id, type: cla.type };
  269. const rescla = await this.model.create(newdata);
  270. await this.toSetClassSetting({ classid: rescla._id });
  271. }
  272. }
  273. }
  274. // 根据传入的学生列表和班级id更新学生信息
  275. async studentup(classid, batchid, beforestu) {
  276. // 循环学生id
  277. for (const stuid of beforestu) {
  278. const student = await this.stumodel.findById(stuid);
  279. if (student) {
  280. student.classid = classid;
  281. student.batchid = batchid;
  282. await student.save();
  283. }
  284. }
  285. }
  286. // 自动分组
  287. async groupcreate(termid, batchid, classid) {
  288. const group = await this.gmodel.find({ termid, batchid, classid });
  289. if (group.length === 0) {
  290. for (let i = 1; i < 8; i++) {
  291. const name = i + '组';
  292. const newdata = { name, termid, batchid, classid };
  293. await this.gmodel.create(newdata);
  294. }
  295. }
  296. }
  297. // 根据传入的学生列表和班级id更新学生信息
  298. async studentupclass({ id }, data) {
  299. assert(id, '班级id为必填项');
  300. // 根据全年计划表id查出对应的全年计划详细信息
  301. const trainplan = await this.tmodel.findOne({ 'termnum.batchnum.class._id': ObjectId(id) });
  302. if (!trainplan) {
  303. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在');
  304. }
  305. // 取得计划期批次信息
  306. let termid = '';
  307. let batchid = '';
  308. let classname = '';
  309. let class_ = {};
  310. for (const term of trainplan.termnum) {
  311. for (const batch of term.batchnum) {
  312. const _class = await batch.class.id(id);
  313. if (_class) {
  314. termid = term.id;
  315. batchid = batch.id;
  316. classname = _class.name;
  317. class_ = _class;
  318. break;
  319. }
  320. }
  321. }
  322. if (!class_) {
  323. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '班级信息不存在');
  324. }
  325. let classid_ = '';
  326. if (classname) {
  327. const cla_ = await this.model.findOne({ termid, batchid, name: classname });
  328. if (cla_) {
  329. classid_ = cla_.id;
  330. } else {
  331. const newdata = {
  332. name: class_.name,
  333. number: class_.number,
  334. batchid,
  335. termid,
  336. planid: trainplan.id,
  337. type: class_.type,
  338. headteacherid: class_.headteacherid,
  339. };
  340. const rescla = await this.model.create(newdata);
  341. if (rescla) {
  342. classid_ = rescla.id;
  343. }
  344. }
  345. }
  346. if (classid_) {
  347. // 循环学生id
  348. for (const stuid of data) {
  349. const student = await this.stumodel.findById(stuid);
  350. if (student) {
  351. student.classid = classid_;
  352. await student.save();
  353. }
  354. }
  355. }
  356. // 添加,给学生排序号
  357. await this.ctx.service.student.arrangeNumber({ classid: classid_ });
  358. // TODO 根据模板复制班级信息
  359. await this.toSetClassSetting({ classid: classid_ });
  360. }
  361. async notice(data) {
  362. for (const classid of data.classids) {
  363. // 根据班级id找到需要通知的班级
  364. const _class = await this.model.findById(classid);
  365. const { headteacherid } = _class;
  366. // 根据班级id找到对应的课程表
  367. const lesson = await this.lessmodel.findOne({ classid });
  368. if (lesson) {
  369. const lessons = lesson.lessons;
  370. const remark = '感谢您的使用';
  371. const date = await this.ctx.service.util.updatedate();
  372. const detail = '班级各项信息已确认,请注意查收';
  373. // 遍历班级授课教师发送通知
  374. for (const lessoninfo of lessons) {
  375. const teaid = lessoninfo.teaid;
  376. const _teacher = await this.umodel.findOne({ uid: teaid, type: '3' });
  377. if (_teacher) {
  378. const teaopenid = _teacher.openid;
  379. this.ctx.service.weixin.sendTemplateMsg(this.ctx.app.config.REVIEW_TEMPLATE_ID, teaopenid, '您有一个新的通知', detail, date, remark, classid);
  380. }
  381. }
  382. // 给班主任发送通知
  383. const _headteacher = await this.umodel.findOne({ uid: headteacherid, type: '1' });
  384. if (_headteacher) {
  385. const headteaopenid = _headteacher.openid;
  386. this.ctx.service.weixin.sendTemplateMsg(this.ctx.app.config.REVIEW_TEMPLATE_ID, headteaopenid, '您有一个新的通知', detail, date, remark, classid);
  387. }
  388. // 根据班级的期id查询对应的培训计划
  389. const trainplan = await this.tmodel.findOne({ 'termnum._id': _class.termid });
  390. const term = await trainplan.termnum.id(_class.termid);
  391. const batch = await term.batchnum.id(_class.batchid);
  392. const startdate = batch.startdate;
  393. const classname = _class.name;
  394. // 给班级所有学生发送邮件通知
  395. const students = await this.stumodel.find({ classid });
  396. for (const student of students) {
  397. const { email, name } = student;
  398. const subject = '吉林省高等学校毕业生就业指导中心通知';
  399. const text = name + '您好!\n欢迎参加由吉林省高等学校毕业生就业指导中心举办的“双困生培训会”。\n您所在的班级为:' + classname + '\n班级开课时间为:' + startdate;
  400. this.ctx.service.util.sendMail(email, subject, text);
  401. }
  402. }
  403. }
  404. }
  405. async uptea(data) {
  406. for (const _data of data) {
  407. const classInfo = await this.model.findById(_data.id);
  408. classInfo.headteacherid = _data.headteacherid;
  409. await classInfo.save();
  410. }
  411. }
  412. async query({ skip, limit, ...info }) {
  413. const classes = await this.model
  414. .find(info)
  415. .populate([
  416. {
  417. path: 'yclocationid',
  418. model: 'Location',
  419. select: 'name',
  420. },
  421. {
  422. path: 'kzjhlocationid',
  423. model: 'Location',
  424. select: 'name',
  425. },
  426. {
  427. path: 'kbyslocationid',
  428. model: 'Location',
  429. select: 'name',
  430. },
  431. {
  432. path: 'jslocationid',
  433. model: 'Location',
  434. select: 'name',
  435. },
  436. {
  437. path: 'headteacherid',
  438. model: 'Headteacher',
  439. select: 'name',
  440. },
  441. ])
  442. .skip(Number(skip))
  443. .limit(Number(limit));
  444. const data = [];
  445. let planids = classes.map(i => i.planid);
  446. planids = _.uniq(planids);
  447. const trainplan = await this.tmodel.find({ _id: { $in: planids } });
  448. for (const _class of classes) {
  449. let res = await this.setClassData(_class, trainplan);
  450. if (res) {
  451. res = this.setData(res);
  452. data.push(res);
  453. } else {
  454. data.push(_class);
  455. }
  456. }
  457. return data;
  458. }
  459. async fetch({ id }) {
  460. let classInfo = await this.model.findById(id).populate([
  461. {
  462. path: 'yclocationid',
  463. model: 'Location',
  464. select: 'name',
  465. },
  466. {
  467. path: 'kzjhlocationid',
  468. model: 'Location',
  469. select: 'name',
  470. },
  471. {
  472. path: 'kbyslocationid',
  473. model: 'Location',
  474. select: 'name',
  475. },
  476. {
  477. path: 'jslocationid',
  478. model: 'Location',
  479. select: 'name',
  480. },
  481. {
  482. path: 'headteacherid',
  483. model: 'Headteacher',
  484. select: 'name',
  485. },
  486. ]);
  487. const trainplan = await this.tmodel.findById(classInfo.planid);
  488. classInfo = await this.setClassData(classInfo, [ trainplan ]);
  489. classInfo = this.setData(classInfo);
  490. return classInfo;
  491. }
  492. // 整理数据,找礼仪教师
  493. async setClassData(cla, trainplan) {
  494. const { planid, termid, batchid } = cla;
  495. cla = JSON.parse(JSON.stringify(cla));
  496. const tpRes = trainplan.find(f => ObjectId(planid).equals(f._id));
  497. if (!tpRes) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的计划信息');
  498. const t = tpRes.termnum.id(termid);
  499. if (!t) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的期信息');
  500. const { term, batchnum } = t;
  501. if (!term) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的期信息');
  502. else cla.term = term;
  503. if (!batchnum) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的批次信息');
  504. const b = batchnum.id(batchid);
  505. if (!b) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级的批次信息');
  506. const { batch, startdate, enddate } = b;
  507. if (batch)cla.batch = batch;
  508. if (startdate) cla.startdate = startdate;
  509. if (enddate) cla.enddate = enddate;
  510. // 礼仪教师
  511. if (cla.lyteacherid) {
  512. let res = await this.teamodel.findById(cla.lyteacherid);
  513. if (!res) res = await this.heamodel.findById(cla.lyteacherid);
  514. if (res) cla.lyteacher = res.name;
  515. }
  516. return cla;
  517. }
  518. // 整理数据
  519. setData(cla) {
  520. const { headteacherid, yclocationid, kzjhlocationid, kbyslocationid, jslocationid } = cla;
  521. const arr = [];
  522. if (headteacherid && _.isObject(headteacherid)) arr.push({ headteacherid });
  523. if (yclocationid && _.isObject(yclocationid)) arr.push({ yclocationid });
  524. if (kzjhlocationid && _.isObject(kzjhlocationid)) arr.push({ kzjhlocationid });
  525. if (kbyslocationid && _.isObject(kbyslocationid)) arr.push({ kbyslocationid });
  526. if (jslocationid && _.isObject(jslocationid)) arr.push({ jslocationid });
  527. for (const kid of arr) {
  528. for (const key in kid) {
  529. if (kid.hasOwnProperty(key)) {
  530. const obj = kid[key];
  531. const { _id, name } = obj;
  532. const keynoids = key.split('id');
  533. cla[key] = _id;
  534. cla[_.get(keynoids, 0)] = name;
  535. }
  536. }
  537. }
  538. return cla;
  539. }
  540. async upclasses(data) {
  541. for (const _data of data) {
  542. await this.model.findByIdAndUpdate(_data.id, _data);
  543. }
  544. }
  545. async classinfo({ id: classid }) {
  546. const _classes = await this.model.findById(classid);
  547. // 班级信息
  548. const classes = _.cloneDeep(JSON.parse(JSON.stringify(_classes)));
  549. // 学生信息
  550. const students = await this.stumodel.find({ classid });
  551. // 所有用户信息
  552. const users = await this.umodel.find();
  553. if (students) {
  554. for (const stu of students) {
  555. const user = users.find(item => item.uid === stu.id);
  556. if (user && user.openid) {
  557. const _stu = _.cloneDeep(JSON.parse(JSON.stringify(stu)));
  558. _stu.hasuserinfo = '1';
  559. _.remove(students, stu);
  560. students.push(_stu);
  561. }
  562. }
  563. classes.students = students;
  564. }
  565. // 班主任信息
  566. let headteacher;
  567. if (classes.headteacherid) {
  568. headteacher = await this.heamodel.findById(classes.headteacherid);
  569. }
  570. // 礼仪课老师信息
  571. let lyteacher;
  572. if (classes.lyteacherid) {
  573. lyteacher = await this.heamodel.findById(classes.lyteacherid);
  574. if (!lyteacher) {
  575. lyteacher = await this.teamodel.findById(classes.lyteacherid);
  576. }
  577. }
  578. // 教课老师信息
  579. let teachers = [];
  580. const lessones = await this.lessmodel.findOne({ classid });
  581. if (lessones) {
  582. for (const lesson of lessones.lessons) {
  583. if (lesson.teaid) {
  584. const teacher = await this.teamodel.findById(lesson.teaid);
  585. teachers.push(teacher);
  586. }
  587. }
  588. }
  589. teachers.push(lyteacher);
  590. teachers.push(headteacher);
  591. teachers = _.uniq(_.compact(teachers));
  592. for (const tea of teachers) {
  593. const user = users.find(item => item.uid === tea.id);
  594. if (user && user.openid) {
  595. const _tea = _.cloneDeep(JSON.parse(JSON.stringify(tea)));
  596. _tea.hasuserinfo = '1';
  597. _.remove(teachers, tea);
  598. teachers.push(_tea);
  599. }
  600. }
  601. classes.teachers = teachers;
  602. return classes;
  603. }
  604. // 根据模板设置班级信息
  605. async toSetClassSetting({ classid }) {
  606. const setting = await this.ctx.model.Setting.findOne();
  607. if (!setting) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到系统设置');
  608. const { template_term } = setting;
  609. if (!template_term) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到班级模板设置');
  610. const templateList = await this.query({ termid: template_term });
  611. const tClass = await this.model.findById(classid);
  612. if (!tClass) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '班级不存在,无法复制设定的班级设置');
  613. const { name, termid, batchid } = tClass;
  614. const r = templateList.find(f => f.name === name);
  615. // 找到班主任全年计划
  616. const trainPlan = await this.tmodel.findById(tClass.planid);
  617. if (!trainPlan) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到该班所在的年度计划信息');
  618. const tpt = trainPlan.termnum.id(tClass.termid);
  619. if (!tpt) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到该班所在年度计划的期信息');
  620. const tpb = tpt.batchnum.id(tClass.batchid);
  621. if (!tpb) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到该班所在年度计划的批次信息');
  622. if (!tpb.class) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到该班所在年度计划批次下的班级');
  623. const tpc = tpb.class.find(f => f.name === tClass.name);
  624. if (!tpc) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到该班所在年度计划的班级信息');
  625. const { headteacherid } = tpc;
  626. if (r) {
  627. // 说明这个是正常班,且从模板中找得到; 除了礼仪教师外,都复制过来
  628. const { jslocationid, kbyslocationid, kzjhlocationid, yclocationid } = r;
  629. if (!tClass.jslocation && jslocationid) tClass.jslocationid = jslocationid;
  630. if (!tClass.kbyslocationid && kbyslocationid) tClass.kbyslocationid = kbyslocationid;
  631. if (!tClass.kzjhlocationid && kzjhlocationid) tClass.kzjhlocationid = kzjhlocationid;
  632. if (!tClass.yclocationid && yclocationid) tClass.yclocationid = yclocationid;
  633. if (!tClass.headteacherid && headteacherid) {
  634. tClass.headteacherid = headteacherid;
  635. // 默认班主任为礼仪教师
  636. tClass.lyteacherid = headteacherid;
  637. }
  638. await tClass.save();
  639. } else {
  640. // 没找到,有可能是普通班,也有可能是非普通班
  641. // 找这个班级的同批次
  642. const tClassBatch = await this.query({ termid, batchid });
  643. const r = tClassBatch.find(f => ObjectId(tClass._id).equals(f._id));
  644. const ri = tClassBatch.findIndex(f => ObjectId(tClass._id).equals(f._id));
  645. // TODO 特殊班需要判断,如果没有就没有
  646. // if (r) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '无法确定班级批次排序');
  647. if (!r) {
  648. const { batch: tAllClassBatch } = r;
  649. const templateBatchList = templateList.filter(f => f.batch === tAllClassBatch);
  650. // 根据该班级所在批次的顺序,找到对应模板,然后复制
  651. const copyTemplate = templateBatchList[ri];
  652. const { jslocationid, kbyslocationid, kzjhlocationid, yclocationid } = copyTemplate;
  653. if (!tClass.jslocation && jslocationid) tClass.jslocationid = jslocationid;
  654. if (!tClass.kbyslocationid && kbyslocationid) tClass.kbyslocationid = kbyslocationid;
  655. if (!tClass.kzjhlocationid && kzjhlocationid) tClass.kzjhlocationid = kzjhlocationid;
  656. if (!tClass.yclocationid && yclocationid) tClass.yclocationid = yclocationid;
  657. if (!tClass.headteacherid && headteacherid) tClass.headteacherid = headteacherid;
  658. await tClass.save();
  659. }
  660. }
  661. }
  662. }
  663. module.exports = ClassService;