瀏覽代碼

学校计划人数设置可以导入excel

zs 9 月之前
父節點
當前提交
7e1d1f894c
共有 3 個文件被更改,包括 132 次插入6 次删除
  1. 12 1
      app/controller/util.js
  2. 3 0
      app/router.js
  3. 117 5
      app/service/util.js

+ 12 - 1
app/controller/util.js

@@ -1,7 +1,6 @@
 'use strict';
 'use strict';
 const Controller = require('egg').Controller;
 const Controller = require('egg').Controller;
 class UtilController extends Controller {
 class UtilController extends Controller {
-
   constructor(ctx) {
   constructor(ctx) {
     super(ctx);
     super(ctx);
     this.service = this.ctx.service.util;
     this.service = this.ctx.service.util;
@@ -11,5 +10,17 @@ class UtilController extends Controller {
     const res = await this.service.utilMethod(this.ctx.query, this.ctx.request.body);
     const res = await this.service.utilMethod(this.ctx.query, this.ctx.request.body);
     this.ctx.ok({ data: res });
     this.ctx.ok({ data: res });
   }
   }
+
+  // 导出学校计划人数
+  async schoolDownload() {
+    const data = await this.service.schoolDownload();
+    this.ctx.ok({ data });
+  }
+
+  // 导入学校计划人数
+  async schoolImport() {
+    const res = await this.service.schoolImport(this.ctx.request.body);
+    this.ctx.ok({ msg: 'created', data: res });
+  }
 }
 }
 module.exports = UtilController;
 module.exports = UtilController;

+ 3 - 0
app/router.js

@@ -361,4 +361,7 @@ module.exports = app => {
   // 教师积分归档
   // 教师积分归档
   router.get('document', '/api/train/document/queryTeacher', controller.document.queryTeacher);
   router.get('document', '/api/train/document/queryTeacher', controller.document.queryTeacher);
   router.resources('document', '/api/train/document', controller.document); // index、create、show、destroy
   router.resources('document', '/api/train/document', controller.document); // index、create、show、destroy
+  // 学校计划人数导入导出
+  router.post('/api/train/schoolDownload', controller.util.schoolDownload); // 导出
+  router.post('/api/train/schoolImport', controller.util.schoolImport); // 导入
 };
 };

+ 117 - 5
app/service/util.js

@@ -1,8 +1,10 @@
 'use strict';
 'use strict';
-
+const assert = require('assert');
 const _ = require('lodash');
 const _ = require('lodash');
 const fs = require('fs');
 const fs = require('fs');
 const Excel = require('exceljs');
 const Excel = require('exceljs');
+const Path = require('path');
+const XLSX = require('xlsx');
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
 const { BusinessError, ErrorCode } = require('naf-core').Error;
 const moment = require('moment');
 const moment = require('moment');
