浏览代码

修改导入的接口

zs 8 月之前
父节点
当前提交
68b9d3826a
共有 3 个文件被更改,包括 425 次插入20 次删除
  1. 106 0
      public/importMapping.js
  2. 44 1
      src/controller/util.controller.ts
  3. 275 19
      src/service/util.service.ts

+ 106 - 0
public/importMapping.js

@@ -0,0 +1,106 @@
+// 注释是表名
+// achievement
+const achievement = [
+  { index: 1, field: 'name', zh: '名称' },
+  { index: 2, field: 'industry', zh: '所属产业' },
+  { index: 3, field: 'patent', zh: '专利号' },
+  { index: 4, field: 'name', zh: '名称' },
+  { index: 5, field: 'attribute', type: 'dict', code: 'attribute', zh: '属性' },
+  { index: 6, field: 'sell', type: 'dict', code: 'sell', zh: '出让方式' },
+  { index: 7, field: 'mature', type: 'dict', code: 'mature', zh: '成熟度' },
+  { index: 8, field: 'field', type: 'dict', code: 'field', zh: '行业领域' },
+  { index: 9, field: 'technology', type: 'dict', code: 'technology', zh: '技术分类' },
+  { index: 10, field: 'area', type: 'area', zh: '地区' },
+  { index: 10, field: 'money', zh: '参考价格' },
+  { index: 11, field: 'time', type: 'date', zh: '发布时间' },
+  { index: 12, field: 'source', zh: '项目来源' },
+  { index: 13, field: 'person', zh: '负责人' },
+  { index: 14, field: 'tel', zh: '联系电话' },
+  { index: 15, field: 'brief', zh: '简介' },
+];
+
+// project
+const project = [
+  { index: 1, field: 'name', zh: '名称' },
+  { index: 2, field: 'industry', zh: '所属产业' },
+  { index: 3, field: 'time', type: 'date', zh: '发布时间' },
+  { index: 4, field: 'type', type: 'dict', code: 'industry', zh: '行业分类' },
+  { index: 5, field: 'maturity', type: 'dict', code: 'projectMaturity', zh: '成熟度' },
+  { index: 6, field: 'skill', type: 'dict', code: 'technology', zh: '技术类型' },
+  { index: 7, field: 'field', type: 'dict', code: 'field', zh: '行业领域' },
+  { index: 8, field: 'cooperate', type: 'dict', code: 'projectType', zh: '合作类型' },
+  { index: 9, field: 'area', type: 'area', zh: '地区' },
+  { index: 10, field: 'main', zh: '项目主体' },
+  { index: 11, field: 'progress', zh: '项目进展' },
+  { index: 12, field: 'main', zh: '项目主体' },
+  { index: 13, field: 'track_unit', zh: '跟踪支持单位' },
+  { index: 14, field: 'source', zh: '项目来源' },
+  { index: 15, field: 'brief', zh: '简介' },
+];
+
+// demand
+const demand = [
+  { index: 1, field: 'name', zh: '名称' },
+  { index: 2, field: 'industry', zh: '所属产业' },
+  { index: 3, field: 'start_time', type: 'date', zh: '开始时间' },
+  { index: 4, field: 'end_time', type: 'date', zh: '结束时间' },
+  { index: 5, field: 'money', type: 'date', zh: '价格' },
+  { index: 6, field: 'type', type: 'dict', code: 'type', zh: '类型' },
+  { index: 7, field: 'field', type: 'dict', code: 'field', zh: '行业领域' },
+  { index: 8, field: 'urgent', type: 'dict', code: 'urgent', zh: '需求紧急度' },
+  { index: 9, field: 'method', type: 'dict', code: 'method', zh: '合作方式' },
+  { index: 10, field: 'area', type: 'area', zh: '地区' },
+  { index: 11, field: 'company', zh: '所属企业' },
+  { index: 12, field: 'company_brief', zh: '企业简况' },
+  { index: 13, field: 'contacts', zh: '联系人' },
+  { index: 14, field: 'tel', zh: '联系电话' },
+  { index: 15, field: 'year', zh: '年份' },
+  { index: 16, field: 'month', zh: '月份' },
+  { index: 17, field: 'tec_name', zh: '技术需求名称' },
+  { index: 18, field: 'question', zh: '待解决问题' },
+  { index: 19, field: 'brief', zh: '简介' },
+];
+
+// supply
+const supply = [
+  { index: 1, field: 'name', zh: '名称' },
+  { index: 2, field: 'industry', zh: '所属产业' },
+  { index: 3, field: 'start_time', type: 'date', zh: '开始时间' },
+  { index: 4, field: 'end_time', type: 'date', zh: '结束时间' },
+  { index: 5, field: 'money', type: 'date', zh: '价格' },
+  { index: 6, field: 'type', type: 'dict', code: 'type', zh: '类型' },
+  { index: 7, field: 'field', type: 'dict', code: 'field', zh: '行业领域' },
+  { index: 8, field: 'urgent', type: 'dict', code: 'urgent', zh: '需求紧急度' },
+  { index: 9, field: 'method', type: 'dict', code: 'method', zh: '合作方式' },
+  { index: 10, field: 'area', type: 'area', zh: '地区' },
+  { index: 11, field: 'source', zh: '项目来源' },
+  { index: 19, field: 'brief', zh: '简介' },
+];
+
+// company
+const company = [
+  { index: 1, field: 'name', zh: '名称' },
+  { index: 2, field: 'industry', zh: '所属产业' },
+  { index: 3, field: 'code', zh: '企业统一信用代码名称' },
+  { index: 3, field: 'representative', zh: '法定代表人' },
+  { index: 3, field: 'email', zh: '电子邮箱' },
+  { index: 3, field: 'number', zh: '员工人数' },
+  { index: 3, field: 'register', zh: '注册资本' },
+  { index: 3, field: 'create_time', type: 'date', zh: '成立时间' },
+  { index: 6, field: 'pattern', type: 'dict', code: 'pattern', zh: '企业类型' },
+  { index: 7, field: 'scale', type: 'dict', code: 'scale', zh: '企业规模' },
+  { index: 7, field: 'type', type: 'dict', code: 'type', zh: '所属行业' },
+  { index: 10, field: 'area', type: 'area', zh: '地区' },
+  { index: 11, field: 'phone', zh: '联系电话' },
+  { index: 12, field: 'address', zh: '地址' },
+  { index: 13, field: 'products', zh: '产品' },
+  { index: 19, field: 'brief', zh: '简介' },
+];
+
+module.exports = {
+  achievement,
+  project,
+  demand,
+  supply,
+  company,
+};

