'use strict'; const _ = require('lodash'); const { CrudService } = require('naf-framework-mongoose/lib/service'); const assert = require('assert'); const { BusinessError, ErrorCode } = require('naf-core').Error; const XLSX = require('xlsx'); const utils = require('../utils/utils.js'); class TrainplanService extends CrudService { constructor(ctx) { super(ctx, 'trainplan'); this.model = this.ctx.model.Trainplan; this.clamodel = this.ctx.model.Class; this.umodel = this.ctx.model.User; this.smodel = this.ctx.model.School; this.tmodel = this.ctx.model.Teacher; this.stumodel = this.ctx.model.Student; } // async create(data) { // const terminfo = await data.termnum; // console.log(terminfo); // const { batchnum: { type, name, number }, term } = terminfo; // console.log(type); // if (type === 1) { // const classdata = { name, number, term, type }; // await this.clamodel.create(classdata); // } // if (type === 0) { // for (let i = 0; i < class; i++) { // const name = '第' + term + '期' + batch + '批次' + i + '班'; // const classdate = { name, number, term, type, newbatch }; // await this.clamodel.create(classdate); // } // } // return this.tpmodel.create(data); // } // } async update({ id }, data) { const trainplan = await this.model.findById(id); // 保存原数据 const trainplanold = _.cloneDeep(trainplan); const { year, title, termnum, festivals, status, school } = data; if (year) { trainplan.year = year; } if (title) { trainplan.title = title; } if (termnum) { trainplan.termnum = termnum; } if (school) { trainplan.school = school; } if (festivals) { trainplan.festivals = festivals; } if (status === '1') { trainplan.status = status; } // 如果培训计划状态改为发布,发送培训计划信息,并自动生成班级 const res = await trainplan.save(); if (res) { if (status === '1') { // 自动生成班级 // await this.autoclass(res, trainplanold); await this.autoclassNew(res, trainplanold); // 将生成的班级重新将班级排班名 // await this.autoclassname(res); // 发送培训计划信息通知给相应人员 // 查询所有入库的教师 const teachers = await this.tmodel.find({ status: '4' }); for (const teacher of teachers) { const teacherid = teacher._id; const _teacher = await this.umodel.findOne({ uid: teacherid, type: '3' }); const openid = _teacher.openid; const detail = trainplan.title + '已发布,请注意查收!'; const date = await this.ctx.service.util.updatedate(); const remark = '感谢您的使用'; if (openid) { this.ctx.service.weixin.sendTemplateMsg(this.ctx.app.config.REVIEW_TEMPLATE_ID, openid, '您有一个新的通知', detail, date, remark); } } // 查询所有学校用户 const schools = await this.umodel.find({ type: '2' }); for (const school of schools) { const openid = school.openid; const detail = trainplan.title + '已发布,请注意查收!'; const date = await this.ctx.service.util.updatedate(); const remark = '感谢您的使用'; if (openid) { this.ctx.service.weixin.sendTemplateMsg(this.ctx.app.config.REVIEW_TEMPLATE_ID, openid, '您有一个新的通知', detail, date, remark); } } } } return res; } // 自动生成班级私有方法 async autoclassNew(res) { // 删除所有计划下的班级 await this.clamodel.deleteMany({ planid: res.id }); // 循环出所有班级进行添加操作 for (const term of res.termnum) { for (const batch of term.batchnum) { const classs = await batch.class; for (const cla of classs) { const newdata = { name: cla.name, number: cla.number, batchid: batch.id, termid: term.id, planid: res.id, type: cla.type, headteacherid: cla.headteacherid }; await this.clamodel.create(newdata); } } } } // 自动生成班级私有方法 async autoclass(res, trainplanold) { // 首先比较当前数据和原数据的值是否有不同 // 保存后所有期id const tremid_res = _.map(res.termnum, 'id'); // 保存前所有期id const tremid_old = _.map(trainplanold.termnum, 'id'); // 取得要删除的期id,进行班级中删除已删除期的班级 const deltrem = _.difference(tremid_old, tremid_res); // 循环删除已经删除期的所有班级 for (const elm of deltrem) { await this.clamodel.deleteMany({ termid: elm }); } // 取得所有新加期id const addtrem = _.difference(tremid_res, tremid_old); // 清空后循环取得所有期进行批次操作 const terms = res.termnum; for (const el of terms) { // 判断是否新加期 if (_.indexOf(addtrem, el.id) !== -1) { // 循环当前新加期的批次列表,根据批次id和班级数生成班级信息 const batchnums = el.batchnum; for (const batchnum of batchnums) { // 取得当前批次的班级数 const classnum = batchnum.class; for (const cla of classnum) { const newdata = { name: cla.name, number: cla.number, batchid: batchnum.id, termid: el.id, planid: res.id, type: cla.type }; await this.clamodel.create(newdata); } } } else { // 不是新加期,更新期信息 // 保存后所有期id const batchid_res = _.map(el.batchnum, 'id'); // 保存前所有期id const batchid_old = _.map(trainplanold.termnum.id(el.id).batchnum, 'id'); // 取得要删除的期id,进行班级中删除已删除期的班级 const delbatchs = _.difference(batchid_old, batchid_res); // 循环删除已经删除期的所有班级 for (const delba of delbatchs) { await this.clamodel.deleteMany({ termid: el.id, batchid: delba }); } // 取得所有新加期id const addbatch = _.difference(batchid_res, batchid_old); const batchnums = el.batchnum; for (const batchnum of batchnums) { // 取得当前批次是否有删除 // 判断是否新加期 if (_.indexOf(addbatch, batchnum.id) !== -1) { // 取得当前批次的班级数 const classnum = batchnum.class; for (const cla of classnum) { const newdata = { name: cla.name, number: cla.number, batchid: batchnum.id, termid: el.id, planid: res.id, type: cla.type }; await this.clamodel.create(newdata); } } else { if (batchnum.class === trainplanold.termnum.id(el.id).batchnum.id(batchnum.id).class) { // 编辑只会针对班级人数进行修改。 const _class = await this.clamodel.find({ termid: el.id, batchid: batchnum.id }); if (_class.length !== 0) { for (const ee of _class) { ee.number = batchnum.number; await ee.save(); } } else { const classnum = batchnum.class; for (const cla of classnum) { const newdata = { name: cla.name, number: cla.number, batchid: batchnum.id, termid: el.id, planid: res.id, type: cla.type }; await this.clamodel.create(newdata); } } } else { // 当班级数有更改时 // 删除所有班级 并重新生成班级 await this.clamodel.deleteMany({ termid: el.id, batchid: batchnum.id }); const classnum = batchnum.class; for (const cla of classnum) { const newdata = { name: cla.name, number: cla.number, batchid: batchnum.id, termid: el.id, planid: res.id, type: cla.type }; await this.clamodel.create(newdata); } } } } } } } // // 将分好的班级重新编排名字 // async autoclassname(res) { // // 取得所有期id // const tremid_res = _.map(res.termnum, 'id'); // for (const termid of tremid_res) { // const classs = await this.clamodel.find({ planid: res.id, termid }); // let i = 0; // for (const cla of classs) { // i = i + 1; // cla.name = i; // await cla.save(); // } // } // } async exportExcel({ trainplanIds }) { const nowDate = new Date().getTime(); const path = 'D:\\wwwroot\\service\\service-file\\upload\\train\\' + nowDate + '.xlsx'; const respath = 'http://free.liaoningdoupo.com:80/files/train/' + nowDate + '.xlsx'; const wb = { SheetNames: [], Sheets: {}, }; for (let i = 0; i < trainplanIds.length; i++) { // 批次期次都在这里面 const trainplan = await this.model.findOne({ _id: trainplanIds[i] }); // 这个计划下所有的学生 const studentList = await this.stumodel.find({ planid: trainplanIds[i] }); // 计划名称 const trainplandName = trainplan.title; // 在计划中找到这个学生在哪期以及哪期下的哪批次 for (const student of studentList) { student.isComming = utils.getIsNot(student.isComming); student.trainplandName = trainplandName; // 期次 const term = trainplan.termnum.filter(term => { return term.id === student.termid; }); if (term.length > 0) { student.termName = term[0].term; } // 批次 if (term.length !== 0) { const batch = term[0].batchnum.filter(batch => { return batch.id === student.batchid; }); if (batch.length > 0) { student.batchName = JSON.parse(JSON.stringify(batch[0])).name; } } student.is_fine = utils.getIsNot(student.is_fine); } const _headers = [ { key: 'trainplandName', title: '计划标题' }, { key: 'termName', title: '期次' }, { key: 'batchName', title: '批次' }, { key: 'school_name', title: '学校' }, { key: 'faculty', title: '院系' }, { key: 'major', title: '专业' }, { key: 'name', title: '姓名' }, { key: 'id_number', title: '身份证号' }, { key: 'phone', title: '手机号' }, { key: 'gender', title: '性别' }, { key: 'nation', title: '民族' }, { key: 'edua_level', title: '学历层次' }, { key: 'edua_system', title: '学制' }, { key: 'entry_year', title: '入学年份' }, { key: 'finish_year', title: '毕业年份' }, { key: 'school_job', title: '在校职务' }, { key: 'qq', title: 'QQ号' }, { key: 'email', title: '邮箱' }, { key: 'openid', title: '微信openid' }, { key: 'family_place', title: '家庭位置' }, { key: 'family_is_hard', title: '是否困难' }, { key: 'have_grant', title: ' 是否获得过助学金' }, { key: 'job', title: '职务' }, { key: 'bedroom', title: '寝室号' }, { key: 'is_fine', title: '是否优秀' }, // { key: 'selfscore', title: '个人分' }, // { key: 'score', title: '总分' }, // { key: 'diy', title: '自定义' }, { key: 'isComming', title: '是否签到' }, ]; // 需要打出的列表 const _data = studentList; const headers = _headers .map(({ title }) => title) .map((v, i) => Object.assign({}, { v, position: String.fromCharCode(65 + i) + 1 }) ) .reduce( (prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v } }), {} ); const data = _data .map((v, i) => _headers.map(({ key }, j) => Object.assign( {}, { v: v[key], position: String.fromCharCode(65 + j) + (i + 2) } ) ) ) .reduce((prev, next) => prev.concat(next)) .reduce( (prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v } }), {} ); // 合并 headers 和 data const output = Object.assign({}, headers, data); // 获取所有单元格的位置 const outputPos = Object.keys(output); // 计算出范围 const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1]; // 构建 workbook 对象 wb.SheetNames.push('sheet' + i); wb.Sheets['sheet' + i] = Object.assign({}, output, { '!ref': ref }); } // 导出 Excel XLSX.writeFile(wb, path); return respath; } async updateclass({ trainplanid, classid, rightHeader }) { assert(trainplanid && classid && rightHeader, '缺少参数项'); // 根据全年计划表id查出对应的全年计划详细信息 const trainplan = await this.model.findById(trainplanid); if (!trainplan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } for (const term of trainplan.termnum) { for (const batch of term.batchnum) { const class_ = await batch.class.id(classid); if (class_) { class_.headteacherid = rightHeader; } } } return await trainplan.save(); } } module.exports = TrainplanService;