student.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  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. const moment = require('moment');
  8. class StudentService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'student');
  11. this.model = this.ctx.model.Student;
  12. this.umodel = this.ctx.model.User;
  13. this.tmodel = this.ctx.model.Trainplan;
  14. this.clamodel = this.ctx.model.Class;
  15. this.upmodel = this.ctx.model.Uploadtask;
  16. this.gmodel = this.ctx.model.Group;
  17. this.psmodel = this.ctx.model.Personalscore;
  18. this.gsmodel = this.ctx.model.Groupscore;
  19. this.uqmodel = this.ctx.model.Uploadquestion;
  20. this.scoremodel = this.ctx.model.Score;
  21. this.leavemodel = this.ctx.model.Leave;
  22. this.attendmodel = this.ctx.model.Attendance;
  23. const { baseUrl } = _.get(this.ctx.app.config, 'mission');
  24. if (baseUrl) this.missionBase = baseUrl;
  25. }
  26. async create(data) {
  27. const { name, phone: mobile, gender, id_number } = data;
  28. const count = await this.model.count({ id_number });
  29. if (count) throw new BusinessError(ErrorCode.DATA_EXISTED, '该身份证号已存在,若未发现错误,请联系开发人员查证');
  30. const res = await this.model.create(data);
  31. if (res) {
  32. const obj = {
  33. name,
  34. mobile,
  35. gender,
  36. type: '4',
  37. passwd: '12345678',
  38. uid: res._id,
  39. };
  40. const user = await this.ctx.service.user.create(obj);
  41. }
  42. return res;
  43. }
  44. async delete({ id }) {
  45. // 删除小组中的这个人,作业表,问卷表,评分,考勤,用户表,学生表
  46. await this.gmodel.update(
  47. { 'students.stuid': id },
  48. { $pull: { students: { stuid: id } } }
  49. );
  50. await this.upmodel.deleteMany({ studentid: id });
  51. await this.uqmodel.deleteMany({ studentid: id });
  52. await this.scoremodel.deleteMany({ stuid: id });
  53. await this.attendmodel.deleteMany({ studentid: id });
  54. await this.umodel.deleteOne({ uid: id });
  55. await this.model.deleteOne({ _id: ObjectId(id) });
  56. }
  57. async update({ id }, data) {
  58. const student = await this.model.findByIdAndUpdate(id, data);
  59. if (student) {
  60. const { phone, name } = data;
  61. if (phone && name) {
  62. await this.umodel.findOneAndUpdate(
  63. { uid: id },
  64. { mobile: phone, name }
  65. );
  66. }
  67. }
  68. return student;
  69. }
  70. // 查询
  71. async query({ name, ...info } = {}, { skip = 0, limit = 0 } = {}) {
  72. const query = { ...info };
  73. if (name) {
  74. query.name = { $regex: name };
  75. }
  76. let data = await this.model
  77. .find(query)
  78. .populate([
  79. {
  80. path: 'classid',
  81. model: 'Class',
  82. select: 'name',
  83. },
  84. ])
  85. .skip(parseInt(skip))
  86. .limit(parseInt(limit));
  87. const planids = _.uniq(data.map(i => ObjectId(i.planid)));
  88. const plan = await this.ctx.model.Trainplan.find({ _id: planids });
  89. data = JSON.parse(JSON.stringify(data));
  90. data = data.map(i => {
  91. if (i.classid && _.isObject(i.classid)) {
  92. i.classname = _.get(i.classid, 'name');
  93. i.classid = _.get(i.classid, '_id');
  94. }
  95. const p = plan.find(f => ObjectId(f._id).equals(i.planid));
  96. if (p) {
  97. const { termnum } = p;
  98. const tr = termnum.id(i.termid);
  99. if (tr) {
  100. i.termname = _.get(tr, 'term');
  101. const br = tr.batchnum.id(i.batchid);
  102. if (br) {
  103. i.batchname = _.get(br, 'batch');
  104. }
  105. }
  106. }
  107. return i;
  108. });
  109. return data;
  110. }
  111. async count({ name, ...info } = {}) {
  112. const query = { ...info };
  113. if (name) {
  114. query.name = { $regex: name };
  115. }
  116. return await this.model.count(query);
  117. }
  118. // 查询
  119. async seek({ termid, type, batchid, skip, limit }) {
  120. const total = await this.model.count({
  121. termid,
  122. type,
  123. batchid,
  124. $or: [{ classid: null }, { classid: '' }],
  125. });
  126. const data = await this.model
  127. .find({
  128. termid,
  129. type,
  130. batchid,
  131. $or: [{ classid: null }, { classid: '' }],
  132. })
  133. .skip(Number(skip))
  134. .limit(Number(limit));
  135. const result = { total, data };
  136. return result;
  137. }
  138. async findbedroom(data) {
  139. const { batchid, classid } = data;
  140. const result = [];
  141. // 如果传的是批次id
  142. if (batchid) {
  143. // 查询该批次下的所有学生
  144. const students = await this.model.find({ batchid });
  145. const bedroomList = new Set();
  146. // 查询该批次的所有寝室号
  147. for (const student of students) {
  148. bedroomList.add(student.bedroom);
  149. }
  150. let studentList = [];
  151. // 查询该批次所有寝室下的学生名单
  152. for (const bedroom of bedroomList) {
  153. const newstudents = await this.model.find({ bedroom });
  154. for (const newstudent of newstudents) {
  155. studentList.push(newstudent.name);
  156. }
  157. result.push({ bedroom, studentList });
  158. studentList = [];
  159. }
  160. }
  161. // 如果传的是班级id
  162. if (classid) {
  163. // 查询该班级所有学生
  164. const students = await this.model.find({ classid });
  165. const bedroomList = new Set();
  166. // 查询该班级所有寝室号
  167. for (const student of students) {
  168. bedroomList.add(student.bedroom);
  169. }
  170. let studentList = [];
  171. // 查询该班级所有寝室的学生名单
  172. for (const bedroom of bedroomList) {
  173. const newstudents = await this.model.find({ bedroom });
  174. for (const newstudent of newstudents) {
  175. // 如果寝室中有非本班级学生(混寝),则过滤掉不予显示
  176. if (newstudent.classid === classid) {
  177. studentList.push(newstudent.name);
  178. }
  179. }
  180. result.push({ bedroom, studentList });
  181. studentList = [];
  182. }
  183. }
  184. return result;
  185. }
  186. async upjob(data) {
  187. const { stuid, job } = data;
  188. const student = await this.model.findById(stuid);
  189. student.job = job;
  190. if (job === '班长' || job === '学委') {
  191. const user = await this.umodel.findOne({ uid: stuid, type: '4' });
  192. const date = await this.ctx.service.util.updatedate();
  193. const openid = user.openid;
  194. const detail = '你已被班主任设置为' + job + ',请及时登录查看';
  195. const remark = '感谢您的使用';
  196. if (openid) {
  197. this.ctx.service.weixin.sendTemplateMsg(
  198. this.ctx.app.config.REVIEW_TEMPLATE_ID,
  199. openid,
  200. '您有一个新的通知',
  201. detail,
  202. date,
  203. remark
  204. );
  205. }
  206. }
  207. return await student.save();
  208. }
  209. // 根据学生id删除班级
  210. async deleteclass(data) {
  211. for (const el of data) {
  212. const student = await this.model.findById(el);
  213. if (student) {
  214. student.classid = '';
  215. await student.save();
  216. }
  217. }
  218. }
  219. // 根据班级id查出班级各个学生的分数
  220. async findscore({ skip, limit, ...info }) {
  221. const { classid } = info;
  222. const total = await this.model.count(info);
  223. const students = await this.model
  224. .find(info)
  225. .skip(Number(skip))
  226. .limit(Number(limit));
  227. const data = [];
  228. const groups = await this.gmodel.find({ classid });
  229. for (const student of students) {
  230. const _student = JSON.parse(JSON.stringify(student));
  231. const group = groups.find(item =>
  232. item.students.find(stuinfo => stuinfo.stuid === _student.id)
  233. );
  234. if (group) {
  235. _student.groupscore = group.score;
  236. }
  237. const tasks = await this.upmodel.find({ studentid: _student.id });
  238. _student.tasks = tasks;
  239. data.push(_student);
  240. }
  241. return { total, data };
  242. }
  243. async findbystuids({ data }) {
  244. const res = [];
  245. for (const stuid of data) {
  246. const stu = await this.model.findById(stuid);
  247. if (stu) res.push(stu);
  248. }
  249. return res;
  250. }
  251. // 根据学生id删除学生
  252. async deletestus(data) {
  253. // throw new BusinessError(
  254. // ErrorCode.BUSINESS,
  255. // '此功能暂不开放,待确定好会出现的以外情况后,再次开放'
  256. // );
  257. for (const id of data) {
  258. await this.umodel.deleteOne({ uid: id });
  259. await this.upmodel.deleteMany({ studentid: id });
  260. await this.uqmodel.deleteMany({ studentid: id });
  261. await this.scoremodel.deleteMany({ stuid: id });
  262. await this.attendmodel.deleteMany({ studentid: id });
  263. await this.model.deleteOne({ _id: ObjectId(id) });
  264. }
  265. }
  266. // 批量更新寝室号
  267. async updatabedroom(data) {
  268. for (const el of data) {
  269. const student = await this.model.findById(el.id);
  270. if (student) {
  271. student.bedroom = el.bedroom;
  272. await student.save();
  273. }
  274. }
  275. }
  276. /**
  277. * 计算班级的优秀学生
  278. * 规则:班级干部(学生的job!=='普通学生'),检查是否有评优资格(is_fine_status==='0'可以评优),全部评优;
  279. * 普通学生取总成绩前10的人评优(非10位并列时,名额该占用就占用;第10名若有并列,就全都要)
  280. * @param {String} param0 {id=>班级id}
  281. */
  282. async getFineStudent({ id: classid }) {
  283. // 获取班级学生列表
  284. let studentList = await this.model.find({ classid });
  285. // 重置评优,干部全优秀
  286. studentList = studentList.map(i => {
  287. if (i.job.includes('普通')) i.is_fine = '0';
  288. else i.is_fine = '1';
  289. return i;
  290. });
  291. // 初始化后取出不需要算的人,他们就这样,没必要算
  292. const reverseList = studentList.filter(
  293. f => !(f.is_fine !== '2' && f.job.includes('普通'))
  294. );
  295. // 过滤出取消评优资格的学生和干部;干部就是优秀;被取消资格就别凑热闹了
  296. studentList = studentList.filter(
  297. f => f.is_fine !== '2' && f.job.includes('普通')
  298. );
  299. // 获取平时分
  300. let dailyScoreList = await this.psmodel.find({ classid });
  301. // 去重复
  302. dailyScoreList = this.getDailyScore(dailyScoreList);
  303. studentList = this.dealScoreList(dailyScoreList, studentList, 'daily');
  304. // 获取作业分
  305. let taskScoreList = await this.upmodel.find({ classid });
  306. taskScoreList = this.getTaskScore(taskScoreList);
  307. studentList = this.dealScoreList(taskScoreList, studentList, 'task');
  308. // 获取小组分,小组
  309. const groupList = await this.gmodel.find({ classid });
  310. const groupScoreList = await this.gsmodel.find({ classid });
  311. studentList = this.dealGroupScoreList(
  312. groupList,
  313. groupScoreList,
  314. studentList
  315. );
  316. studentList = studentList.map(i => {
  317. i.score = _.round(
  318. (i.daily || 0) + (i.task || 0) + (i.groupscore || 0),
  319. 2
  320. );
  321. return i;
  322. });
  323. studentList = studentList.sort(
  324. (a, b) => (b.score * 1 || 0) - (a.score * 1 || 0)
  325. );
  326. // 排名
  327. // eslint-disable-next-line no-unused-vars
  328. let num = 0;
  329. for (const student of studentList) {
  330. // 先判断是否超过第10位,超过就跳出
  331. if (num >= 10) break;
  332. const { score, is_fine, job, name, _id } = student;
  333. // 最开始初始化过所有人的状态,并且将干部和不能评优的人都过滤出去,所以正常学生应该都是没有评优,如果此处已经是优秀,那么就是和前人同分改的,直接跳过就好
  334. if (is_fine === '1') continue;
  335. // 没有分凑什么热闹
  336. if (!score) continue;
  337. let plus = 1; // 这轮有多少人,到这了,这个人肯定是要改了,所以默认1
  338. // 评优
  339. student.is_fine = '1';
  340. const rlist = studentList.filter(
  341. f => f.score === score && !ObjectId(f._id).equals(_id)
  342. );
  343. // 处理同分的人也都变成is_fine
  344. for (const stud of rlist) {
  345. stud.is_fine = '1';
  346. const sindex = studentList.findIndex(f =>
  347. ObjectId(stud._id).equals(f._id)
  348. );
  349. if (sindex >= 0) {
  350. studentList[sindex] = stud;
  351. plus++;
  352. }
  353. }
  354. // num+plus,算下num
  355. num = num + plus;
  356. }
  357. // 算完的和不用算的合并,提交
  358. const lastList = [ ...studentList, ...reverseList ];
  359. for (const student of lastList) {
  360. // const res = await student.save();
  361. // const { meta, ...data } = student;
  362. const r = await this.model.findByIdAndUpdate(
  363. { _id: ObjectId(student._id) },
  364. { score: student.score, is_fine: student.is_fine }
  365. );
  366. }
  367. }
  368. /**
  369. * 将分数放到学生身上
  370. * @param {Array} scoreList 班级的分数列表
  371. * @param {Array} studentList 学生列表
  372. * @param {String} type 分数类型
  373. */
  374. dealScoreList(scoreList, studentList, type) {
  375. scoreList = JSON.parse(JSON.stringify(scoreList));
  376. studentList = JSON.parse(JSON.stringify(studentList));
  377. scoreList = _.groupBy(scoreList, 'studentid');
  378. const arr = [];
  379. for (let i of studentList) {
  380. const slist = scoreList[i._id];
  381. const obj = {};
  382. if (slist) {
  383. const score = slist.reduce((p, n) => p + (n.score * 1 || 0), 0);
  384. obj[type] = score;
  385. } else {
  386. obj[type] = 0;
  387. }
  388. i = Object.assign(i, obj);
  389. arr.push(i);
  390. }
  391. return arr;
  392. }
  393. /**
  394. * 将 学生所在 组的 团队平均分 + 到学生身上
  395. * @param {Array} groupList 班级的小组的列表
  396. * @param {Array} scoreList 所有小组的分数列表
  397. * @param {Array} studentList 学生列表
  398. */
  399. dealGroupScoreList(groupList, scoreList, studentList) {
  400. scoreList = _.groupBy(scoreList, 'groupid');
  401. // 算出每组的平均分,之后加给学生
  402. groupList = groupList.map(i => {
  403. const { students } = i;
  404. if (students.length > 0) {
  405. const slist = scoreList[i._id];
  406. if (slist) {
  407. i.score = slist.reduce((p, n) => p + (n.score * 1 || 0), 0);
  408. i.score = _.floor(_.divide(i.score, students.length), 2);
  409. }
  410. }
  411. return i;
  412. });
  413. // 每个学生加自己的组的平均分
  414. studentList = studentList.map(i => {
  415. const r = groupList.find(f =>
  416. f.students.find(sf => ObjectId(sf.stuid).equals(i._id))
  417. );
  418. if (r) {
  419. // i.score = _.round((i.score * 1 || 0) + (r.score * 1 || 0), 2);
  420. i.groupscore = r.score * 1 || 0;
  421. } else {
  422. i.groupscore = 0;
  423. }
  424. return i;
  425. });
  426. return studentList;
  427. }
  428. // 平时分去重处理
  429. getDailyScore(list) {
  430. const arr = [];
  431. const mid1 = _.groupBy(list, 'studentid');
  432. const keys = Object.keys(mid1);
  433. for (const key of keys) {
  434. const mid2 = _.uniqBy(mid1[key], 'subid');
  435. arr.push(...mid2);
  436. }
  437. return arr;
  438. }
  439. // 作业分去重处理
  440. getTaskScore(list) {
  441. const arr = [];
  442. const mid1 = _.groupBy(list, 'studentid');
  443. const keys = Object.keys(mid1);
  444. for (const key of keys) {
  445. const mid2 = _.uniqBy(mid1[key], 'lessonid');
  446. arr.push(...mid2);
  447. }
  448. return arr;
  449. }
  450. // 将学生排号
  451. async arrangeNumber({ classid }) {
  452. const studList = await this.model.find({ classid });
  453. let number = 1;
  454. // 查每个学生的编号,如果没有,就给赋上值;有,就给number赋上值,然后继续下一位
  455. for (const stu of studList) {
  456. if (!stu.number) {
  457. if (number * 1 < 10) stu.number = `0${number}`;
  458. else stu.number = number;
  459. await stu.save();
  460. } else {
  461. number = stu.number * 1;
  462. }
  463. number = number * 1 + 1;
  464. }
  465. number = 1;
  466. }
  467. // 建立导出学生名单的任务
  468. async toExport(body) {
  469. const { planid, termid, batchid, classid } = body;
  470. const trainPlan = await this.ctx.model.Trainplan.findById(planid);
  471. let fn = '学生名单';
  472. if (termid && termid.length > 0) {
  473. if (classid) {
  474. const cla = await this.ctx.model.Class.findById(classid);
  475. if (cla) {
  476. const { name } = cla;
  477. if (name) {
  478. fn = `${name.includes('班') ? name : `${name}班`}${fn}`;
  479. }
  480. }
  481. }
  482. if (termid.length === 1) {
  483. const tid = _.head(termid);
  484. const { termnum } = trainPlan;
  485. const t = termnum.id(tid);
  486. if (t) {
  487. const { term, batchnum } = t;
  488. if (batchid) {
  489. const b = batchnum.id(batchid);
  490. if (b) {
  491. const { batch } = b;
  492. if (b) fn = `第${batch}批${fn}`;
  493. }
  494. }
  495. if (term) fn = `第${term}期${fn}`;
  496. }
  497. } else if (termid.length > 1) {
  498. const { termnum } = trainPlan;
  499. let str = '第';
  500. for (const tid of termid) {
  501. const t = termnum.id(tid);
  502. if (t) {
  503. const { term } = t;
  504. str = `${str}${term} `;
  505. }
  506. }
  507. fn = `${str}期${fn}`;
  508. }
  509. } else {
  510. const { title } = trainPlan;
  511. fn = `${title}${fn}`;
  512. }
  513. const data = {
  514. title: fn,
  515. params: {
  516. project: 'center',
  517. // router: '/api/train/mission/student/export',
  518. service: 'student',
  519. method: 'exportStudent',
  520. body,
  521. },
  522. };
  523. if (this.missionBase) {
  524. const url = `${this.missionBase}/api/mission`;
  525. const res = await this.ctx.curl(url, {
  526. method: 'post',
  527. headers: {
  528. 'content-type': 'application/json',
  529. },
  530. data,
  531. dataType: 'json',
  532. });
  533. if (res.status !== 200 || res.data.errcode !== 0) {
  534. throw new BusinessError(ErrorCode.SERVICE_FAULT, '创建任务失败');
  535. }
  536. } else {
  537. throw new BusinessError(ErrorCode.SERVICE_FAULT, '未找到任务项目设置');
  538. }
  539. }
  540. // 导出学生
  541. async exportStudent(body) {
  542. let { missionid, model, ...data } = body;
  543. assert(missionid, '缺少任务信息,无法执行任务');
  544. try {
  545. // 整理model
  546. model = model.map(i => {
  547. const { zh, model } = i;
  548. if (zh && model) {
  549. const obj = {};
  550. obj.header = zh;
  551. if (model === 'termid') obj.key = 'termname';
  552. else if (model === 'batchid') obj.key = 'batchname';
  553. else if (model === 'classid') obj.key = 'classname';
  554. else obj.key = model;
  555. obj.width = 20;
  556. return obj;
  557. }
  558. });
  559. model = _.compact(model);
  560. // 请求数据
  561. // 修改条件,termid变成数组了,需要一个一个查出来
  562. const { planid, termid, batchid, classid, isComming } = data;
  563. const queryObject = {};
  564. if (planid) queryObject.planid = planid;
  565. if (batchid) queryObject.batchid = batchid;
  566. if (classid) queryObject.classid = classid;
  567. if (isComming) {
  568. // 因为isComming有3种,0=>没来;1=>来了;2=>来了又退了.而已参培的类型应该是不为0,而不是单纯的1,只管来没来,不管走没走,毕竟吃饭了,得交钱
  569. if (isComming !== '0') queryObject.isComming = { $ne: '0' };
  570. else queryObject.isComming = isComming;
  571. }
  572. let studentList = [];
  573. console.log(queryObject);
  574. if (termid && termid.length > 0) {
  575. for (const t of termid) {
  576. queryObject.termid = t;
  577. const stuList = await this.query(queryObject);
  578. studentList.push(...stuList);
  579. }
  580. } else {
  581. studentList = await this.query(queryObject);
  582. }
  583. console.log(studentList.length);
  584. // 获取学生,4分之1
  585. this.ctx.service.util.updateProcess(missionid, '25');
  586. console.log('学生导出=>25%');
  587. studentList = JSON.parse(JSON.stringify(studentList));
  588. let ids = studentList.map(i => i.classid);
  589. ids = _.uniq(ids);
  590. ids = _.compact(ids);
  591. ids = ids.map(i => ObjectId(i));
  592. const classList = await this.ctx.model.Class.find({
  593. _id: { $in: ids },
  594. });
  595. for (const stu of studentList) {
  596. // 转换是否参培
  597. const { classid, isComming } = stu;
  598. if (!classid) continue;
  599. const cla = await this.ctx.service.class.fetch({ id: classid });
  600. if (!cla) continue;
  601. const { startdate } = cla;
  602. if (!startdate) continue;
  603. stu.insurance = moment(startdate).add(1, 'd').format('YYYY-MM-DD');
  604. if (isComming) {
  605. if (isComming === '0') stu.isComming = '否';
  606. else if (isComming === '1') stu.isComming = '是';
  607. else if (isComming === '2') stu.isComming = '退出';
  608. }
  609. }
  610. // 整理完数据,4分之2
  611. this.ctx.service.util.updateProcess(missionid, '50');
  612. console.log('学生导出=>50%');
  613. let fn = '学生名单';
  614. // 因为是递进下来, batchid和classid并列,并非递进
  615. // 获取fn
  616. if (classid) {
  617. // 文件名称: 期, 班
  618. // 班级名上面有直接拽来
  619. const cla = classList.find(f => ObjectId(classid).equals(f._id));
  620. if (cla) {
  621. const { name, termid } = cla;
  622. if (name) fn = `${name.includes('班') ? name : `${name}班`}${fn}`;
  623. if (termid) {
  624. const obj = await this.toGetFn(termid);
  625. if (obj) {
  626. const { term } = obj;
  627. fn = `第${term}期${fn}`;
  628. }
  629. }
  630. }
  631. } else if (batchid) {
  632. // 文件名称,期,批
  633. const tid = _.head(termid);
  634. const obj = await this.toGetFn(tid, batchid);
  635. if (obj) {
  636. const { term, batch } = obj;
  637. if (batch) fn = `第${batch}批${fn}`;
  638. if (term) fn = `第${term}期${fn}`;
  639. }
  640. } else if (termid) {
  641. // 文件名称: 期
  642. if (termid.length === 1) {
  643. const obj = await this.toGetFn(_.head(termid));
  644. if (obj) {
  645. const { term } = obj;
  646. if (term) fn = `第${term}期${fn}`;
  647. }
  648. } else {
  649. let tStr = '';
  650. for (let i = 0; i < termid.length; i++) {
  651. const tid = termid[i];
  652. const obj = await this.toGetFn(tid);
  653. if (obj) {
  654. const { term } = obj;
  655. if (term) {
  656. if (i === 0) {
  657. tStr += `${term}期`;
  658. } else {
  659. tStr += `,${term}期`;
  660. }
  661. }
  662. }
  663. }
  664. fn = `${tStr}${fn}`;
  665. }
  666. } else if (planid) {
  667. // 文件名称:该计划标题
  668. const trainPlan = await this.ctx.model.Trainplan.findById(planid);
  669. if (trainPlan) {
  670. const { title } = trainPlan;
  671. if (title) fn = `${title}${fn}`;
  672. }
  673. }
  674. // 获取文件名,60%
  675. this.ctx.service.util.updateProcess(missionid, '60');
  676. console.log('学生导出=>60%');
  677. const res = await this.ctx.service.util.toExcel(studentList, model, fn);
  678. if (!res) {
  679. console.error(
  680. `${moment().format('YYYY-MM-DD HH:SS:mm')} ${fn} 导出失败`
  681. );
  682. throw new BusinessError(ErrorCode.SERVICE_FAULT, `${fn}导出失败`);
  683. }
  684. this.ctx.service.util.updateProcess(missionid, '100', '2', {
  685. uri: res,
  686. });
  687. console.log('学生导出=>100%');
  688. } catch (error) {
  689. this.ctx.service.util.updateProcess(missionid, undefined, '3');
  690. }
  691. }
  692. async toGetFn(termid, batchid) {
  693. const trainPlan = await this.ctx.model.Trainplan.findOne({
  694. 'termnum._id': ObjectId(termid),
  695. });
  696. if (!trainPlan) {
  697. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到年度计划信息');
  698. }
  699. const { termnum } = trainPlan;
  700. if (!termnum) {
  701. throw new BusinessError(
  702. ErrorCode.DATA_NOT_EXIST,
  703. '未找到年度计划的期信息'
  704. );
  705. }
  706. const obj = {};
  707. if (termid) {
  708. const term = termnum.id(termid);
  709. if (term) obj.term = term.term;
  710. if (batchid) {
  711. const { batchnum } = term;
  712. const batch = batchnum.id(batchid);
  713. if (batch) obj.batch = batch.batch;
  714. }
  715. }
  716. return obj;
  717. }
  718. // 确认学生打印证书
  719. async printCert({ ids }) {
  720. const res = await this.model.updateMany(
  721. { _id: { $in: ids.map(i => ObjectId(i)) } },
  722. { cert: '1' }
  723. );
  724. return res;
  725. }
  726. // 根据计划id找到学校是否上传学生
  727. async getSchoolStudent({ planid }) {
  728. const res = await this.model.aggregate([
  729. { $match: { planid } },
  730. { $group: { _id: '$schid', sum: { $sum: 1 } } },
  731. { $project: { _id: 0, schid: '$_id', schnum: '$sum' } },
  732. ]);
  733. return res;
  734. }
  735. // excel导出表头设置
  736. metaBx(type) {
  737. const header = [
  738. {
  739. header: '姓名',
  740. key: 'name',
  741. width: 20,
  742. },
  743. ];
  744. return header;
  745. }
  746. }
  747. module.exports = StudentService;