import { Inject, Provide, Config } from '@midwayjs/core'; import { get } from 'lodash'; import { Context } from '@midwayjs/koa'; 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'; import { UserService } from './system/user.service'; import * as mappings from '../public/importMapping'; import * as Excel from 'exceljs'; import * as Path from 'path'; import * as fs from 'fs'; import { User } from '../entity/system/user.entity'; /** * 工具类服务,为其他地方提供一些通用的函数 */ @Provide() export class UtilService { @Inject() ctx: Context; @Inject() userService: UserService; @InjectEntityModel(User) userModel: Repository; @InjectEntityModel(Achievement) achievementModel: Repository; @InjectEntityModel(Project) projectModel: Repository; @InjectEntityModel(Demand) demandModel: Repository; @InjectEntityModel(Supply) supplyModel: Repository; @InjectEntityModel(Company) companyModel: Repository; @Inject() dictDataService: DictDataService; @Config('PathConfig.path') path; // 导出 async toExport(query) { const { table, config, user } = query; const nowDate = new Date().getTime(); const filename = `产学研用导出-${table}-${nowDate}.xlsx`; const path = this.path; if (!path) { throw new ServiceError('服务端没有设置存储路径'); } if (!fs.existsSync(path)) { // 如果不存在文件夹,就创建 this.mkdir(path); } try { let info = {}; if (user) info = { where: { user: Equal(user) } }; const targetModel = this[`${table}Model`]; const data = await targetModel.find(info); const workbook = new Excel.Workbook(); const sheet = workbook.addWorksheet('sheet1'); // 根据前端传回来的设置和顺序,将表头先塞进去 const meta = config.map(i => i.label); sheet.addRow(meta); let arr = []; for (const d of data) { arr = []; for (const c of config) { const { mark, model, code } = c; if (mark === 'tags') { if (d[model]) d[model] = arr.push(d[model].join(',')); else arr.push(d[model]); } else if (mark === 'area') { if (d[model]) d[model] = arr.push(d[model].join('-')); else arr.push(d[model]); } else if (mark === 'dict') { const req = await this.dictDataService.query({ code, is_use: '0' }, {}); if (req.data) { const selected = req.data.find(f => f.value === d[model]); if (selected) { d[model] = get(selected, 'label'); arr.push(d[model]); } else arr.push(d[model]); } else arr.push(d[model]); } else if (mark === 'time') { if (d.start_time && d.end_time) { arr.push((d[model] = `${d.start_time}-${d.end_time}`)); } else arr.push(d[model]); } else arr.push(d[model]); } sheet.addRow(arr); } // 生成excel const filepath = `${path}${filename}`; if (data.length <= 0) return; await workbook.xlsx.writeFile(filepath); return `/files/cxyy/export/${filename}`; } catch (error) { console.log(error); } } // 创建文件夹 mkdir(dirname) { if (fs.existsSync(dirname)) { return true; } if (this.mkdir(Path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } } 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}条${name}出现错误!!!`); } } else { try { await this.achievementModel.insert({ ...i, user: user_id, status: '0' }); } catch (error) { const namek = Object.keys(error.errors)[0]; const mapping = mappingList.find(i => i.field === namek); errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`); } } } 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}条${name}字段出现错误!!!`); } } else { try { await this.projectModel.insert({ ...i, user: user_id, status: '0' }); } catch (error) { const namek = Object.keys(error.errors)[0]; const mapping = mappingList.find(i => i.field === namek); errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`); } } } 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}条${name}出现错误!!!`); } } else { try { await this.demandModel.insert({ ...i, user: user_id, status: '0' }); } catch (error) { const namek = Object.keys(error.errors)[0]; const mapping = mappingList.find(i => i.field === namek); errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`); } } } 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}条${name}出现错误!!!`); } } else { try { await this.supplyModel.insert({ ...i, user: user_id, status: '0' }); } catch (error) { const namek = Object.keys(error.errors)[0]; const mapping = mappingList.find(i => i.field === namek); errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`); } } } 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}条${name}出现错误!!!`); } } else { try { const userInfo = await this.userModel.insert({ account: name, nick_name: name, password: '123456', gender: '0', role: ['User', 'Company'], status: '1' }); const id = get(userInfo, 'identifiers.0.id'); await this.companyModel.insert({ ...i, user: id, status: '0' }); } catch (error) { const namek = Object.keys(error.errors)[0]; const mapping = mappingList.find(i => i.field === namek); errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`); } } } 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('-'); } else if (type === 'number') { if (val) result = parseInt(val) || 0; } return result; } nameToFunction(name) { const obj = { 成果: 'achievement', 项目: 'project', 需求: 'demand', 供给: 'supply', 企业: 'company', }; return get(obj, name); } }