瀏覽代碼

新人才报

lrf402788946 4 年之前
父節點
當前提交
af1b00da3b
共有 8 個文件被更改,包括 423 次插入2 次删除
  1. 63 0
      app/controller/.talented.js
  2. 16 0
      app/controller/talented.js
  3. 22 0
      app/model/talented.js
  4. 5 0
      app/router.js
  5. 202 0
      app/service/talented.js
  6. 113 2
      app/service/util.js
  7. 1 0
      config/config.prod.js
  8. 1 0
      package.json

+ 63 - 0
app/controller/.talented.js

@@ -0,0 +1,63 @@
+module.exports = {
+  create: {
+    requestBody: [
+      "planid",
+      "termid",
+      "batchid",
+      "classid",
+      "studentid",
+      "files",
+    ],
+  },
+  destroy: {
+    params: ["!id"],
+    service: "delete",
+  },
+  update: {
+    params: ["!id"],
+    requestBody: [
+      "planid",
+      "termid",
+      "batchid",
+      "classid",
+      "studentid",
+      "files",
+    ],
+  },
+  show: {
+    parameters: {
+      params: ["!id"],
+    },
+    service: "fetch",
+  },
+  index: {
+    parameters: {
+      query: {
+        planid:"planid",
+        termid: "termid",
+        batchid: "batchid",
+        classid: "classid",
+      },
+    },
+    service: "query",
+    options: {
+      query: ["skip", "limit"],
+      sort: ["meta.createdAt"],
+      desc: true,
+      count: true,
+    },
+  },
+  export: {
+    parameters: {
+      query: {
+        planid: "planid",
+        termid: "termid",
+        batchid: "batchid",
+        classid: "classid",
+        studentid: "studentid",
+        id: "id",
+      },
+    },
+    service: "export",
+  },
+};

+ 16 - 0
app/controller/talented.js

@@ -0,0 +1,16 @@
+'use strict';
+
+const _ = require('lodash');
+const meta = require('./.talented.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+// 职责说明管理
+class TalentedController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.talented;
+  }
+}
+
+module.exports = CrudController(TalentedController, meta);

+ 22 - 0
app/model/talented.js

@@ -0,0 +1,22 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+
+// 科目表
+const TalentedSchema = {
+  planid: { type: String, required: false }, // 计划id
+  termid: { type: String, required: false }, // 期id
+  batchid: { type: String, required: false }, // 批次id
+  classid: { type: String, ref: 'Class' }, // 班级id
+  studentid: { type: String, ref: 'Student' }, // 学生id
+  files: { type: Array }, // 文件列表
+};
+
+const schema = new Schema(TalentedSchema, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.plugin(metaPlugin);
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('Talented', schema, 'talented');
+};

+ 5 - 0
app/router.js

@@ -663,4 +663,9 @@ module.exports = app => {
   router.get('/api/train/cerconfirm', controller.cerconfirm.index);
   // 工具方法
   router.post('/api/train/util', controller.util.utilMethod);
+
+  // 新人才报
+  router.get('talented', '/api/train/talented/export', controller.talented.export);
+  router.resources('talented', '/api/train/talented', controller.talented); // index、create、show、destroy
+  router.post('talented', '/api/train/talented/update/:id', controller.talented.update);
 };

+ 202 - 0
app/service/talented.js

