'use strict'; const assert = require('assert'); const _ = require('lodash'); const { ObjectId } = require('mongoose').Types; const moment = require('moment'); const { CrudService } = require('naf-framework-mongoose/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; class LessonService extends CrudService { constructor(ctx) { super(ctx, 'lesson'); this.model = this.ctx.model.Lesson; this.tmodel = this.ctx.model.Trainplan; this.clamodel = this.ctx.model.Class; this.lmodel = this.ctx.model.Lessonmode; this.teamodel = this.ctx.model.Teacher; this.stumodel = this.ctx.model.Student; this.schmodel = this.ctx.model.School; this.headteamodel = this.ctx.model.Headteacher; this.umodel = this.ctx.model.User; this.nmodel = this.ctx.model.Notice; } // 自动排课私有方法 async autolesson({ id }) { // 首先将课程表清空 const res = await this.tmodel.findById(id); if (!res) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } const terms = res.termnum; const _lessonmode = await this.lmodel.find(); // 循环取得所有期 for (const elm of terms) { // 根据期id清空课程表 await this.model.deleteMany({ termid: elm.id }); // 清空成功后,循环取得当前期下所有批次信息 const batchs = elm.batchnum; for (const batch of batchs) { // 取得当前批次开始结束日期,并根据日期取得所有天数 const sedays = await this.getAllDays(batch.startdate, batch.enddate); // 根据批次取得当前批次下所有班级 const _classs = await this.clamodel.find({ planid: id, termid: elm.id, batchid: batch.id, }); // 循环班级 const teachids = []; for (const cla of _classs) { // 取得课程模板信息 let lessonmode_ = _.find(_lessonmode, { type: cla.type }); if (!lessonmode_) { lessonmode_ = _lessonmode[0]; if (!lessonmode_) { throw new BusinessError( ErrorCode.DATA_NOT_EXIST, '课程模板信息不存在' ); } } // 取得模板内容并转化成json const lessons_ = JSON.parse(lessonmode_.lessons); // 记录天数 let i = 1; // 循环天数 const newlesson = []; for (const day of sedays) { // 循环课程模板,将模板信息排入班级课程表中 for (const lessm of lessons_) { // 循环插入模板信息 if (lessm['day' + i] !== '--') { let _subid = ''; if (lessm['day' + i + 'type'] === '课程') { _subid = lessm['day' + i + 'subid']; } else { _subid = ''; } let allday = 0; if (i === 6) { // 判断是否有外市的学生有的时候 将其设置为半天 const ishalfday = await this.ishalfday(cla.id); if (ishalfday) { allday = 1; } } const data = { subid: _subid, subname: lessm['day' + i], date: day, time: lessm.time, day: allday, }; // 将教师按照分数的综合成绩排序,上报时间,安排教师. const teacher_ = await this.autoteacher(_subid, teachids); if (teacher_) { data.teaid = teacher_.id; data.teaname = teacher_.name; teachids.push(teacher_.id); } newlesson.push(data); } } i = i + 1; } const newdata = { termid: elm.id, batchid: batch.id, classid: cla.id, lessons: newlesson, }; // 将课程信息填入课程表 await this.model.create(newdata); } } } } // 自动排教师,按照分数的综合成绩排序,上报时间,安排教师 async autoteacher(subid, teachids) { // 按照上报时间取得所有老师,进行正序排列 const teachers = await this.teamodel .find({ subid, status: '4' }) .sort({ zlscore: '-1', msscore: '-1', xsscore: '-1' }); for (const teaid of teachids) { _.remove(teachers, item => item.id === teaid); } let teacher = {}; if (teachers.length > 0) { teacher = teachers[0]; } return teacher; } // 判断是否为半天 async ishalfday(classid) { // 通过班级id取得所有学生 const students = await this.stumodel.find({ classid }); let res = false; for (const stu of students) { const sch = await this.schmodel.findOne({ code: stu.schid }); if (sch && sch.hascar === '0') { res = true; break; } } return res; } // 取得日期间所有日期 async getAllDays(begin_date, end_date) { const errArr = [], resultArr = [], dateReg = /^[2]\d{3}-[01]\d-[0123]\d$/; if ( typeof begin_date !== 'string' || begin_date === '' || !dateReg.test(begin_date) ) { return errArr; } if ( typeof end_date !== 'string' || end_date === '' || !dateReg.test(end_date) ) { return errArr; } try { const beginTimestamp = Date.parse(new Date(begin_date)), endTimestamp = Date.parse(new Date(end_date)); // 开始日期小于结束日期 if (beginTimestamp > endTimestamp) { return errArr; } // 开始日期等于结束日期 if (beginTimestamp === endTimestamp) { resultArr.push(begin_date); return resultArr; } let tempTimestamp = beginTimestamp, tempDate = begin_date; // 新增日期是否和结束日期相等, 相等跳出循环 while (tempTimestamp !== endTimestamp) { resultArr.push(tempDate); // 增加一天 tempDate = moment(tempTimestamp).add(1, 'd').format('YYYY-MM-DD'); // 将增加时间变为时间戳 tempTimestamp = Date.parse(new Date(tempDate)); } // 将最后一天放入数组 resultArr.push(end_date); return resultArr; } catch (err) { return errArr; } } // 根据计划id、教师id查询所有班级信息 async classbyteaid({ planid, teaid }) { // 取得传入的计划id与教师id // 根据计划id取得所有期 const plan = await this.tmodel.findById(planid); if (!plan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } const terms = await plan.termnum; // 循环取得所有期信息 const data = []; for (const term of terms) { // 根据期id与教师id查出课程班级信息 const lessons = await this.model.find({ termid: term.id, 'lessons.teaid': teaid, }); const batchs = await term.batchnum; for (const elm of lessons) { const newdata = {}; const batch = await batchs.id(elm.batchid); newdata.planid = planid; newdata.title = plan.title; newdata.termid = elm.termid; newdata.term = term.term; newdata.batchid = elm.batchid; newdata.batch = batch.batch; newdata.classid = elm.classid; if (elm.classid) { const cla = await this.clamodel.findById(elm.classid); if (cla) { newdata.classname = cla.name; } } const _lessons = elm.lessons.filter(item => item.teaid === teaid); newdata.lessons = _lessons; data.push(newdata); } } return data; } // 根据计划id、教师id查询所有班级信息 async teaclass({ planid, teaid }) { // 取得传入的计划id与教师id // 根据计划id取得所有期 const plan = await this.tmodel.findById(planid); if (!plan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } const terms = await plan.termnum; // 循环取得所有期信息 const data = []; for (const term of terms) { // 根据期id与教师id查出课程班级信息 const lessons = await this.model.find({ termid: term.id, 'lessons.teaid': teaid, }); for (const elm of lessons) { if (elm.classid) { const cla = await this.ctx.service.class.fetch({ id: elm.classid }); data.push(cla); } } } return data; } async uplessones(data) { for (const _data of data) { await this.model.findByIdAndUpdate(_data.id, _data); } } /** * 修改课表的状态,并发送信息 * @param {Array} ids 要修改的课表 */ async check({ ids }) { // 1,修改课表状态; TODO 2,拿到所有的班级,获取所有人员;3,然后发送信息 const list = await this.model.find({ _id: { $in: ids } }); const res = await this.model.updateMany({ _id: { $in: ids } }, { status: '1' }); // 循环课表 for (const lessonInfo of list) { // 获取期数 const { termid, classid, lessons } = lessonInfo; const planRes = await this.tmodel.findOne({ termnum: { $elemMatch: { _id: termid } } }); if (!planRes) continue; const term = planRes.termnum.find(f => ObjectId(termid).equals(f._id)); if (!term) continue; const { term: termnum, batchnum } = term; let start; let end; if (batchnum) { const { startdate, enddate } = batchnum; if (startdate) start = startdate; if (enddate) end = enddate; } const classInfo = await this.clamodel.findById(classid); // 先查找信息,如果有,不需要创建,修改创建信息,获取数据 const content = `欢迎参加由吉林省高等学校毕业生就业指导中心举办的"双困生培训会"第${termnum}期-${classInfo.name}${classInfo.name.includes('班') ? '' : '班'}${start ? `(${start}至${end})` : ''}`; let is_update = false; let nres = await this.nmodel.findOne({ planyearid: planRes.planyearid, planid: planRes._id, termid, classid, noticeid: 'system', type: '4', }); console.log(nres); let alreadyList = []; if (nres) { const { notified } = nres; alreadyList = notified.filter(i => i.status === '1'); is_update = true; } if (!is_update) { nres = await this.nmodel.create({ planyearid: planRes.planyearid, planid: planRes._id, termid, classid, noticeid: 'system', type: '4', content, }); } const { headteacherid, lyteacherid } = classInfo; const headteacher = await this.headteamodel.findById(headteacherid); if (headteacher) { const r = await this.toSendMsg(headteacher, 'headteacher', termnum, nres._id, content, alreadyList); if (r && !is_update) nres.notified.push(r); else if (r && is_update) { const dr = nres.notified.find(f => f.notifiedid === r.notifiedid); if (!dr) nres.notified.push(r); } } // 礼仪教师和班主任不是一个人时查礼仪教师是班主任还是任课教师,然后发消息 if (lyteacherid !== headteacherid) { let lyTeacher = await this.headteamodel.findById(lyteacherid); if (lyTeacher) { const r = await this.toSendMsg(lyTeacher, 'headteacher', termnum, nres._id, content, alreadyList); if (r && !is_update) nres.notified.push(r); else if (r && is_update) { const dr = nres.notified.find(f => f.notifiedid === r.notifiedid); if (!dr) nres.notified.push(r); } } else { lyTeacher = await this.teamodel.findById(lyteacherid); if (lyTeacher) { const r = await this.toSendMsg(lyTeacher, 'teacher', termnum, nres._id, content, alreadyList); if (r && !is_update) nres.notified.push(r); else if (r && is_update) { const dr = nres.notified.find(f => f.notifiedid === r.notifiedid); if (!dr) nres.notified.push(r); } } } } // 获取所有任课教师ids const teacherList = _.compact(_.uniq(lessons.map(i => i.teaid))); if (teacherList) { for (const tea of teacherList) { const teacher = await this.teamodel.findById(tea); if (!teacher) continue; const r = await this.toSendMsg(teacher, 'teacher', termnum, nres._id, content, alreadyList); if (r && !is_update) nres.notified.push(r); else if (r && is_update) { const dr = nres.notified.find(f => f.notifiedid === r.notifiedid); if (!dr) nres.notified.push(r); } } } nres.save(); } } async toSendMsg(teacherInfo, type, term, nresid, content, alreadyList) { const r = alreadyList.find(f => ObjectId(f.notifiedid).equals(teacherInfo._id)); if (r) return; let person = null; if (teacherInfo) { let email; if (type === 'headteacher') { const { qq } = teacherInfo; if (qq) email = `${qq}@qq.com`; } else { email = teacherInfo.email; } // 发邮件 if (email) { // console.error(`${teacherInfo.name}-email:${email}`); const subject = '吉林省高等学校毕业生就业指导中心通知'; const text = teacherInfo.name + `${content},请您尽快登陆双困生培训系统查看您的安排,系统邮件,请勿回复!`; this.ctx.service.util.sendMail(email, subject, text); } // 获取openid,推送 const teacherUser = await this.umodel.findOne({ uid: teacherInfo._id }); if (teacherUser) { const { openid } = teacherUser; if (openid) { const tourl = this.ctx.app.config.baseUrl + '/msgconfirm/?userid=' + teacherUser.uid + '¬iceid=' + nresid; // TODO 推送 await this.ctx.service.weixin.sendTemplateDesign( this.ctx.app.config.REVIEW_TEMPLATE_ID, openid, '您有一个新的通知,请点击信息,确认您已收到信息!(若已确认,则无需理会)', '您有新的安排', content, '感谢您的使用', tourl ); person = { notifiedid: teacherUser.uid, username: teacherUser.name }; } } } return person; } // 新排课,从计划中拿出来对应的课表 async newArrange({ planid, termid }) { const lmodelList = await this.lmodel.find(); const trainplan = await this.tmodel.findById(planid); if (!trainplan) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '计划不存在'); let { termnum } = trainplan; // 指定期的数据 termnum = JSON.parse(JSON.stringify(termnum)); if (!termnum) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '该期不存在'); // 该期的课表,没有就添加 await this.model.deleteMany({ termid }); const sterm = termnum.find(f => f._id === termid); const { batchnum } = sterm; // 确保batchnum是数组 if (!_.isArray(batchnum)) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '该期下批次数据错误'); for (const b of batchnum) { const { _id: batchid, class: classArrange, type, startdate, enddate } = b; const classList = await this.clamodel.find({ planid, termid, batchid }); // 确保list是数组 if (!classList || classList.length === 0) continue; const clist = JSON.parse(JSON.stringify(classList)); for (const c of clist) { // 排指定班 const { name, ...lessinfo } = await this.partsOfClass(c); // 找到指定班级的安排 这里目前只能用name找,这个地方很不稳定,需要找到其他的具有唯一性的判断来执行这个find const clalr = classArrange.find(f => f.name === name); // 没找到指定班级的安排 if (!clalr) { console.error('没有找到指定安排'); continue; } const { lessons: ntemplate } = clalr; // 如果没有模板 if (!ntemplate) { console.error('没有找到指定班级安排模板'); continue; } // 根据班级类型找到原课表模板 let lessonModel = lmodelList.find(f => f.code === type); lessonModel = JSON.parse(JSON.stringify(lessonModel)); // 原模板 let { lessons: otemplate } = lessonModel; otemplate = JSON.parse(otemplate); // 日期列表,感谢裕哥能给我留个可用的东西 const dayList = await this.getAllDays(startdate, enddate); const lessons = []; for (let i = 0; i < dayList.length; i++) { for (const ot of otemplate) { const date = dayList[i]; const { time } = ot; const keys = Object.keys(ot).filter(f => f.includes(`day${i + 1}`)); const kvs = {}; for (const key of keys) { // 将原课表的每日,每个时间段的安排整理成object if (key.startsWith('day') && key.endsWith('type')) { // console.log(`${key}=>${ot[key]}`); // kvs.type = ot[key]; } else if (key.startsWith('day') && key.endsWith('subid')) { kvs.subid = ot[key]; } else { kvs.subname = ot[key]; } } // 整理完的object,如果有subid,就是课程,找教师 const tsubid = _.get(kvs, 'subid'); if (tsubid) { const r = ntemplate.find(f => f.subid === tsubid); if (r) { const { teaid, teaname } = r; if (teaid && teaname) { kvs.teaid = teaid; kvs.teaname = teaname; } } } const obj = { date, time, ...kvs }; lessons.push(obj); } } // 最后整合 const classLesson = { ...lessinfo, lessons }; // 保存 await this.model.create(classLesson); } } } // 新排课,将班级层面处理抽出来 async partsOfClass(classinfo) { classinfo = JSON.parse(JSON.stringify(classinfo)); const { termid, batchid, _id: classid, name } = classinfo; const obj = { termid, batchid, classid, name }; return obj; } } module.exports = LessonService;