util.service.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. import { Inject, Provide, Config } from '@midwayjs/core';
  2. import { get } from 'lodash';
  3. import { Context } from '@midwayjs/koa';
  4. import { InjectEntityModel } from '@midwayjs/typeorm';
  5. import { ServiceError, ErrorCode } from '../error/service.error';
  6. import dayjs = require('dayjs');
  7. import { DictDataService } from './system/dictData.service';
  8. import { Equal, Repository } from 'typeorm';
  9. import { Achievement } from '../entity/platform/achievement.entity';
  10. import { Company } from '../entity/users/company.entity';
  11. import { Supply } from '../entity/platform/supply.entity';
  12. import { Project } from '../entity/platform/project.entity';
  13. import { Demand } from '../entity/platform/demand.entity';
  14. import { UserService } from './system/user.service';
  15. import * as mappings from '../public/importMapping';
  16. import * as Excel from 'exceljs';
  17. import * as Path from 'path';
  18. import * as fs from 'fs';
  19. import { User } from '../entity/system/user.entity';
  20. /**
  21. * 工具类服务,为其他地方提供一些通用的函数
  22. */
  23. @Provide()
  24. export class UtilService {
  25. @Inject()
  26. ctx: Context;
  27. @Inject()
  28. userService: UserService;
  29. @InjectEntityModel(User)
  30. userModel: Repository<User>;
  31. @InjectEntityModel(Achievement)
  32. achievementModel: Repository<Achievement>;
  33. @InjectEntityModel(Project)
  34. projectModel: Repository<Project>;
  35. @InjectEntityModel(Demand)
  36. demandModel: Repository<Demand>;
  37. @InjectEntityModel(Supply)
  38. supplyModel: Repository<Supply>;
  39. @InjectEntityModel(Company)
  40. companyModel: Repository<Company>;
  41. @Inject()
  42. dictDataService: DictDataService;
  43. @Config('PathConfig.path')
  44. path;
  45. // 导出
  46. async toExport(query) {
  47. const { table, config, user } = query;
  48. const nowDate = new Date().getTime();
  49. const filename = `产学研用导出-${table}-${nowDate}.xlsx`;
  50. const path = this.path;
  51. if (!path) {
  52. throw new ServiceError('服务端没有设置存储路径');
  53. }
  54. if (!fs.existsSync(path)) {
  55. // 如果不存在文件夹,就创建
  56. this.mkdir(path);
  57. }
  58. try {
  59. let info = {};
  60. if (user) info = { where: { user: Equal(user) } };
  61. const targetModel = this[`${table}Model`];
  62. const data = await targetModel.find(info);
  63. const workbook = new Excel.Workbook();
  64. const sheet = workbook.addWorksheet('sheet1');
  65. // 根据前端传回来的设置和顺序,将表头先塞进去
  66. const meta = config.map(i => i.label);
  67. sheet.addRow(meta);
  68. let arr = [];
  69. for (const d of data) {
  70. arr = [];
  71. for (const c of config) {
  72. const { mark, model, code } = c;
  73. if (mark === 'tags') {
  74. if (d[model]) d[model] = arr.push(d[model].join(','));
  75. else arr.push(d[model]);
  76. } else if (mark === 'area') {
  77. if (d[model]) d[model] = arr.push(d[model].join('-'));
  78. else arr.push(d[model]);
  79. } else if (mark === 'dict') {
  80. const req = await this.dictDataService.query({ code, is_use: '0' }, {});
  81. if (req.data) {
  82. const selected = req.data.find(f => f.value === d[model]);
  83. if (selected) {
  84. d[model] = get(selected, 'label');
  85. arr.push(d[model]);
  86. } else arr.push(d[model]);
  87. } else arr.push(d[model]);
  88. } else if (mark === 'time') {
  89. if (d.start_time && d.end_time) {
  90. arr.push((d[model] = `${d.start_time}-${d.end_time}`));
  91. } else arr.push(d[model]);
  92. } else arr.push(d[model]);
  93. }
  94. sheet.addRow(arr);
  95. }
  96. // 生成excel
  97. const filepath = `${path}${filename}`;
  98. if (data.length <= 0) return;
  99. await workbook.xlsx.writeFile(filepath);
  100. return `/files/cxyy/export/${filename}`;
  101. } catch (error) {
  102. console.log(error);
  103. }
  104. }
  105. // 创建文件夹
  106. mkdir(dirname) {
  107. if (fs.existsSync(dirname)) {
  108. return true;
  109. }
  110. if (this.mkdir(Path.dirname(dirname))) {
  111. fs.mkdirSync(dirname);
  112. return true;
  113. }
  114. }
  115. randomStr(len = 6) {
  116. return Math.random().toString(36).slice(-len);
  117. }
  118. /**
  119. * 成果
  120. * @param {Object} rows excel数据
  121. */
  122. async achievement(rows) {
  123. const mappingList = mappings.achievement;
  124. const result = await this.dealRows(rows, mappingList);
  125. const errorList = [];
  126. // 需要查看是否有人,有人更新数据,没人添加数据
  127. const user_id = this.ctx.user.id;
  128. for (const [index, i] of result.entries()) {
  129. // 根据 成果名称 查重
  130. const { name } = i;
  131. const data = await this.achievementModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
  132. if (data && data.id) {
  133. try {
  134. i.id = data.id;
  135. await this.achievementModel.update({ id: data.id }, i);
  136. } catch (error) {
  137. errorList.push(`修改第${index + 1}条${name}出现错误!!!`);
  138. }
  139. } else {
  140. try {
  141. await this.achievementModel.insert({ ...i, user: user_id, status: '0' });
  142. } catch (error) {
  143. const namek = Object.keys(error.errors)[0];
  144. const mapping = mappingList.find(i => i.field === namek);
  145. errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`);
  146. }
  147. }
  148. }
  149. return { result: result.length, errorList };
  150. }
  151. /**
  152. * 项目
  153. * @param {Object} rows excel数据
  154. */
  155. async project(rows) {
  156. const mappingList = mappings.project;
  157. const result = await this.dealRows(rows, mappingList);
  158. const errorList = [];
  159. // 需要查看是否有人,有人更新数据,没人添加数据
  160. const user_id = this.ctx.user.id;
  161. for (const [index, i] of result.entries()) {
  162. // 根据 项目名称 查重
  163. const { name } = i;
  164. const data = await this.projectModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
  165. if (data && data.id) {
  166. try {
  167. i.id = data.id;
  168. await this.projectModel.update({ id: data.id }, i);
  169. } catch (error) {
  170. errorList.push(`修改第${index + 1}条${name}字段出现错误!!!`);
  171. }
  172. } else {
  173. try {
  174. await this.projectModel.insert({ ...i, user: user_id, status: '0' });
  175. } catch (error) {
  176. const namek = Object.keys(error.errors)[0];
  177. const mapping = mappingList.find(i => i.field === namek);
  178. errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`);
  179. }
  180. }
  181. }
  182. return { result: result.length, errorList };
  183. }
  184. /**
  185. * 需求
  186. * @param {Object} rows excel数据
  187. */
  188. async demand(rows) {
  189. const mappingList = mappings.demand;
  190. const result = await this.dealRows(rows, mappingList);
  191. const errorList = [];
  192. // 需要查看是否有人,有人更新数据,没人添加数据
  193. const user_id = this.ctx.user.id;
  194. for (const [index, i] of result.entries()) {
  195. // 根据 需求名称 查重
  196. const { name } = i;
  197. const data = await this.demandModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
  198. if (data && data.id) {
  199. try {
  200. i.id = data.id;
  201. await this.demandModel.update({ id: data.id }, i);
  202. } catch (error) {
  203. errorList.push(`修改第${index + 1}条${name}出现错误!!!`);
  204. }
  205. } else {
  206. try {
  207. await this.demandModel.insert({ ...i, user: user_id, status: '0' });
  208. } catch (error) {
  209. const namek = Object.keys(error.errors)[0];
  210. const mapping = mappingList.find(i => i.field === namek);
  211. errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`);
  212. }
  213. }
  214. }
  215. return { result: result.length, errorList };
  216. }
  217. /**
  218. * 供给
  219. * @param {Object} rows excel数据
  220. */
  221. async supply(rows) {
  222. const mappingList = mappings.supply;
  223. const result = await this.dealRows(rows, mappingList);
  224. const errorList = [];
  225. // 需要查看是否有人,有人更新数据,没人添加数据
  226. const user_id = this.ctx.user.id;
  227. for (const [index, i] of result.entries()) {
  228. // 根据 供给名称 查重
  229. const { name } = i;
  230. const data = await this.supplyModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
  231. if (data && data.id) {
  232. try {
  233. i.id = data.id;
  234. await this.supplyModel.update({ id: data.id }, i);
  235. } catch (error) {
  236. errorList.push(`修改第${index + 1}条${name}出现错误!!!`);
  237. }
  238. } else {
  239. try {
  240. await this.supplyModel.insert({ ...i, user: user_id, status: '0' });
  241. } catch (error) {
  242. const namek = Object.keys(error.errors)[0];
  243. const mapping = mappingList.find(i => i.field === namek);
  244. errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`);
  245. }
  246. }
  247. }
  248. return { result: result.length, errorList };
  249. }
  250. /**
  251. * 企业
  252. * @param {Object} rows excel数据
  253. */
  254. async company(rows) {
  255. const mappingList = mappings.company;
  256. const result = await this.dealRows(rows, mappingList);
  257. const errorList = [];
  258. // 需要查看是否有人,有人更新数据,没人添加数据
  259. const user_id = this.ctx.user.id;
  260. for (const [index, i] of result.entries()) {
  261. // 根据 企业名称 查重
  262. const { name } = i;
  263. const data = await this.companyModel.findOne({ where: { user: Equal(user_id), name: Equal(name) } });
  264. if (data && data.id) {
  265. try {
  266. i.id = data.id;
  267. await this.companyModel.update({ id: data.id }, i);
  268. } catch (error) {
  269. errorList.push(`修改第${index + 1}条${name}出现错误!!!`);
  270. }
  271. } else {
  272. try {
  273. const userInfo = await this.userModel.insert({ account: name, nick_name: name, password: '123456', gender: '0', role: ['User', 'Company'], status: '1' });
  274. const id = get(userInfo, 'identifiers.0.id');
  275. await this.companyModel.insert({ ...i, user: id, status: '0' });
  276. } catch (error) {
  277. const namek = Object.keys(error.errors)[0];
  278. const mapping = mappingList.find(i => i.field === namek);
  279. errorList.push(`第${index + 1}条${mapping.zh}列${name}字段出现错误!!!`);
  280. }
  281. }
  282. }
  283. return { result: result.length, errorList };
  284. }
  285. /**
  286. * 处理excel传来的数据
  287. * @param {Array} rows excel数据,二维数组
  288. * @param {Object} mappingList 设置的某个映射
  289. * @return {Array} result 数据
  290. */
  291. async dealRows(rows, mappingList) {
  292. const result = [];
  293. const user = this.ctx.user;
  294. if (!user) throw new ServiceError(ErrorCode.USER_NOT_FOUND);
  295. for (let i = 0; i < rows.length; i++) {
  296. const rowData = rows[i];
  297. const obj = { user: user.id };
  298. for (let k = 0; k < rowData.length; k++) {
  299. let val = rowData[k];
  300. if (val === null) continue;
  301. if (typeof val === 'object' && val !== null) {
  302. const richText = get(val, 'richText');
  303. if (richText) {
  304. let texts = '';
  305. // 使用map提取name字段,然后检查是否为undefined
  306. // eslint-disable-next-line array-callback-return
  307. const mappedNames = richText.map(item => {
  308. // 判断字段是否存在
  309. if ('text' in item) {
  310. return item.text;
  311. }
  312. });
  313. // 过滤掉null或undefined的值
  314. const filteredNames = mappedNames.filter(text => text !== null && text !== undefined);
  315. // 拼接字符串
  316. texts = filteredNames.join('');
  317. val = texts;
  318. }
  319. }
  320. const mapping = mappingList.find(f => f.index === k);
  321. if (mapping) {
  322. const { field, type } = mapping;
  323. if (type) val = await this.dealTypeValue(mapping, val);
  324. obj[field] = val;
  325. }
  326. }
  327. result.push(obj);
  328. }
  329. return result;
  330. }
  331. /**
  332. * 转换数据
  333. * @param {Object} mapping 当前要处理的映射
  334. * @param {any} val excel值
  335. * @return {any} result 转换后的数据
  336. */
  337. async dealTypeValue(mapping, val) {
  338. const { type, code } = mapping;
  339. let result;
  340. if (type === 'date') {
  341. // 判断日期对不对,经过moment处理下
  342. const mobj = dayjs(val);
  343. if (mobj.isValid()) {
  344. result = mobj.format('YYYY-MM-DD');
  345. }
  346. } else if (type === 'dict') {
  347. const req = await this.dictDataService.query({}, { code });
  348. if (req.data) {
  349. const selected = req.data.find(f => f.label === val);
  350. if (selected) result = get(selected, 'value');
  351. }
  352. } else if (type === 'area') {
  353. if (val) result = val.split('-');
  354. } else if (type === 'number') {
  355. if (val) result = parseInt(val) || 0;
  356. }
  357. return result;
  358. }
  359. nameToFunction(name) {
  360. const obj = {
  361. 成果: 'achievement',
  362. 项目: 'project',
  363. 需求: 'demand',
  364. 供给: 'supply',
  365. 企业: 'company',
  366. };
  367. return get(obj, name);
  368. }
  369. }