lrf402788946 4 lat temu
rodzic
commit
25599ceec3

+ 2 - 0
app.js

@@ -9,10 +9,12 @@ class AppBootHook {
     const ctx = await this.app.createAnonymousContext();
     // 企业入驻申请消息接收事件
     // await ctx.service.rabbitmq.receiveQueueMsg('user_bind');
+    await ctx.service.rabbitmq.mission();
   }
 
   async serverDidReady() {
     // 应用已经启动完毕
+    const ctx = await this.app.createAnonymousContext();
   }
 }
 module.exports = AppBootHook;

+ 5 - 1
app/controller/.student.js

@@ -141,9 +141,13 @@ module.exports = {
     service: "getFineStudent",
   },
   exportStudent: {
-    requestBody: ["planid", "termid", "batchid", "classid", "model"],
+    requestBody: ["planid", "termid", "batchid", "classid", "model", 'missionid'],
     service: "exportStudent",
   },
+  toExport: {
+    requestBody: ["planid", "termid", "batchid", "classid", "model"],
+    service: "toExport",
+  },
   arrangeNumber: {
     parameters: {
       query: { classid: "classid" },

+ 4 - 4
app/controller/student.js

@@ -12,10 +12,10 @@ class StudentController extends Controller {
     this.service = this.ctx.service.student;
   }
 
-  async index() {
-    const data = await this.service.query(this.ctx.query);
-    this.ctx.ok({ ...data });
-  }
+  // async index() {
+  //   const data = await this.service.query(this.ctx.query);
+  //   this.ctx.ok({ ...data });
+  // }
 
   // GET
   // 查询

+ 1 - 1
app/controller/task.js

@@ -13,7 +13,7 @@ class TaskController extends Controller {
   }
 
   async export() {
-    const res = await this.service.export(this.ctx.request.body);
+    const res = await this.service.toExport(this.ctx.request.body);
     this.ctx.ok({ data: res });
   }
 }

+ 7 - 1
app/router.js

@@ -92,10 +92,16 @@ module.exports = app => {
   router.get('student', '/api/train/student/school', controller.student.getSchoolStudent);
   // 班级学生排号
   router.get('sutdent', '/api/train/student/arrangeNumber', controller.student.arrangeNumber);
-
+  // 建立导出学生的任务
   router.post(
     'student',
     '/api/train/student/export',
+    controller.student.toExport
+  );
+  // 导出学生
+  router.post(
+    'student',
+    '/api/train/mission/student/export',
     controller.student.exportStudent
   );
   // 学生表设置路由

+ 1 - 1
app/service/bedroom.js

@@ -19,7 +19,7 @@ class BedroomService extends CrudService {
     this.nmodel = this.ctx.model.Notice;
   }
 
-  async query({ code, ...data }, { skip, limit }) {
+  async query({ code, ...data }, { skip = 0, limit = 0 } = {}) {
     const query = { ...data };
     if (code) {
       query.code = { $regex: code };

+ 1 - 1
app/service/experience.js

@@ -13,7 +13,7 @@ class ExperienceService extends CrudService {
     this.model = this.ctx.model.Experience;
   }
 
-  async query(data, { skip, limit }) {
+  async query(data, { skip = 0, limit = 0 } = {}) {
     let res = await this.model.find(data).populate({ path: 'studentid', select: 'name job' }).skip(parseInt(skip))
       .limit(parseInt(limit));
     if (res.length > 0) {

+ 140 - 52
app/service/questionnaire.js

@@ -3,6 +3,7 @@
 
 const assert = require('assert');
 const _ = require('lodash');
+const moment = require('moment');
 const { ObjectId } = require('mongoose').Types;
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
@@ -12,6 +13,8 @@ class QuestionnaireService extends CrudService {
     super(ctx, 'qusetionnaire');
     this.questionnairemodel = this.ctx.model.Questionnaire;
     this.questionmodel = this.ctx.model.Question;
+    const { baseUrl } = _.get(this.ctx.app.config, 'mission');
+    if (baseUrl) this.missionBase = baseUrl;
   }
 
   // 插入问卷
@@ -73,57 +76,128 @@ class QuestionnaireService extends CrudService {
     return questionnaire;
   }
 
+  // 建立任务
+  async toExport(body) {
+    const { range, questionnaireid } = body;
+    const questionnaire = await this.questionnairemodel.findById(questionnaireid);
+    if (!questionnaire) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到问卷信息');
+    }
+    const fn = await this.toSetFileName(questionnaire.name, range);
+    const data = {
+      title: fn,
+      params: {
+        project: 'center',
+        service: 'questionnaire',
+        method: 'export',
+        body,
+      },
+    };
+    if (this.missionBase) {
+      const url = `${this.missionBase}/api/mission`;
+      const res = await this.ctx.curl(url, {
+        method: 'post',
+        headers: {
+          'content-type': 'application/json',
+        },
+        data,
+        dataType: 'json',
+      });
+      if (res.status !== 200 || res.data.errcode !== 0) {
+        throw new BusinessError(ErrorCode.SERVICE_FAULT, '创建任务失败');
+      }
+    } else {
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '未找到任务项目设置');
+    }
+  }
+
   /**
    * 导出问卷
-   * @param {Object} { range, direction, questionnaireid, modelList } 数据集合
+   * @param {Object} { range, direction, questionnaireid, modelList, missionid } 数据集合
    * @property Object range 学生的查询范围
    * @property String direction horizontal横向/vertical纵向
    * @property String questionnaireid 问卷id
    * @property Array modelList 要导出的字段,学生和问卷都在这里, 学生的table:student, 问卷的table:questionnaire
+   * @property String missionid 任务id
    */
-  async export({ range, direction, questionnaireid, modelList }) {
-    // 将期批班转换
-    modelList = modelList.map(i => {
-      const { model } = i;
-      if (model === 'termid') i.model = 'termname';
-      else if (model === 'batchid') i.model = 'batchname';
-      else if (model === 'classid') i.model = 'classname';
-      return i;
-    });
-    // 获取问卷
-    let questionnaire = await this.questionnairemodel.findById(questionnaireid);
-    if (!questionnaire) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到问卷信息'); }
-    questionnaire = JSON.parse(JSON.stringify(questionnaire));
-    // 修改条件,termid变成数组了,需要一个一个查出来
-    const { planid, termid, batchid, classid } = range;
-    const queryObject = {};
-    if (planid) queryObject.planid = planid;
-    if (batchid) queryObject.batchid = batchid;
-    if (classid) queryObject.classid = classid;
-    const studentList = [];
-    const questAnswerList = [];
-    for (const t of termid) {
-      queryObject.termid = t;
-      const obj = await this.toGetData(queryObject, questionnaireid);
-      if (!obj) continue;
-      const { studentList: stuList, questAnswerList: qaList } = obj;
-      if (stuList) studentList.push(...stuList);
-      if (qaList) questAnswerList.push(...qaList);
-    }
-    // fn,根据范围+问卷 得出文件名
-    const fn = await this.toSetFileName(questionnaire.name, range);
+  async export({ range, direction, questionnaireid, modelList, missionid }) {
+    assert(missionid, '缺少任务信息,无法执行任务');
+    try {
+      // 将期批班转换
+      modelList = modelList.map(i => {
+        const { model } = i;
+        if (model === 'termid') i.model = 'termname';
+        else if (model === 'batchid') i.model = 'batchname';
+        else if (model === 'classid') i.model = 'classname';
+        return i;
+      });
+      // 获取问卷
+      let questionnaire = await this.questionnairemodel.findById(questionnaireid);
+      if (!questionnaire) {
+        throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到问卷信息');
+      }
+      this.ctx.service.util.updateProcess(missionid, '25');
+      console.log('问卷导出=>25%');
+      questionnaire = JSON.parse(JSON.stringify(questionnaire));
+      // 修改条件,termid变成数组了,需要一个一个查出来
+      const { planid, termid, batchid, classid } = range;
+      const queryObject = {};
+      if (planid) queryObject.planid = planid;
+      if (batchid) queryObject.batchid = batchid;
+      if (classid) queryObject.classid = classid;
+      const studentList = [];
+      const questAnswerList = [];
+      for (const t of termid) {
+        queryObject.termid = t;
+        const obj = await this.toGetData(queryObject, questionnaireid);
+        if (!obj) continue;
+        const { studentList: stuList, questAnswerList: qaList } = obj;
+        if (stuList) studentList.push(...stuList);
+        if (qaList) questAnswerList.push(...qaList);
+      }
+      this.ctx.service.util.updateProcess(missionid, '50');
+      console.log('问卷导出=>50%');
+      // fn,根据范围+问卷 得出文件名
+      const fn = await this.toSetFileName(questionnaire.name, range);
 
-    let excelData;
-    if (direction === 'horizontal') {
-      excelData = this.horizontalSetData(studentList, questAnswerList, modelList);
-    } else if (direction === 'vertical') {
-      excelData = this.verticaSetData(studentList, questAnswerList, modelList);
-    } else {
-      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到excel的表头排列方式');
-    }
-    if (excelData) {
-      const { head, data } = excelData;
-      return await this.ctx.service.util.toExcel(data, head, fn);
+      let excelData;
+      if (direction === 'horizontal') {
+        excelData = this.horizontalSetData(
+          studentList,
+          questAnswerList,
+          modelList
+        );
+      } else if (direction === 'vertical') {
+        excelData = this.verticaSetData(
+          studentList,
+          questAnswerList,
+          modelList
+        );
+      } else {
+        throw new BusinessError(
+          ErrorCode.DATA_NOT_EXIST,
+          '未找到excel的表头排列方式'
+        );
+      }
+      this.ctx.service.util.updateProcess(missionid, '75');
+      console.log('学生导出=>75%');
+      if (excelData) {
+        const { head, data } = excelData;
+        const res = await this.ctx.service.util.toExcel(data, head, fn);
+        if (!res) {
+          console.error(
+            `${moment().format('YYYY-MM-DD HH:SS:mm')} ${fn} 导出失败`
+          );
+          throw new BusinessError(ErrorCode.SERVICE_FAULT, `${fn}导出失败`);
+        }
+        this.ctx.service.util.updateProcess(missionid, '100', '2', {
+          uri: res,
+        });
+        this.ctx.service.util.updateProcess(missionid, '100');
+        console.log('问卷导出=>100%');
+      }
+    } catch (error) {
+      this.ctx.service.util.updateProcess(missionid, undefined, '3');
     }
   }
 
@@ -134,15 +208,19 @@ class QuestionnaireService extends CrudService {
    */
   async toGetData(condition, questionnaireid) {
     // 获取学生
-    let { data: studentList } = await this.ctx.service.student.query(condition);
-    if (studentList.length <= 0) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何学生信息'); }
+    let studentList = await this.ctx.service.student.query(condition);
+    if (studentList.length <= 0) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何学生信息');
+    }
     studentList = JSON.parse(JSON.stringify(studentList));
     // 再获取问卷答案
     let questAnswerList = await this.ctx.model.Uploadquestion.find({
       ...condition,
       questionnaireid,
     });
-    if (!questAnswerList) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何完成的问卷'); }
+    if (!questAnswerList) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何完成的问卷');
+    }
     questAnswerList = JSON.parse(JSON.stringify(questAnswerList));
     const obj = {};
     if (studentList) obj.studentList = studentList;
@@ -189,7 +267,11 @@ class QuestionnaireService extends CrudService {
           if (obj) {
             const { term } = obj;
             if (term) {
-              if (i === 0) { tStr += `${term}期`; } else { tStr += `,${term}期`; }
+              if (i === 0) {
+                tStr += `${term}期`;
+              } else {
+                tStr += `,${term}期`;
+              }
             }
           }
         }
@@ -211,10 +293,17 @@ class QuestionnaireService extends CrudService {
    * @param {String} batchid 批id
    */
   async toGetFn(termid, batchid) {
-    const trainPlan = await this.ctx.model.Trainplan.findOne({ 'termnum._id': ObjectId(termid) });
-    if (!trainPlan) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到年度计划信息');
+    const trainPlan = await this.ctx.model.Trainplan.findOne({
+      'termnum._id': ObjectId(termid),
+    });
+    if (!trainPlan) { throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到年度计划信息'); }
     const { termnum } = trainPlan;
-    if (!termnum) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到年度计划的期信息');
+    if (!termnum) {
+      throw new BusinessError(
+        ErrorCode.DATA_NOT_EXIST,
+        '未找到年度计划的期信息'
+      );
+    }
     const obj = {};
     if (termid) {
       const term = termnum.id(termid);
@@ -270,10 +359,9 @@ class QuestionnaireService extends CrudService {
         }
       }
       data.push(obj);
-
     }
     const obj = {};
-    if (head)obj.head = head;
+    if (head) obj.head = head;
     if (data) obj.data = data;
     return obj;
   }

+ 31 - 0
app/service/rabbitmq.js

@@ -30,6 +30,37 @@ class RabbitmqService extends Service {
     const result = msg.content.toString();
     const headers = msg.properties.headers;
   }
+
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      const queue = 'mission/center';
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    let data = bdata.content.toString();
+    try {
+      data = JSON.parse(data);
+    } catch (error) {
+      this.ctx.logger.error('数据不是object');
+    }
+    const { service, method, ...others } = data;
+    if (service && method) this.ctx.service[service][method](others);
+
+  }
 }
 
 module.exports = RabbitmqService;

+ 236 - 135
app/service/student.js

@@ -1,6 +1,5 @@
 'use strict';
 
-
 const assert = require('assert');
 const _ = require('lodash');
 const { ObjectId } = require('mongoose').Types;
@@ -22,6 +21,8 @@ class StudentService extends CrudService {
     this.scoremodel = this.ctx.model.Score;
     this.leavemodel = this.ctx.model.Leave;
     this.attendmodel = this.ctx.model.Attendance;
+    const { baseUrl } = _.get(this.ctx.app.config, 'mission');
+    if (baseUrl) this.missionBase = baseUrl;
   }
 
   async create(data) {
@@ -69,54 +70,56 @@ class StudentService extends CrudService {
   }
 
   // 查询
-  async query({ skip, limit, ...info }) {
-    const total = await this.model.count(info);
-    let res = await this.model
-      .find(info)
-      .skip(Number(skip))
-      .limit(Number(limit));
-    res = JSON.parse(JSON.stringify(res));
-    let termList = res.map(i => i.termid);
-    termList = _.compact(_.uniq(termList));
-    termList = termList.map(i => ObjectId(i));
-    const planList = await this.tmodel.find({
-      'termnum._id': { $in: termList },
-    });
-    let classid = res.map(i => i.classid);
-    classid = _.compact(_.uniq(classid));
-    classid = classid.map(i => ObjectId(i));
-    const classList = await this.clamodel.find({ _id: { $in: classid } });
-    // 整理数据
-    res = res.map(i => {
-      const { planid, termid, batchid, classid } = i;
-      // 拿出班级名称
-      const cla = classList.find(f => ObjectId(classid).equals(f._id));
-      if (cla) {
-        const { name: classname } = cla;
-        i.classname = classname;
+  async query({ name, ...info }, { skip = 0, limit = 0 } = {}) {
+    const query = { ...info };
+    if (name) {
+      query.name = { $regex: name };
+    }
+    let data = await this.model
+      .find(query)
+      .populate([
+        {
+          path: 'classid',
+          model: 'Class',
+          select: 'name',
+        },
+        {
+          path: 'planid',
+          model: 'Trainplan',
+        },
+      ])
+      .skip(parseInt(skip))
+      .limit(parseInt(limit));
+    data = JSON.parse(JSON.stringify(data));
+    for (const stu of data) {
+      const { classid, planid, termid, batchid } = stu;
+      // 先拿学生
+      if (classid && _.isObject(classid)) {
+        const { _id, name } = classid;
+        if (name) stu.classname = name;
+        if (_id) stu.classid = _id;
       }
-      const plan = planList.find(f => ObjectId(planid).equals(f._id));
-      if (plan) {
-        const { termnum } = plan;
+      // 拼计划信息
+      if (planid && _.isObject(planid)) {
+        const { termnum, _id } = planid;
         if (termnum && _.isArray(termnum)) {
-          const termInfo = termnum.id(termid);
-          if (termInfo) {
-            const { term, batchnum } = termInfo;
-            if (term) i.termname = term;
+          const t = termnum.find(f => f._id === termid);
+          if (t) {
+            const { batchnum, term } = t;
+            if (term) stu.termname = term;
             if (batchnum && _.isArray(batchnum)) {
-              const batchInfo = batchnum.id(batchid);
-              if (batchInfo) {
-                const { batch } = batchInfo;
-                if (batch) i.batchname = batch;
+              const b = batchnum.find(f => f._id === batchid);
+              if (b) {
+                const { batch } = b;
+                if (batch) stu.batchname = batch;
               }
             }
           }
         }
+        stu.planid = _id;
       }
-      return i;
-    });
-    const result = { total, data: res };
-    return result;
+    }
+    return data;
   }
 
   async count({ name, ...info }) {
@@ -489,119 +492,217 @@ class StudentService extends CrudService {
     }
     number = 1;
   }
-
-  // 导出学生
-  async exportStudent(body) {
-    let { model, ...data } = body;
-    // 整理model
-    model = model.map(i => {
-      const { zh, model } = i;
-      if (zh && model) {
-        const obj = {};
-        obj.header = zh;
-        if (model === 'termid') obj.key = 'termname';
-        else if (model === 'batchid') obj.key = 'batchname';
-        else if (model === 'classid') obj.key = 'classname';
-        else obj.key = model;
-        obj.width = 20;
-        return obj;
+  // 建立导出学生名单的任务
+  async toExport(body) {
+    const { planid, termid, batchid, classid } = body;
+    const trainPlan = await this.ctx.model.Trainplan.findById(planid);
+    let fn = '学生名单';
+    if (termid && termid.length > 0) {
+      if (classid) {
+        const cla = await this.ctx.model.Class.findById(classid);
+        if (cla) {
+          const { name } = cla;
+          if (name) {
+            fn = `${name.includes('班') ? name : `${name}班`}${fn}`;
+          }
+        }
       }
-    });
-    model = _.compact(model);
-    // 请求数据
-    // 修改条件,termid变成数组了,需要一个一个查出来
-    const { planid, termid, batchid, classid } = data;
-    const queryObject = {};
-    if (planid) queryObject.planid = planid;
-    if (batchid) queryObject.batchid = batchid;
-    if (classid) queryObject.classid = classid;
-    let studentList = [];
-    for (const t of termid) {
-      queryObject.termid = t;
-      const { data: stuList } = await this.query(queryObject);
-      studentList.push(...stuList);
+      if (termid.length === 1) {
+        const tid = _.head(termid);
+        const { termnum } = trainPlan;
+        const t = termnum.id(tid);
+        if (t) {
+          const { term, batchnum } = t;
+          if (batchid) {
+            const b = batchnum.id(batchid);
+            if (b) {
+              const { batch } = b;
+              if (b) fn = `第${batch}批${fn}`;
+            }
+          }
+          if (term) fn = `第${term}期${fn}`;
+        }
+      } else if (termid.length > 1) {
+        const { termnum } = trainPlan;
+        let str = '第';
+        for (const tid of termid) {
+          const t = termnum.id(tid);
+          if (t) {
+            const { term } = t;
+            str = `${str}${term} `;
+          }
+        }
+        fn = `${str}期${fn}`;
+      }
+    } else {
+      const { title } = trainPlan;
+      fn = `${title}${fn}`;
     }
-    studentList = JSON.parse(JSON.stringify(studentList));
-    let ids = studentList.map(i => i.classid);
-    ids = _.uniq(ids);
-    ids = _.compact(ids);
-    ids = ids.map(i => ObjectId(i));
-    const classList = await this.ctx.model.Class.find({ _id: { $in: ids } });
-    for (const stu of studentList) {
-      // 转换是否参培
-      const { classid, isComming } = stu;
-      if (!classid) continue;
-      const cla = await this.ctx.service.class.fetch({ id: classid });
-      if (!cla) continue;
-      const { startdate } = cla;
-      if (!startdate) continue;
-      stu.insurance = moment(startdate).add(1, 'd').format('YYYY-MM-DD');
-      if (isComming) {
-        if (isComming === '0') stu.isComming = '否';
-        if (isComming === '1') stu.isComming = '是';
+    const data = {
+      title: fn,
+      params: {
+        project: 'center',
+        // router: '/api/train/mission/student/export',
+        service: 'student',
+        method: 'exportStudent',
+        body,
+      },
+    };
+    if (this.missionBase) {
+      const url = `${this.missionBase}/api/mission`;
+      const res = await this.ctx.curl(url, {
+        method: 'post',
+        headers: {
+          'content-type': 'application/json',
+        },
+        data,
+        dataType: 'json',
+      });
+      if (res.status !== 200 || res.data.errcode !== 0) {
+        throw new BusinessError(ErrorCode.SERVICE_FAULT, '创建任务失败');
       }
+    } else {
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '未找到任务项目设置');
     }
-    let fn = '学生名单';
-    // 因为是递进下来, batchid和classid并列,并非递进
-    if (classid) {
-      // 文件名称: 期, 班
-      // 班级名上面有直接拽来
-      const cla = classList.find(f => ObjectId(classid).equals(f._id));
-      if (cla) {
-        const { name, termid } = cla;
-        if (name) fn = `${name.includes('班') ? name : `${name}班`}${fn}`;
-        if (termid) {
-          const obj = await this.toGetFn(termid);
-          if (obj) {
-            const { term } = obj;
-            fn = `第${term}期${fn}`;
-          }
+  }
+  // 导出学生
+  async exportStudent(body) {
+    let { missionid, model, ...data } = body;
+    assert(missionid, '缺少任务信息,无法执行任务');
+    try {
+      // 整理model
+      model = model.map(i => {
+        const { zh, model } = i;
+        if (zh && model) {
+          const obj = {};
+          obj.header = zh;
+          if (model === 'termid') obj.key = 'termname';
+          else if (model === 'batchid') obj.key = 'batchname';
+          else if (model === 'classid') obj.key = 'classname';
+          else obj.key = model;
+          obj.width = 20;
+          return obj;
         }
+      });
+      model = _.compact(model);
+      // 请求数据
+      // 修改条件,termid变成数组了,需要一个一个查出来
+      const { planid, termid, batchid, classid } = data;
+      const queryObject = {};
+      if (planid) queryObject.planid = planid;
+      if (batchid) queryObject.batchid = batchid;
+      if (classid) queryObject.classid = classid;
+      let studentList = [];
+      for (const t of termid) {
+        queryObject.termid = t;
+        const stuList = await this.query(queryObject);
+        studentList.push(...stuList);
       }
-    } else if (batchid) {
-      // 文件名称,期,批
-      const tid = _.head(termid);
-      const obj = await this.toGetFn(tid, batchid);
-      if (obj) {
-        const { term, batch } = obj;
-        if (batch) fn = `第${batch}批${fn}`;
-        if (term) fn = `第${term}期${fn}`;
+      // 获取学生,4分之1
+      this.ctx.service.util.updateProcess(missionid, '25');
+      console.log('学生导出=>25%');
+      studentList = JSON.parse(JSON.stringify(studentList));
+      let ids = studentList.map(i => i.classid);
+      ids = _.uniq(ids);
+      ids = _.compact(ids);
+      ids = ids.map(i => ObjectId(i));
+      const classList = await this.ctx.model.Class.find({
+        _id: { $in: ids },
+      });
+      for (const stu of studentList) {
+        // 转换是否参培
+        const { classid, isComming } = stu;
+        if (!classid) continue;
+        const cla = await this.ctx.service.class.fetch({ id: classid });
+        if (!cla) continue;
+        const { startdate } = cla;
+        if (!startdate) continue;
+        stu.insurance = moment(startdate).add(1, 'd').format('YYYY-MM-DD');
+        if (isComming) {
+          if (isComming === '0') stu.isComming = '否';
+          if (isComming === '1') stu.isComming = '是';
+        }
       }
-    } else if (termid) {
-      // 文件名称: 期
-      if (termid.length === 1) {
-        const obj = await this.toGetFn(_.head(termid));
+      // 整理完数据,4分之2
+      this.ctx.service.util.updateProcess(missionid, '50');
+      console.log('学生导出=>50%');
+      let fn = '学生名单';
+      // 因为是递进下来, batchid和classid并列,并非递进
+      if (classid) {
+        // 文件名称: 期, 班
+        // 班级名上面有直接拽来
+        const cla = classList.find(f => ObjectId(classid).equals(f._id));
+        if (cla) {
+          const { name, termid } = cla;
+          if (name) fn = `${name.includes('班') ? name : `${name}班`}${fn}`;
+          if (termid) {
+            const obj = await this.toGetFn(termid);
+            if (obj) {
+              const { term } = obj;
+              fn = `第${term}期${fn}`;
+            }
+          }
+        }
+      } else if (batchid) {
+        // 文件名称,期,批
+        const tid = _.head(termid);
+        const obj = await this.toGetFn(tid, batchid);
         if (obj) {
-          const { term } = obj;
+          const { term, batch } = obj;
+          if (batch) fn = `第${batch}批${fn}`;
           if (term) fn = `第${term}期${fn}`;
         }
-      } else {
-        let tStr = '';
-        for (let i = 0; i < termid.length; i++) {
-          const tid = termid[i];
-          const obj = await this.toGetFn(tid);
+      } else if (termid) {
+        // 文件名称: 期
+        if (termid.length === 1) {
+          const obj = await this.toGetFn(_.head(termid));
           if (obj) {
             const { term } = obj;
-            if (term) {
-              if (i === 0) {
-                tStr += `${term}期`;
-              } else {
-                tStr += `,${term}期`;
+            if (term) fn = `第${term}期${fn}`;
+          }
+        } else {
+          let tStr = '';
+          for (let i = 0; i < termid.length; i++) {
+            const tid = termid[i];
+            const obj = await this.toGetFn(tid);
+            if (obj) {
+              const { term } = obj;
+              if (term) {
+                if (i === 0) {
+                  tStr += `${term}期`;
+                } else {
+                  tStr += `,${term}期`;
+                }
               }
             }
           }
+          fn = `${tStr}${fn}`;
+        }
+      } else if (planid) {
+        // 文件名称:该计划标题
+        const trainPlan = await this.ctx.model.Trainplan.findById(planid);
+        if (trainPlan) {
+          const { title } = trainPlan;
+          if (title) fn = `${title}${fn}`;
         }
-        fn = `${tStr}${fn}`;
       }
-    } else if (planid) {
-      // 文件名称:该计划标题
-      const trainPlan = await this.ctx.model.Trainplan.findById(planid);
-      if (trainPlan) {
-        const { title } = trainPlan;
-        if (title) fn = `${title}${fn}`;
+      // 获取文件名,60%
+      this.ctx.service.util.updateProcess(missionid, '60');
+      console.log('学生导出=>60%');
+      const res = await this.ctx.service.util.toExcel(studentList, model, fn);
+      if (!res) {
+        console.error(
+          `${moment().format('YYYY-MM-DD HH:SS:mm')} ${fn} 导出失败`
+        );
+        throw new BusinessError(ErrorCode.SERVICE_FAULT, `${fn}导出失败`);
       }
+      this.ctx.service.util.updateProcess(missionid, '100', '2', {
+        uri: res,
+      });
+      console.log('学生导出=>100%');
+    } catch (error) {
+      this.ctx.service.util.updateProcess(missionid, undefined, '3');
     }
-    return await this.ctx.service.util.toExcel(studentList, model, fn);
   }
 
   async toGetFn(termid, batchid) {

+ 1 - 1
app/service/talented.js

@@ -13,7 +13,7 @@ class TalentedService extends CrudService {
     this.model = this.ctx.model.Talented;
   }
 
-  async query(data, { skip, limit }) {
+  async query(data, { skip = 0, limit = 0 } = {}) {
     let res = await this.model.find(data).populate({ path: 'studentid', select: 'name job' }).skip(parseInt(skip))
       .limit(parseInt(limit));
     if (res.length > 0) {

+ 101 - 50
app/service/task.js

@@ -11,63 +11,114 @@ class TaskService extends CrudService {
   constructor(ctx) {
     super(ctx, 'task');
     this.model = this.ctx.model.Task;
+    const { baseUrl } = _.get(this.ctx.app.config, 'mission');
+    if (baseUrl) this.missionBase = baseUrl;
   }
-
-  async export({ range, subid }) {
-    console.log(range, subid);
-    // 找到学生
-    // 修改条件,termid变成数组了,需要一个一个查出来
-    const { planid, termid, batchid, classid } = range;
-    const queryObject = {};
-    if (planid) queryObject.planid = planid;
-    if (batchid) queryObject.batchid = batchid;
-    if (classid) queryObject.classid = classid;
-    let studentList = [];
-    for (const t of termid) {
-      queryObject.termid = t;
-      const { data: stuList } = await this.ctx.service.student.query(queryObject);
-      studentList.push(...stuList);
-    }
-    if (studentList.length <= 0) {
-      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何学生信息');
+  // 建立任务
+  async toExport(body) {
+    const { range } = body;
+    const { fn } = await this.getFnDir(range);
+    const data = {
+      title: fn,
+      params: {
+        project: 'center',
+        service: 'task',
+        method: 'export',
+        body,
+      },
+    };
+    if (this.missionBase) {
+      const url = `${this.missionBase}/api/mission`;
+      const res = await this.ctx.curl(url, {
+        method: 'post',
+        headers: {
+          'content-type': 'application/json',
+        },
+        data,
+        dataType: 'json',
+      });
+      if (res.status !== 200 || res.data.errcode !== 0) {
+        throw new BusinessError(ErrorCode.SERVICE_FAULT, '创建任务失败');
+      }
+    } else {
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '未找到任务项目设置');
     }
-    studentList = JSON.parse(JSON.stringify(studentList));
-    // 找到作业
-    const taskList = await this.getTaskInfo(range, subid);
-    // prefix 最少 科目名称/人 可能出现 选择到期:期/班/科目/人; 选择到批:期/批/班/科目/人; 选择到班:科目/人 ;选择计划:期/批/班/科目/人
-    // 找到应该是哪种模式的文件夹,同时可以获得压缩包的名称
-    const { fn, prefix: pn } = await this.getFnDir(range);
-    // 循环作业,之后匹配所需要的信息
-    const arr = [];
-    for (const task of taskList) {
-      const { lessonname, studentid, picurl } = task;
-      const stu = studentList.find(f => f._id === studentid);
-      if (!stu) continue;
-      const { name: studentname, termname, batchname, classname } = stu;
-      let picarr = [];
-      if (_.isString(picurl)) {
-        picarr = [ picurl ];
-      } else {
-        picarr = picurl;
+  }
+
+  async export({ range, subid, missionid }) {
+    assert(missionid, '缺少任务信息,无法执行任务');
+    try {
+      // 找到学生
+      // 修改条件,termid变成数组了,需要一个一个查出来
+      const { planid, termid, batchid, classid } = range;
+      const queryObject = {};
+      if (planid) queryObject.planid = planid;
+      if (batchid) queryObject.batchid = batchid;
+      if (classid) queryObject.classid = classid;
+      let studentList = [];
+      for (const t of termid) {
+        queryObject.termid = t;
+        const stuList = await this.ctx.service.student.query(queryObject);
+        studentList.push(...stuList);
       }
-      for (const uri of picarr) {
-        const obj = { uri };
-        const keys = Object.keys(pn);
-        let prefix = `${lessonname}/${studentname}/`;
-        if (keys.includes('class')) {
-          prefix = `${classname}/${prefix}`;
-        }
-        if (keys.includes('batchid')) {
-          prefix = `${batchname}/${prefix}`;
+      if (studentList.length <= 0) {
+        throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何学生信息');
+      }
+      studentList = JSON.parse(JSON.stringify(studentList));
+      this.ctx.service.util.updateProcess(missionid, '25');
+      console.log('作业导出=>25%');
+      // 找到作业
+      const taskList = await this.getTaskInfo(range, subid);
+      this.ctx.service.util.updateProcess(missionid, '50');
+      console.log('作业导出=>50%');
+      // prefix 最少 科目名称/人 可能出现 选择到期:期/班/科目/人; 选择到批:期/批/班/科目/人; 选择到班:科目/人 ;选择计划:期/批/班/科目/人
+      // 找到应该是哪种模式的文件夹,同时可以获得压缩包的名称
+      const { fn, prefix: pn } = await this.getFnDir(range);
+      // 循环作业,之后匹配所需要的信息
+      const arr = [];
+      for (const task of taskList) {
+        const { lessonname, studentid, picurl } = task;
+        const stu = studentList.find(f => f._id === studentid);
+        if (!stu) continue;
+        const { name: studentname, termname, batchname, classname } = stu;
+        let picarr = [];
+        if (_.isString(picurl)) {
+          picarr = [ picurl ];
+        } else {
+          picarr = picurl;
         }
-        if (keys.includes('term')) {
-          prefix = `${termname}/${prefix}`;
+        for (const uri of picarr) {
+          const obj = { uri };
+          const keys = Object.keys(pn);
+          let prefix = `${lessonname}/${studentname}/`;
+          if (keys.includes('class')) {
+            prefix = `${classname}/${prefix}`;
+          }
+          if (keys.includes('batchid')) {
+            prefix = `${batchname}/${prefix}`;
+          }
+          if (keys.includes('term')) {
+            prefix = `${termname}/${prefix}`;
+          }
+          obj.prefix = prefix;
+          arr.push(obj);
         }
-        obj.prefix = prefix;
-        arr.push(obj);
       }
+      this.ctx.service.util.updateProcess(missionid, '75');
+      console.log('作业导出=>75%');
+      const res = await this.ctx.service.util.toZip(arr, fn);
+      if (!res) {
+        console.error(`${moment().format('YYYY-MM-DD HH:SS:mm')} ${fn} 导出失败`);
+        throw new BusinessError(ErrorCode.SERVICE_FAULT, `${fn}导出失败`);
+      }
+      this.ctx.service.util.updateProcess(missionid, '100', '2', {
+        uri: res,
+      });
+      console.log('作业导出=>100%');
+    } catch (error) {
+      this.ctx.service.util.updateProcess(missionid, undefined, '3');
+
     }
-    return await this.ctx.service.util.toZip(arr, fn);
   }
 
   async getTaskInfo(range, subid) {

+ 1 - 1
app/service/teacher.js

@@ -16,7 +16,7 @@ class TeacherService extends CrudService {
     this.umodel = this.ctx.model.User;
   }
 
-  async query({ name, ...info }, { skip, limit }) {
+  async query({ name, ...info }, { skip = 0, limit = 0 } = {}) {
     const query = { ...info };
     if (name) {
       query.name = { $regex: name };

+ 60 - 42
app/service/util.js

@@ -14,6 +14,10 @@ const { template } = require('lodash');
 const docx = require('docx');
 const archiver = require('archiver');
 class UtilService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.mq = this.ctx.mq;
+  }
   async updatedate() {
     let date = new Date();
     date = moment(date).format('YYYY-MM-DD HH:mm:ss');
@@ -75,43 +79,55 @@ class UtilService extends CrudService {
     const data = this.ctx.model[_model].prototype.schema.obj;
     return data;
   }
-  async utilMethod(data, body) {
-    // 将指定计划,期数的教师状态解除确认
-    let trainPlan = await this.ctx.model.Trainplan.findById('5f5adb337ceb003386c9b0d4');
-    trainPlan = JSON.parse(JSON.stringify(trainPlan));
-    let terms = {};
-    for (const term of trainPlan.termnum) {
-      if (ObjectId('5f5aed5e69b4221aedaa5005').equals(term._id)) {
-        for (const batch of term.batchnum) {
-          for (const c of batch.class) {
-            for (const l of c.lessons) {
-              l.status = '0';
-            }
-          }
-        }
-        terms = term;
-      }
-    }
-    const i = trainPlan.termnum.findIndex(f => ObjectId('5f5aed5e69b4221aedaa5005').equals(f._id));
-    trainPlan.termnum[i] = terms;
-    delete trainPlan.meta;
-    const r = await this.ctx.model.Trainplan.update(
-      { _id: ObjectId('5f5adb337ceb003386c9b0d4') },
-      { ...trainPlan }
-    );
-    console.log(r);
+  async utilMethod(query, body) {
+    // const ch = await this.ctx.amqp.conn.createChannel();
+    // const queue = 'hello';
+    // ch.consume(
+    //   queue,
+    //   msg => {
+    //     console.log(' [x] Received %s', msg.content.toString());
+    //   },
+    //   { noAck: true }
+    // );
 
+    // // ch.close();
+  }
 
-    // const output = fs.createWriteStream('E:\\exportFile\\test.zip');
-    // const archive = archiver('zip', {
-    //   zlib: { level: 9 },
-    // });
-    // archive.pipe(output);
-    // const res = await this.ctx.curl('http://jytz.jilinjobs.cn/files/task/20200914174650.jpg');
-    // if (res && res.data) {
-    //   archive.append(res.data, { name: 'test.jpg', prefix: 'test/test2/test3' });
-    // }
-    // archive.finalize();
+  /**
+   * 更新进度,状态 不存在/完成以外(不是2的值)的数值, 不添加参数,只更新进度
+   * @param {String} missionid 任务id
+   * @param {String} progress 进度(人为划分)
+   * @param {String} status 状态
+   * @param {Object} params 参数
+   */
+  async updateProcess(missionid, progress, status, params) {
+    try {
+      if (!missionid) return;
+      const { baseUrl } = _.get(this.ctx.app.config, 'mission');
+      let url = `${baseUrl}`;
+      let data;
+      if (!baseUrl) return;
+      if (!status || status !== '2') {
+        url = `${url}/api/mission/progress`;
+        data = { id: missionid, progress };
+      } else if (status === '3') {
+        url = `${url}/api/mission/update/${missionid}`;
+        data = { status };
+      } else {
+        url = `${url}/api/mission/update/${missionid}`;
+        data = { progress: '100', params, status };
+      }
+      await this.ctx.curl(url, {
+        method: 'post',
+        headers: {
+          'content-type': 'application/json',
+        },
+        data,
+        dataType: 'json',
+      });
+    } catch (error) {
+      console.error(`任务更新进度报错,missionid:${missionid}\n`);
+    }
   }
 
   async teacherImport() {
@@ -152,16 +168,13 @@ class UtilService extends CrudService {
     //   }
     // }
     // const user = await this.ctx.model.User.find({ passwd: { $exists: false } });
-    // console.log(user.length);
     // for (const u of user) {
     //   u.passwd = { secret: '12345678' };
     //   u.save();
     // }
   }
 
-
   async toExcel(dataList, meta, fn = '导出结果') {
-    console.log(meta);
     // 导出excel
     const { app } = this;
     const nowDate = new Date().getTime();
@@ -273,7 +286,10 @@ class UtilService extends CrudService {
    */
   async toZip(fileList, fn = '导出结果') {
     if (!_.isArray(fileList)) {
-      throw new BusinessError(ErrorCode.DATA_INVALID, '需要压缩的文件数据格式错误');
+      throw new BusinessError(
+        ErrorCode.DATA_INVALID,
+        '需要压缩的文件数据格式错误'
+      );
     }
     fn = `${fn}.zip`;
     // zip文件夹创建
@@ -310,7 +326,7 @@ class UtilService extends CrudService {
       }
       const obj = {};
       if (uri) obj.uri = uri;
-      if (filename)obj.filename = filename;
+      if (filename) obj.filename = filename;
       if (prefixs) obj.prefix = prefixs;
       resetFileList.push(obj);
     }
@@ -326,9 +342,11 @@ class UtilService extends CrudService {
       const res = await this.ctx.curl(`http://127.0.0.1${uri}`);
       if (res && res.data) {
         const options = {};
-        if (filename)options.name = filename;
+        if (filename) options.name = filename;
         if (prefix) options.prefix = prefix;
-        if (filename) { archive.append(res.data, options); }
+        if (filename) {
+          archive.append(res.data, options);
+        }
       }
     }
     await archive.finalize();