@@ -0,0 +1,202 @@
+'use strict';
+
+
+const assert = require('assert');
+const _ = require('lodash');
+const { ObjectId } = require('mongoose').Types;
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+
+class TalentedService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'Talented');
+    this.model = this.ctx.model.Talented;
+  }
+
+  async query(data, { skip, limit }) {
+    let res = await this.model.find(data).populate({ path: 'studentid', select: 'name job' }).skip(parseInt(skip))
+      .limit(parseInt(limit));
+    if (res.length > 0) {
+      res = JSON.parse(JSON.stringify(res));
+      res = res.map(i => {
+        const { studentid } = i;
+        if (studentid && _.isObject(studentid)) {
+          const { name, job } = studentid;
+          i.stuname = name;
+          i.stujob = job;
+        }
+        return i;
+      });
+    }
+    return res;
+  }
+
+  async create(data) {
+    const { studentid } = data;
+    let res;
+    const r = await this.model.findOne({ studentid });
+    if (r) {
+      const { files } = data;
+      r.files = files;
+      res = await r.save();
+    } else {
+      res = await this.model.create(data);
+    }
+    return res;
+  }
+
+  async export(data) {
+    const { planid, termid, batchid, classid, studentid, id } = data;
+    // 从小到大判断
+    // res是最后的结果,可能是Object也可能是Array
+    // 作者拼接:能直接获取学生姓名,班级名称,需要单独查下期数
+    let res;
+    let fn = '';
+    const trainPlanInfo = async (termid, batchid) => {
+      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, '未找到年度计划的期信息');
+      const obj = {};
+      if (termid) {
+        const term = termnum.id(termid);
+        if (term) obj.term = term.term;
+        if (batchid) {
+          const { batchnum } = term;
+          const batch = batchnum.id(batchid);
+          if (batch) obj.batch = batch.batch;
+        }
+      }
+      return obj;
+    };
+    if (id) {
+      let r = await this.model.findById(id).populate({ path: 'studentid', select: 'name job' }).populate({ path: 'classid', select: 'name' });
+      if (!r) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定范围的新人才报');
+      r = JSON.parse(JSON.stringify(r));
+      const { term } = await trainPlanInfo(r.termid);
+      if (term) { r.term = `第${term}期`; }
+      res = r;
+    } else if (studentid) {
+      let r = await this.model.findOne({ studentid }).populate({ path: 'studentid', select: 'name job' }).populate({ path: 'classid', select: 'name' });
+      if (!r) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定范围的新人才报');
+      const { term } = await trainPlanInfo(r.termid);
+      r = JSON.parse(JSON.stringify(r));
+      if (term) { r.term = `第${term}期`; }
+      res = r;
+    } else if (classid) {
+      let r = await this.model.find({ classid }).populate({ path: 'studentid', select: 'name' }).populate({ path: 'classid', select: 'name' });
+      if (r.length <= 0) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定范围的新人才报');
+      r = JSON.parse(JSON.stringify(r));
+      const h = _.head(r);
+      const { term } = await trainPlanInfo(h.termid);
+      r = r.map(i => {
+        i.term = `第${term}期`;
+        return i;
+      });
+      res = r;
+      fn = `第${term}期${h.classid.name}班新人才报`;
+    } else if (batchid) {
+      let r = await this.model.find({ batchid }).populate({ path: 'studentid', select: 'name job' }).populate({ path: 'classid', select: 'name' });
+      if (r.length <= 0) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定范围的新人才报');
+      r = JSON.parse(JSON.stringify(r));
+      const h = _.head(r);
+      const { term, batch } = await trainPlanInfo(h.termid, h.batchid);
+      r = r.map(i => {
+        i.term = `第${term}期`;
+        i.batch = `第${batch}批`;
+        return i;
+      });
+      res = r;
+      fn = `第${term}期第${batch}批新人才报`;
+    } else if (termid) {
+      let r = await this.model.find({ termid }).populate({ path: 'studentid', select: 'name job' }).populate({ path: 'classid', select: 'name' });
+      if (r.length <= 0) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定范围的新人才报');
+      r = JSON.parse(JSON.stringify(r));
+      const h = _.head(r);
+      const { term } = await trainPlanInfo(h.termid, h.batchid);
+      r = r.map(i => {
+        i.term = `第${term}期`;
+        return i;
+      });
+      res = r;
+      fn = `第${term}期新人才报`;
+    } else if (planid) {
+      const trainPlan = await this.ctx.model.Trainplan.findById(planid);
+      if (!trainPlan) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定年度计划信息');
+      const { termnum } = trainPlan;
+      if (!termnum) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定年度计划下的各期信息');
+      if (!_.isArray(termnum)) throw new BusinessError(ErrorCode.DATA_INVALID, '年度计划下的期信息数据格式错误');
+      const arr = [];
+      for (const t of termnum) {
+        const dup = JSON.parse(JSON.stringify(t));
+        let r = await this.model.find({ termid: dup._id }).populate({ path: 'studentid', select: 'name job' }).populate({ path: 'classid', select: 'name' });
+        if (r.length <= 0) continue;
+        r = JSON.parse(JSON.stringify(r));
+        const h = _.head(r);
+        const { term } = await trainPlanInfo(h.termid);
+        r = r.map(i => {
+          i.term = `第${term}期`;
+          return i;
+        });
+        arr.push(...r);
+      }
+      res = arr;
+      fn = `${trainPlan.title}新人才报`;
+    }
+    let arr = [];
+    if (res && !_.isArray(res)) {
+      console.log(res);
+      const { classid, studentid, term, files } = res;
+      if (term) fn = `${fn}${term}`;
+      if (classid) {
+        const { name } = classid;
+        if (name) fn = `${fn}${name.includes('班') ? name : `${name}班`}`;
+      }
+      if (studentid) {
+        const { name } = studentid;
+        if (name) fn = `${fn}${name}`;
+      }
+      fn = `${fn}新人才报`;
+      arr = files;
+    } else if (res && _.isArray(res)) {
+      for (const o of res) {
+        const { files } = o;
+        arr.push(...files);
+      }
+    }
+    if (res.length <= 0) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到任何新人才报');
+    return await this.ctx.service.util.toZip(arr, fn);
+  }
+
+  TalentedData(data) {
+    const { title, content, classid, studentid, term } = data;
+    let docxObj = { title };
+    const cArr = content.split('\n');
+    const ncArr = [];
+    // cArr内容按回车分行,检查每行内容开始是不是有4个空格(首行缩进),没有就加上
+    for (let c of cArr) {
+      if (_.isString(c) && !c.startsWith('    ')) {
+        c = `    ${_.trim(c)}`;
+      }
+      ncArr.push(c);
+    }
+    docxObj = Object.assign(docxObj, { content: ncArr });
+    let author = term;
+    if (_.isObject(classid)) {
+      const { name } = classid;
+      if (name) author = `${author}${name.includes('班') ? name : `${name}班`}`;
+    }
+    if (_.isObject(studentid)) {
+      const { name } = studentid;
+      if (name) author = `${author}${name.includes('班') ? name : `${name}`}`;
+    }
+    if (author !== '') {
+      docxObj = Object.assign(docxObj, { author });
+    }
+
+    return docxObj;
+  }
+
+}
+
+module.exports = TalentedService;