+ 44 - 1
src/controller/util.controller.ts

@@ -1,9 +1,52 @@
-import { Controller, Get, Inject } from '@midwayjs/core';
+import { Controller, Post, Inject } from '@midwayjs/core';
+import { Context } from '@midwayjs/koa';
 import { ApiTags } from '@midwayjs/swagger';
 import { UtilService } from '../service/util.service';
+const Excel = require('exceljs');
 @ApiTags(['工具'])
 @Controller('/util')
 export class UtilController {
   @Inject()
   service: UtilService;
+
+  @Inject()
+  ctx: Context;
+
+  @Post('/toImport')
+  async toImport() {
+    const stream = await this.ctx.getFileStream();
+    const workbook = new Excel.Workbook();
+    await workbook.xlsx.read(stream);
+    const result = [];
+    const sheetList = [];
+    workbook.eachSheet(sheet => {
+      // 整理出的数据
+      const rows = [];
+      sheet.eachRow((row, ri) => {
+        if (ri !== 1) {
+          const rd = [null];
+          row.eachCell({ includeEmpty: true }, c => {
+            const value = c.value;
+            rd.push(value);
+          });
+          rows.push(rd);
+        }
+      });
+      sheetList.push({ sheet: sheet.name, rows });
+    });
+    for (const s of sheetList) {
+      const { sheet, rows } = s;
+      const func = this.service.nameToFunction(sheet);
+      if (!func) continue;
+      try {
+        const num = await this.service[func](rows);
+        result[sheet] = num.result;
+        result.push({ key: sheet, num: num.result, errorList: num.errorList.join(',') });
+      } catch (error) {
+        console.log(error);
+        result.push({ key: sheet, num: 'error' });
+      }
+    }
+    this.ctx.ok({ data: result });
+  }
 }

+ 275 - 19
src/service/util.service.ts

@@ -1,13 +1,17 @@
 import { Inject, Provide } from '@midwayjs/core';
-import { get, union } from 'lodash';
-import { UserService } from './system/user.service';
+import { get } from 'lodash';
 import { Context } from '@midwayjs/koa';
-import { AchievementService } from './platform/achievement.service';
-import { ProjectService } from './platform/project.service';
-import { DemandService } from './platform/demand.service';
-import { SupplyService } from './platform/supply.service';
-import { CompanyService } from './users/company.service';
-
+import { InjectEntityModel } from '@midwayjs/typeorm';
+import { ServiceError, ErrorCode } from '../error/service.error';
+import dayjs = require('dayjs');
+import { DictDataService } from './system/dictData.service';
+import { Equal, Repository } from 'typeorm';
+import { Achievement } from '../entity/platform/achievement.entity';
+import { Company } from '../entity/users/company.entity';
+import { Supply } from '../entity/platform/supply.entity';
+import { Project } from '../entity/platform/project.entity';
+import { Demand } from '../entity/platform/demand.entity';
+const mappings = require('../../public/importMapping');
 /**
  * 工具类服务,为其他地方提供一些通用的函数
  */
