'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'); const moment = require('moment'); const XLSXStyle = require('xlsx-style'); 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; this.schmodel = this.ctx.model.Schtime; this.lmmodel = this.ctx.model.Lessonmode; } async create(data) { const { planyearid, year, title } = data; assert(planyearid, '缺少大批次信息'); assert(year, '缺少年度'); assert(title, '缺少标题'); const res = await this.model.create(data); let planid = ''; if (res) planid = res._id; const schoolList = await this.smodel.find(); const schtimeArr = []; for (const sch of schoolList) { const { code } = sch; const obj = { schid: code, year, planid }; const schtimeres = await this.schmodel.create(obj); if (schtimeres) schtimeArr.push(schtimeres); } if (!schtimeArr.every(e => e)) { throw new BusinessError(ErrorCode.DATA_INVALID, '学校计划生成失败'); } else return res; } 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; } // 日历安排中添加课表信息,查询每种班级类型的课表,然后显示 if (trainplan.termnum) { // trainplan.termnum = trainplan.termnum = await this.termGetLesson(trainplan.termnum); } // 如果培训计划状态改为发布,发送培训计划信息,并自动生成班级 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 ); } } } // 查哪个学校schtime表没有生成,就给生成了 const schoolList = await this.smodel.find(); for (const school of schoolList) { const r = await this.schmodel.findOne({ year, planid: id, schid: school.code }); if (r) continue; const obj = { schid: school.code, year, planid: id }; await this.schmodel.create(obj); } } return res; } async termGetLesson(termnum) { const lessonModelList = await this.lmmodel.find(); for (const term of termnum) { for (const batch of term.batchnum) { const { class: classes, startdate, enddate } = batch; // 获取每批次下每个班的班级类型 const typeList = _.uniq(classes.map(i => i.type)); const h = _.head(typeList); if (!h) continue; const tem = lessonModelList.find(f => f.type === h); if (!tem) continue; let { lessons } = tem; if (!lessons) continue; lessons = JSON.parse(lessons); // 过滤出上课的时间段 lessons = lessons.filter(f => { const keys = Object.keys(f).filter(f => f.includes('subid')); return keys.length > 0; }); // 记录上课的时间 const times = []; // 记录所有的科目 let subject = []; lessons.map(i => { times.push(i.time); const keys = Object.keys(i); let arr = []; for (const key of keys) { if (key.match(/\d/g)) arr.push(_.head(key.match(/\d/g))); } arr = _.uniq(arr); for (const ai of arr) { if (i[`day${ai}subid`]) { subject.push({ subname: i[`day${ai}`], subid: i[`day${ai}subid`], day: ai, }); } } return i; }); // 去重 subject = _.uniqBy(subject, 'subid'); // 获得天列表 const dnum = moment(enddate).diff(moment(startdate), 'days') + 1; const dayList = []; for (let ind = 0; ind < dnum; ind++) { dayList.push(moment(startdate).add(ind, 'd').format('YYYY-MM-DD')); } // 将subject中的day换成日期 for (const sub of subject) { sub.day = dayList[sub.day * 1 - 1]; sub.time = times; } batch.lessons = subject; } } return termnum; } // 自动生成班级私有方法 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: 'isComming', title: '是否签到' }, { key: 'selfscore', title: '个人分' }, { key: 'score', 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 exportSchool({ trainplanId }) { // 备注 const remarks = []; // 期数 let termCount = []; // 班级数 const classCount = []; // 日期 const studyTime = []; // 合并单元格坐标 const colRows = []; // 列起始 let colzb = 3; // 行起始 const rowzb = 1; // const colRow = { // s: { c: 3, r: rowzb }, // e: { c: 6, r: rowzb }, // }; // colRows.push(colRow); const shcoolList = []; // 计划表 const trainplan = await this.model.findOne({ _id: trainplanId }); // 学校报名表 const schtime = await this.schmodel.find({ planid: trainplanId }); // 期次 const termnums = trainplan.termnum; // 学校学校数据 // const schools = trainplan.school; const schools = await this.smodel.find({}); // 组装学校数据 for (let i = 0; i < schools.length; i++) { // 学校数据 const shcool = []; // 序号 shcool.push(i + 1); // 学校名 shcool.push(schools[i].name); // 总人数 shcool.push(''); for (const termnum of termnums) { // 批次 const batchnum = termnum.batchnum; // 期次所占的格(期占格) const qizhange = batchnum.length - 1; /** * 合并单元格元素(decode_range方法解析数据格式) { s: { //s start 开始 c: 1,//cols 开始列 r: 0 //rows 开始行 }, e: {//e end 结束 c: 4,//cols 结束列 r: 0 //rows 结束行 } } */ // 添加坐标 const colRow = { s: { c: colzb, r: rowzb }, e: { c: colzb + qizhange, r: rowzb }, }; // colzb为上一次终止,那么起始需+1, colzb = colzb + qizhange + 1; colRows.push(colRow); // 向其中加入空格,以备合并单元格使用 const qi = []; qi.push(termnum.term); for (let index = 0; index < qizhange; index++) { qi.push(''); } termCount = [ ...termCount, ...qi ]; // 循环 for (const batch of batchnum) { // 把班级数与日期放入数组中 classCount.push(batch.class.length); let startDate = batch.startdate; startDate = startDate.substr(5, 2) + '.' + startDate.substr(8, 2); let endDate = batch.enddate; endDate = endDate.substr(5, 2) + '.' + endDate.substr(8, 2); studyTime.push(startDate + '-' + endDate); // 拿着batch的id去schtime表中的arrange中查remark,将结果存入remarks中即可完成备注数组 let remark = ''; for (const sch of schtime) { // 计划中学校的code=上报时的code if (schools[i].code === sch.schid) { for (const arrange of sch.arrange) { if (arrange.batchid === batch.id) { remark = arrange.remark; // 查到了退出即可因为是个数组 // 总人数 shcool.push(arrange.number); } } } } remarks.push(remark); } } shcoolList.push(shcool); } const wscols = [ { wpx: 50 }, // 第一列宽度设置单位px ]; let xuhao = [ XLSX.utils.decode_range('A1:A4') ]; const xuexiao = [ XLSX.utils.decode_range('B1:B4') ]; xuhao = [ ...xuhao, ...xuexiao, ...colRows ]; const data = []; // 第一行 const row0 = [ '序号', '学校名称', '备注' ].concat(remarks); data.push(row0); // 第二行 const row1 = [ '', '', '期数' ].concat(termCount); data.push(row1); // 第三行 const row2 = [ '', '', '班级数' ].concat(classCount); data.push(row2); // 第四行 const row3 = [ '', '', '日期' ].concat(studyTime); data.push(row3); for (const shcoolL of shcoolList) { let count = 0; for (let i = 3; i < shcoolL.length; i++) { count += parseInt(shcoolL[i]); } // 计算出总人数,开始总认识默认的是'',这里赋值 shcoolL[2] = count; data.push(shcoolL); } // ...以此类推即可 /** 头部-行列信息*/ const ws = XLSX.utils.aoa_to_sheet(data); // 构建 workbook 对象 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 = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); ws['!cols'] = wscols; // xuhao.push(XLSX.utils.decode_range('B1:D1')) // 测试数据 仓库1模拟数据 ws['!merges'] = xuhao; XLSX.writeFile(wb, path); return respath; } // 导出学校大表 async exportPlan({ trainplanId }) { const wscols = [ { wpx: 50 }, // 第一列宽度设置单位px ]; const monthList = []; // 月份合并单元格 const colzb = 0; let rowzb = 1; // 头部合并单元格 const coltb = 0; let rowtb = 0; // 人数合并单元格 const colrs = 0; let rowrs = 1; // 人数数量合并单元格 const colrssl = 0; let rowrssl = 3; // 班级数合并单元格 const colbjs = 0; let rowbjs = 1; // 班级数数量合并单元格 const colbjssl = 0; let rowbjssl = 3; // 数据 const data = []; let colRowBJSSL = {}; // 这里是头部颜色 const tatleCell = { v: '', s: { fill: { fgColor: { rgb: '191970' } } } }; // 坐标 const tatleCellstyle = 0; let tatleRowstyle = 0; const styleTatle = []; // 这里是月份颜色 const monthCell = [ { v: '一月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '二月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '三月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '四月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '五月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '六月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '七月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '八月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '九月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '十月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '十一月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, { v: '十二月', s: { fill: { fgColor: { rgb: 'B0E2FF' } } } }, ]; // 坐标 const monthCellstyle = 0; let monthRowstyle = 1; const styleMonth = []; // 这里是假期颜色 const festivalsCell = { v: '', s: { fill: { fgColor: { rgb: 'A2CD5A' } } }, }; // 坐标 const festivalsCellstyle = 0; let festivalsRowstyle = 0; const stylefestivals = []; // 计划表 const trainplan = await this.model.findOne({ _id: trainplanId }); const termnum = trainplan.termnum; let classNum = 0; // 获取最大的班级数,也就是月份的高 for (const term of termnum) { if (term.classnum > classNum) { classNum = parseInt(term.classnum); } } // 得到所有的节日日期的数组,然后循环时注意得到一个删除一个 const festivals = trainplan.festivals; const festivalList = this.getfestivalList(festivals); const termnumList = this.gettermnumList(termnum); // 得到所有班级的数组,然后循环时注意得到一个删除一个 // 循环12个月,得到12个月以及每个月的数据 for (let index = 1; index < 13; index++) { // 这里增加表格头部下标 const tatleCells = XLSX.utils.encode_cell({ c: tatleCellstyle, r: tatleRowstyle, }); tatleRowstyle = tatleRowstyle + classNum + 3; styleTatle.push(tatleCells); // 这里是月份颜色 const monthCells = XLSX.utils.encode_cell({ c: monthCellstyle, r: monthRowstyle, }); monthRowstyle = monthRowstyle + classNum + 3; styleMonth.push(monthCells); for (let j = 0; j < festivalList.length; j++) { const festival = festivalList[j]; // 如果月份相同时才会增加 const yue = parseInt(festival.substr(5, 2)); const lie = parseInt(festival.substr(8, 2)); if (index === yue) { // 这里是假期颜色这一列列7行都是这个颜色 for (let k = 0; k < classNum; k++) { const festivalsCells = XLSX.utils.encode_cell({ // 列 c: festivalsCellstyle + lie, r: festivalsRowstyle + k + 3, }); stylefestivals.push(festivalsCells); } } } festivalsRowstyle = festivalsRowstyle + classNum + 3; // 添加月份坐标 const colRow = { s: { c: colzb, r: rowzb }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: colzb, r: rowzb + classNum + 1 }, }; // rowzb为上一次终止,那么起始需+1,这里加3,代表头部+月份+星期,所以+3 rowzb = rowzb + classNum + 3; monthList.push(colRow); // 添加头部坐标 const colRowTB = { s: { c: coltb, r: rowtb }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: coltb + 33, r: rowtb }, }; // rowzb为上一次终止,那么起始需+1, rowtb = rowtb + classNum + 3; monthList.push(colRowTB); // 添加人数坐标 const colRowRS = { s: { c: colrs + 32, r: rowrs }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: colrs + 32, r: rowrs + 1 }, }; // rowzb为上一次终止,那么起始需+1, rowrs = rowrs + classNum + 3; monthList.push(colRowRS); // 添加人数数量坐标 const colRowRSSL = { s: { c: colrssl + 32, r: rowrssl }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: colrssl + 32, r: rowrssl + classNum - 1 }, }; // rowzb为上一次终止,那么起始需+1, rowrssl = rowrssl + classNum + 3; monthList.push(colRowRSSL); // 添加班级数坐标 const colRowBJS = { s: { c: colbjs + 33, r: rowbjs }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: colbjs + 33, r: rowbjs + 1 }, }; // rowzb为上一次终止,那么起始需+1, rowbjs = rowbjs + classNum + 3; monthList.push(colRowBJS); // 添加班级数数量坐标 colRowBJSSL = { s: { c: colbjssl + 33, r: rowbjssl }, // 保证留下7个空行,如果需要在上面加值,直接在下面加入即可第几空行加入就行 e: { c: colbjssl + 33, r: rowbjssl + classNum - 1 }, }; // rowzb为上一次终止,那么起始需+1, rowbjssl = rowbjssl + classNum + 3; monthList.push(colRowBJSSL); const resDate = this.makeCalendar(trainplan.year, index); data.push([ '' ]); data.push( [[ this.getBigMonth(index) + '月' ]] .concat(resDate.dlist) .concat([ '人数' ].concat([ '班级数' ])) ); data.push([ '' ].concat(resDate.tlist)); // 加列数组 for (let i = 0; i < classNum; i++) { data.push(''); } } // ...以此类推即可 /** 头部-行列信息*/ const ws = XLSX.utils.aoa_to_sheet(data); // 构建 workbook 对象 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 = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); ws['!cols'] = wscols; ws['!merges'] = monthList; // 头部赋值颜色需要计算出坐标 for (const tatlezb of styleTatle) { ws[tatlezb] = tatleCell; } // 月份赋值颜色需要计算出坐标 for (let index = 0; index < styleMonth.length; index++) { ws[styleMonth[index]] = monthCell[index]; } // 假期赋值颜色需要计算出坐标 for (const festivals of stylefestivals) { ws[festivals] = festivalsCell; } XLSXStyle.writeFile(wb, path); return respath; } // 获取批次日期列表 gettermnumList(termnums) { const termnumList = []; for (const termnum of termnums) { termnum.term; termnum.classnum; for (const batchnum of termnum.batchnum) { batchnum.batch; batchnum.class.length; batchnum.startdate; batchnum.enddate; } } return termnumList; } // 获取节假日集合 getfestivalList(festivals) { let dateList = []; for (let index = 0; index < festivals.length; index++) { dateList = [ ...dateList, ...utils.begindateEnddateSum( festivals[index].begindate, festivals[index].finishdate ), ]; } return dateList; } // 获取大月份传过来的值是以1月份开始的 getBigMonth(index) { const monthBig = [ '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', ]; return monthBig[index - 1]; } // 获取这个月份的所有日期1~30号或者31或者28,或者29 makeCalendar(year, month = 1, month0) { month0 = month; if (month * 1 < 10) month = '0' + month; // 获取这个月份的最大值 const days = moment(year + '-' + month).daysInMonth(); const dlist = this.getDayList(year, month, days, month0); while (dlist.dlist.length < 31) { dlist.dlist.push(''); } return dlist; } // 获取这个月份的1-30号经过加工的 getDayList(year, month, days, month0) { const dlist = []; const tlist = []; const all = {}; for (let index = 0; index < days; index++) { dlist.push( month0 + '月' + moment(year + '-' + month) .add(index, 'days') .format('D') + '日' ); let dayy = parseInt(index + 1); if (dayy * 1 < 10) dayy = '0' + dayy; tlist.push(this.getWeekDay(year + '-' + month + '-' + dayy)); } all.dlist = dlist; all.tlist = tlist; return all; } // 获取星期几 getWeekDay(datestr) { const weekday = moment(datestr).weekday(); if (weekday || weekday === 0) { const arr = [ '日', '一', '二', '三', '四', '五', '六' ]; return '星期' + arr[weekday]; } return ''; } // async updateclass({ trainplanid, classid, rightHeader }) { // assert(trainplanid && classid && rightHeader, '缺少参数项'); async updateclass({ trainplanid, termid, batchid, classid, rightHeader }) { assert( trainplanid && termid && batchid && classid && rightHeader, '缺少参数项' ); // 根据全年计划表id查出对应的全年计划详细信息 const trainplan = await this.model.findById(trainplanid); if (!trainplan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } const term = trainplan.termnum.id(termid); if (!term) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '期信息不存在'); } const batch = term.batchnum.id(batchid); if (!batch) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '批次信息不存在'); } const class_ = await batch.class.id(classid); if (class_) { class_.headteacherid = rightHeader; } const res = await trainplan.save(); if (res) { const cla_ = await this.clamodel.findOne({ termid, batchid, name: class_.name, }); if (cla_) { cla_.headteacherid = rightHeader; await cla_.save(); } } return res; } async updatereteacher({ trainplanid, termid, reteacher }) { assert(trainplanid && termid && reteacher, '缺少参数项'); // 根据全年计划表id查出对应的全年计划详细信息 const trainplan = await this.model.findById(trainplanid); if (!trainplan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '全年计划信息不存在'); } const term = await trainplan.termnum.id(termid); if (term) { term.reteacher = reteacher; } return await trainplan.save(); } } module.exports = TrainplanService;