+ 113 - 2
app/service/util.js

@@ -12,7 +12,7 @@ const moment = require('moment');
 const nodemailer = require('nodemailer');
 const { template } = require('lodash');
 const docx = require('docx');
-
+const archiver = require('archiver');
 class UtilService extends CrudService {
   async updatedate() {
     let date = new Date();
@@ -76,7 +76,60 @@ class UtilService extends CrudService {
     return data;
   }
   async utilMethod(data, body) {
-    console.log(data, body);
+    const output = fs.createWriteStream(__dirname + '/example.zip');
+    const archive = archiver('zip', {
+      zlib: { level: 9 },
+    });
+    archive.pipe(output);
+    const res = await this.ctx.curl('http://jytz.jilinjobs.cn/files/talented/337期/2班/朱凯英1602645545740.png');
+    archive.append(res.data, { name: '朱凯英1602645545740.png' });
+    archive.append(res.data, { name: '朱凯英1602645545740(1).png' });
+    archive.finalize();
+  }
+
+  async teacherImport() {
+    // const filepath = './teacherlist.xlsx';
+    // const workbook = new Excel.Workbook();
+    // await workbook.xlsx.readFile(filepath);
+    // const worksheet = workbook.getWorksheet(1);
+    // if (!worksheet) return;
+    // let arr = [];
+    // worksheet.eachRow((row, ri) => {
+    //   if (ri !== 1) {
+    //     const obj = {};
+    //     obj.name = row.getCell(3).value || undefined;
+    //     obj.department = row.getCell(4).value || undefined;
+    //     if (row.getCell(5).value) obj.job = row.getCell(5).value;
+    //     obj.phone = row.getCell(6).value || undefined;
+    //     obj.status = '4';
+    //     arr.push(obj);
+    //   }
+    // });
+    // // 检查谁生成过了, user表和teacher表
+    // let ur = await this.ctx.model.User.find({ mobile: { $in: arr.map(i => i.phone) }, type: '3' });
+    // let tr = await this.ctx.model.Teacher.find({ phone: { $in: arr.map(i => i.phone) } });
+    // // 将有的老师过滤出去
+    // if (ur) {
+    //   ur = JSON.parse(JSON.stringify(ur));
+    //   arr = arr.filter(f => !ur.find(uf => `${uf.mobile}` === `${f.phone}`));
+    // }
+    // if (tr) {
+    //   tr = JSON.parse(JSON.stringify(tr));
+    //   arr = arr.filter(f => !(tr.find(tf => `${tf.phone}` === `${f.phone}`)));
+    // }
+    // for (const tea of arr) {
+    //   const ctr = await this.ctx.model.Teacher.create(tea);
+    //   if (ctr) {
+    //     const obj = { name: tea.name, mobile: tea.phone, type: '3', uid: ctr._id };
+    //     const cur = await this.ctx.model.User.create(obj);
+    //   }
+    // }
+    // 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 = '导出结果') {
@@ -181,6 +234,64 @@ class UtilService extends CrudService {
     // });
     return `/files${rooturl}${fn}-${num}.docx`;
   }
+
+  /**
+   * 将选择的文件导出到zip压缩包中,提供下载
+   * @param {*} fileList 需要导入到zip中的列表,格式有2中: [{url:""}]或[String]
+   * @param {*} fn 文件名,默认为 "导出结果"
+   */
+  async toZip(fileList, fn = '导出结果') {
+    if (!_.isArray(fileList)) {
+      throw new BusinessError(ErrorCode.DATA_INVALID, '需要压缩的文件数据格式错误');
+    }
+    fn = `${fn}.zip`;
+    // zip文件夹创建
+    const { app } = this;
+    const rootPath = `${app.config.cdn.repos_root_path}`;
+    const zipPath = `${app.config.cdn.repos_root_url_zip}`;
+    const path = `${rootPath}${zipPath}`;
+    if (!fs.existsSync(path)) {
+      fs.mkdirSync(path);
+    }
+    // 文件请求后将数据整理到这里
+    const resetFileList = [];
+    for (const file of fileList) {
+      let uri = '';
+      let filename = '';
+      if (_.isString(file)) {
+        uri = file;
+        const arr = file.split('/');
+        const last = _.last(arr);
+        if (last) filename = last;
+      } else if (_.isObject(file)) {
+        const { uri: furi, url: furl, name } = file;
+        if (furi) uri = furi;
+        else if (furl) uri = furl;
+        if (name) filename = name;
+        else {
+          const arr = uri.split('/');
+          const last = _.last(arr);
+          if (last) filename = last;
+        }
+      }
+      if (uri && filename) resetFileList.push({ uri, filename });
+    }
+    // 导出
+    const output = fs.createWriteStream(`${path}${fn}`);
+    const archive = archiver('zip', {
+      zlib: { level: 9 },
+    });
+    // 请求文件,追加进压缩包
+    for (const file of resetFileList) {
+      const { uri, filename } = file;
+      const res = await this.ctx.curl(`http://127.0.0.1${uri}`);
+      if (res && res.data) {
+        archive.append(res.data, filename);
+      }
+    }
+    archive.pipe(output);
+    archive.finalize();
+  }
 }
 
 module.exports = UtilService;

+ 1 - 0
config/config.prod.js

@@ -12,6 +12,7 @@ module.exports = () => {
     repos_root_path: '/usr/local/workspace/service-file/upload',
     repos_root_url_excel: '/excel/',
     repos_root_url_experience: '/experience/',
+    repos_root_url_zip: '/zip/',
   };
 
   config.wxapi = {

+ 1 - 0
package.json

@@ -7,6 +7,7 @@
     "framework": "naf-framework-mongoose"
   },
   "dependencies": {
+    "archiver": "^5.0.2",
     "docx": "^5.3.0",
     "egg": "^2.23.0",
     "egg-naf-amqp": "0.0.13",