@@ -15,20 +19,272 @@ import { CompanyService } from './users/company.service';
 export class UtilService {
   @Inject()
   ctx: Context;
+  @InjectEntityModel(Achievement)
+  achievementModel: Repository<Achievement>;
+  @InjectEntityModel(Project)
+  projectModel: Repository<Project>;
+  @InjectEntityModel(Demand)
+  demandModel: Repository<Demand>;
+  @InjectEntityModel(Supply)
+  supplyModel: Repository<Supply>;
+  @InjectEntityModel(Company)
+  companyModel: Repository<Company>;
   @Inject()
-  userService: UserService;
-  @Inject()
-  achievementService: AchievementService;
-  @Inject()
-  projectService: ProjectService;
-  @Inject()
-  demandService: DemandService;
-  @Inject()
-  supplyService: SupplyService;
-  @Inject()
-  companyService: CompanyService;
+  dictDataService: DictDataService;
 
   randomStr(len = 6) {
     return Math.random().toString(36).slice(-len);
   }
+
+  /**
+   * 成果
+   * @param {Object} rows excel数据
+   */
+  async achievement(rows) {
+    const mappingList = mappings.achievement;
+    const result = await this.dealRows(rows, mappingList);
+    const errorList = [];
+    // 需要查看是否有人,有人更新数据,没人添加数据
+    const user_id = this.ctx.user.id;
+    for (const [index, i] of result.entries()) {
+      // 根据 成果名称 查重
+      const { name } = i;
+      const data = await this.achievementModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
+      if (data && data.id) {
+        try {
+          i.id = data.id;
+          await this.achievementModel.update({ id: data.id }, i);
+        } catch (error) {
+          errorList.push(`修改第${index + 1}条出现错误!!!`);
+        }
+      } else {
+        try {
+          await this.achievementModel.create({ ...i, user: user_id });
+        } catch (error) {
+          const namek = Object.keys(error.errors)[0];
+          const mapping = mappingList.find(i => i.field === namek);
+          errorList.push(`第${index + 1}条${mapping.zh}列字段出现错误!!!`);
+        }
+      }
+    }
+    return { result: result.length, errorList };
+  }
+
+  /**
+   * 项目
+   * @param {Object} rows excel数据
+   */
+  async project(rows) {
+    const mappingList = mappings.project;
+    const result = await this.dealRows(rows, mappingList);
+    const errorList = [];
+    // 需要查看是否有人,有人更新数据,没人添加数据
+    const user_id = this.ctx.user.id;
+    for (const [index, i] of result.entries()) {
+      // 根据 项目名称 查重
+      const { name } = i;
+      const data = await this.projectModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
+      if (data && data.id) {
+        try {
+          i.id = data.id;
+          await this.projectModel.update({ id: data.id }, i);
+        } catch (error) {
+          errorList.push(`修改第${index + 1}条出现错误!!!`);
+        }
+      } else {
+        try {
+          await this.projectModel.create({ ...i, user: user_id });
+        } catch (error) {
+          const namek = Object.keys(error.errors)[0];
+          const mapping = mappingList.find(i => i.field === namek);
+          errorList.push(`第${index + 1}条${mapping.zh}列字段出现错误!!!`);
+        }
+      }
+    }
+    return { result: result.length, errorList };
+  }
+  /**
+   * 需求
+   * @param {Object} rows excel数据
+   */
+  async demand(rows) {
+    const mappingList = mappings.demand;
+    const result = await this.dealRows(rows, mappingList);
+    const errorList = [];
+    // 需要查看是否有人,有人更新数据,没人添加数据
+    const user_id = this.ctx.user.id;
+    for (const [index, i] of result.entries()) {
+      // 根据 需求名称 查重
+      const { name } = i;
+      const data = await this.demandModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
+      if (data && data.id) {
+        try {
+          i.id = data.id;
+          await this.demandModel.update({ id: data.id }, i);
+        } catch (error) {
+          errorList.push(`修改第${index + 1}条出现错误!!!`);
+        }
+      } else {
+        try {
+          await this.demandModel.create({ ...i, user: user_id });
+        } catch (error) {
+          const namek = Object.keys(error.errors)[0];
+          const mapping = mappingList.find(i => i.field === namek);
+          errorList.push(`第${index + 1}条${mapping.zh}列字段出现错误!!!`);
+        }
+      }
+    }
+    return { result: result.length, errorList };
+  }
+  /**
+   * 供给
+   * @param {Object} rows excel数据
+   */
+  async supply(rows) {
+    const mappingList = mappings.supply;
+    const result = await this.dealRows(rows, mappingList);
+    const errorList = [];
+    // 需要查看是否有人,有人更新数据,没人添加数据
+    const user_id = this.ctx.user.id;
+    for (const [index, i] of result.entries()) {
+      // 根据 供给名称 查重
+      const { name } = i;
+      const data = await this.supplyModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
+      if (data && data.id) {
+        try {
+          i.id = data.id;
+          await this.supplyModel.update({ id: data.id }, i);
+        } catch (error) {
+          errorList.push(`修改第${index + 1}条出现错误!!!`);
+        }
+      } else {
+        try {
+          await this.supplyModel.create({ ...i, user: user_id });
+        } catch (error) {
+          const namek = Object.keys(error.errors)[0];
+          const mapping = mappingList.find(i => i.field === namek);
+          errorList.push(`第${index + 1}条${mapping.zh}列字段出现错误!!!`);
+        }
+      }
+    }
+    return { result: result.length, errorList };
+  }
+
+  /**
+   * 企业
+   * @param {Object} rows excel数据
+   */
+  async company(rows) {
+    const mappingList = mappings.company;
+    const result = await this.dealRows(rows, mappingList);
+    const errorList = [];
+    // 需要查看是否有人,有人更新数据,没人添加数据
+    const user_id = this.ctx.user.id;
+    for (const [index, i] of result.entries()) {
+      // 根据 企业名称 查重
+      const { name } = i;
+      const data = await this.companyModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
+      if (data && data.id) {
+        try {
+          i.id = data.id;
+          await this.companyModel.update({ id: data.id }, i);
+        } catch (error) {
+          errorList.push(`修改第${index + 1}条出现错误!!!`);
+        }
+      } else {
+        try {
+          await this.companyModel.create({ ...i, user: user_id });
+        } catch (error) {
+          const namek = Object.keys(error.errors)[0];
+          const mapping = mappingList.find(i => i.field === namek);
+          errorList.push(`第${index + 1}条${mapping.zh}列字段出现错误!!!`);
+        }
+      }
+    }
+    return { result: result.length, errorList };
+  }
+  /**
+   * 处理excel传来的数据
+   * @param {Array} rows excel数据,二维数组
+   * @param {Object} mappingList 设置的某个映射
+   * @return {Array} result 数据
+   */
+  async dealRows(rows, mappingList) {
+    const result = [];
+    const user = this.ctx.user;
+    if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
+    for (let i = 0; i < rows.length; i++) {
+      const rowData = rows[i];
+      const obj = { user: user.id };
+      for (let k = 0; k < rowData.length; k++) {
+        let val = rowData[k];
+        if (val === null) continue;
+        if (typeof val === 'object' && val !== null) {
+          const richText = get(val, 'richText');
+          if (richText) {
+            let texts = '';
+            // 使用map提取name字段,然后检查是否为undefined
+            // eslint-disable-next-line array-callback-return
+            const mappedNames = richText.map(item => {
+              // 判断字段是否存在
+              if ('text' in item) {
+                return item.text;
+              }
+            });
+            // 过滤掉null或undefined的值
+            const filteredNames = mappedNames.filter(text => text !== null && text !== undefined);
+            // 拼接字符串
+            texts = filteredNames.join('');
+            val = texts;
+          }
+        }
+        const mapping = mappingList.find(f => f.index === k);
+        if (mapping) {
+          const { field, type } = mapping;
+          if (type) val = await this.dealTypeValue(mapping, val);
+          obj[field] = val;
+        }
+      }
+      result.push(obj);
+    }
+    return result;
+  }
+
+  /**
+   * 转换数据
+   * @param {Object} mapping 当前要处理的映射
+   * @param {any} val excel值
+   * @return {any} result 转换后的数据
+   */
+  async dealTypeValue(mapping, val) {
+    const { type, code } = mapping;
+    let result;
+    if (type === 'date') {
+      // 判断日期对不对,经过moment处理下
+      const mobj = dayjs(val);
+      if (mobj.isValid()) {
+        result = mobj.format('YYYY-MM-DD');
+      }
+    } else if (type === 'dict') {
+      const req = await this.dictDataService.query({}, { code });
+      if (req.data) {
+        const selected = req.data.find(f => f.label === val);
+        if (selected) result = get(selected, 'value');
+      }
+    } else if (type === 'area') {
+      if (val) result = val.split('-');
+    }
+    return result;
+  }
+
+  nameToFunction(name) {
+    const obj = {
+      成果: 'achievement',
+      项目: 'project',
+      需求: 'demand',
+      供给: 'supply',
+      企业: 'company',
+    };
+    return get(obj, name);
+  }
 }