@@ -15,6 +17,7 @@ class UtilService extends CrudService {
   constructor(ctx) {
   constructor(ctx) {
     super(ctx);
     super(ctx);
     this.mq = this.ctx.mq;
     this.mq = this.ctx.mq;
+    this.sModel = this.ctx.model.School;
   }
   }
   async updatedate() {
   async updatedate() {
     let date = new Date();
     let date = new Date();
@@ -198,7 +201,7 @@ XQIDAQAB
     if (sort && _.isString(sort)) {
     if (sort && _.isString(sort)) {
       sort = { [sort]: desc ? -1 : 1 };
       sort = { [sort]: desc ? -1 : 1 };
     } else if (sort && _.isArray(sort)) {
     } else if (sort && _.isArray(sort)) {
-      sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
+      sort = sort.map((f) => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
     }
     return { skip, limit, sort };
     return { skip, limit, sort };
   }
   }
@@ -402,7 +405,7 @@ XQIDAQAB
       const c = [];
       const c = [];
       if (title) {
       if (title) {
         const tit = new Paragraph({
         const tit = new Paragraph({
-          children: [ new TextRun({ text: title, bold: true }) ],
+          children: [new TextRun({ text: title, bold: true })],
           heading: HeadingLevel.TITLE,
           heading: HeadingLevel.TITLE,
           alignment: AlignmentType.CENTER,
           alignment: AlignmentType.CENTER,
         });
         });
@@ -410,7 +413,7 @@ XQIDAQAB
       }
       }
       if (author) {
       if (author) {
         const auth = new Paragraph({
         const auth = new Paragraph({
-          children: [ new TextRun({ color: '#000000', text: author }) ],
+          children: [new TextRun({ color: '#000000', text: author })],
           heading: HeadingLevel.HEADING_2,
           heading: HeadingLevel.HEADING_2,
           alignment: AlignmentType.RIGHT,
           alignment: AlignmentType.RIGHT,
         });
         });
@@ -419,7 +422,7 @@ XQIDAQAB
       if (content && _.isArray(content) && content.length > 0) {
       if (content && _.isArray(content) && content.length > 0) {
         for (const cont of content) {
         for (const cont of content) {
           const p = new Paragraph({
           const p = new Paragraph({
-            children: [ new TextRun({ text: cont, bold: true }) ],
+            children: [new TextRun({ text: cont, bold: true })],
           });
           });
           c.push(p);
           c.push(p);
         }
         }
@@ -526,6 +529,115 @@ XQIDAQAB
     await archive.finalize();
     await archive.finalize();
     return `/files${zipPath}${fn}`;
     return `/files${zipPath}${fn}`;
   }
   }
+
+  // 学校计划人数导出
+  async schoolDownload() {
+    const { app } = this;
+    const headList = [
+      { key: 'name', header: '学校', width: 50, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { key: 'code', header: '学校代码', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { key: 'class_special', header: '特殊班', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { key: 'class_common', header: '普通班', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+    ];
+    const nowDate = new Date().getTime();
+    const filename = `学校计划人数信息导出-${nowDate}.xlsx`;
+    const rootPath = `${app.config.cdn.repos_root_path}`;
+    const rooturl = `${app.config.cdn.repos_root_url_experience}`;
+    const path = `${rootPath}${rooturl}`;
+    if (!path) {
+      throw new BusinessError(ErrorCode.BUSINESS, '服务端没有设置存储路径');
+    }
+    if (!fs.existsSync(path)) {
+      // 如果不存在文件夹,就创建
+      this.mkdir(path);
+    }
+    const AggregateInfo = [
+      // 去除重复数据
+      { $group: { _id: '$code', uniqueData: { $first: '$$ROOT' } } },
+      { $replaceRoot: { newRoot: '$uniqueData' } },
+      { $addFields: { id: '$_id' } },
+    ];
+    const list = await this.sModel.aggregate(AggregateInfo);
+    const workbook = new Excel.Workbook();
+    const sheet = workbook.addWorksheet('sheet');
+    const meta = headList;
+    sheet.columns = meta;
+    sheet.addRows(list);
+    // 生成excel
+    const filepath = `${path}${filename}`;
+    if (list.length <= 0) return;
+    await workbook.xlsx.writeFile(filepath);
+    return `/files/excel/${filename}`;
+  }
+
+  // 学校计划人数导入
+  async schoolImport(data) {
+    const { filepath } = data;
+    assert(filepath, 'filepath不能为空');
+    // 取得excle中数据
+    const _filepath = this.ctx.app.config.baseUrl + filepath;
+    const teadatas = await this.getImportXLSXData(_filepath);
+    const school = [];
+    for (const val of teadatas) {
+      const schoolInfo = await this.sModel.findOne({ name: val.name }).lean();
+      const classnum = [];
+      let num;
+      if (val.class_special) classnum.push({ number: val.class_special, name: '特殊班', code: '1' });
+      if (val.class_common) classnum.push({ number: val.class_common, name: '普通班', code: '0' });
+      if (val.class_special && val.class_common) num = parseInt(val.class_special) || 0 + parseInt(val.class_common) || 0;
+      school.push({
+        _id: schoolInfo._id.toString(),
+        num,
+        code: val.code,
+        classnum,
+      });
+    }
+    return { school };
+  }
+  // 获取导入的XLSX文件中的数据
+  async getImportXLSXData(filepath) {
+    const file = await this.ctx.curl(filepath);
+    const workbook = XLSX.read(file.data);
+    // 读取内容
+    let exceldata = [];
+    const sheetNames = workbook.SheetNames; // 获取表名
+    const sheet = workbook.Sheets[sheetNames[0]]; // 通过表名得到表对象
+    // 遍历26个字母
+    const theadRule = [];
+    const range = XLSX.utils.decode_range(sheet['!ref']);
+    const col_start = range.s.c;
+    const col_end = range.e.c;
+    for (let i = col_start; i <= col_end; i++) {
+      const addr = XLSX.utils.encode_col(i) + XLSX.utils.encode_row(0);
+      theadRule.push(sheet[addr].v);
+    }
+    const params = XLSX.utils.sheet_to_json(sheet); // 通过工具将表对象的数据读出来并转成json
+    if (!params) return [];
+    const length = params.length;
+    const _datas = [];
+    let data = {};
+    for (let i = 0; i < length; i++) {
+      data = params[i];
+      _datas.push({
+        name: data[theadRule[0]],
+        code: data[theadRule[1]],
+        class_special: data[theadRule[2]],
+        class_common: data[theadRule[3]],
+      });
+    }
+    exceldata = [...exceldata, ..._datas];
+    return exceldata;
+  }
+  // 创建文件夹
+  mkdir(dirname) {
+    if (fs.existsSync(dirname)) {
+      return true;
+    }
+    if (this.mkdir(Path.dirname(dirname))) {
+      fs.mkdirSync(dirname);
+      return true;
+    }
+  }
 }
 }
 
 
 module.exports = UtilService;
 module.exports = UtilService;