personal.service.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import { Provide, Inject } from '@midwayjs/decorator';
  2. import { InjectEntityModel } from '@midwayjs/typegoose';
  3. import { ReturnModelType } from '@typegoose/typegoose';
  4. import { HttpServiceFactory, HttpService } from '@midwayjs/axios';
  5. import { Config, InjectClient } from '@midwayjs/core';
  6. import {
  7. BaseService,
  8. FrameworkErrorEnum,
  9. ServiceError,
  10. } from 'free-midway-component';
  11. import { Personal } from '../../entity/user/personal.entity';
  12. import { Admin } from '../../entity/user/admin.entity';
  13. import {
  14. LoginDTO,
  15. QDTO_personal,
  16. } from '../../interface/user/personal.interface';
  17. import _ = require('lodash');
  18. import { UtilService } from '../../service/util/util';
  19. const Excel = require('exceljs');
  20. import * as fs from 'node:fs';
  21. import * as Path from 'node:path';
  22. const sep = Path.sep;
  23. const assert = require('assert');
  24. type modelType = ReturnModelType<typeof Personal>;
  25. @Provide()
  26. export class PersonalService extends BaseService<modelType> {
  27. @InjectEntityModel(Personal)
  28. model: modelType;
  29. @InjectEntityModel(Admin)
  30. adminModel: ReturnModelType<typeof Admin>;
  31. @Inject()
  32. util: UtilService;
  33. @Config('export.root_path')
  34. root_path;
  35. @InjectClient(HttpServiceFactory, 'Axios')
  36. Axios: HttpService;
  37. async findUserToLogin(data: LoginDTO): Promise<object> {
  38. const { account, password } = data;
  39. const user = await this.model.findOne({ account }, '+password').lean();
  40. if (!user)
  41. throw new ServiceError(
  42. '未找到个人用户信息',
  43. FrameworkErrorEnum.NOT_FOUND_DATA
  44. );
  45. if (_.get(user, 'status') !== '1')
  46. throw new ServiceError(
  47. '当前个人用户没有通过审核,拒绝登录',
  48. FrameworkErrorEnum.SERVICE_FAULT
  49. );
  50. if (!_.isEqual(user.password.secret, password))
  51. throw new ServiceError('密码错误', FrameworkErrorEnum.SERVICE_FAULT);
  52. return user;
  53. }
  54. async dealQueryCondition(condition: QDTO_personal): Promise<QDTO_personal> {
  55. const { type, code } = this.ctx.user;
  56. condition = this.util.dealQuery(condition);
  57. // 查询业务管理
  58. const busFind = async query =>
  59. await this.adminModel.find({ ...query, type: '3' }, { code: 1 });
  60. // 查询机构管理
  61. const orgFind = async query =>
  62. await this.adminModel.find({ ...query, type: '2' }, { code: 1 });
  63. // 查询管理员
  64. const aFind = async query =>
  65. await this.adminModel.find({ ...query, type: '1' }, { code: 1 });
  66. if (type === '1' && code) {
  67. // 管理员查询
  68. // =>获取该code下的机构管理员列表 => 用机构管理员id 获取业务管理员列表 => 将code都整理出来作为查询条件
  69. const a = await aFind({ code });
  70. if (a.length <= 0)
  71. throw new ServiceError(
  72. '未找到该管理员',
  73. FrameworkErrorEnum.NOT_FOUND_DATA
  74. );
  75. const aid = _.get(_.head(a), '_id');
  76. const orgList = await orgFind({ pid: aid });
  77. const busList = await busFind({ pid: orgList.map(i => i._id) });
  78. const codes: any = [
  79. ...orgList.map(i => i.code),
  80. ...busList.map(i => i.code),
  81. code,
  82. ];
  83. condition.code = codes;
  84. } else if (type === '2' && code) {
  85. // 机构查询
  86. // =>获取该code下的业务管理员列表 => 将code都整理出来作为查询条件
  87. const o = await orgFind({ code });
  88. if (o.length <= 0)
  89. throw new ServiceError(
  90. '未找到该机构',
  91. FrameworkErrorEnum.NOT_FOUND_DATA
  92. );
  93. const oid = _.get(_.head(o), '_id');
  94. const busList = await busFind({ pid: oid });
  95. const codes: any = [...busList.map(i => i.code), code];
  96. condition.code = codes;
  97. } else if (type === '3' && code) {
  98. // 业务查询
  99. // code直接查询用户返回即可
  100. condition.code = code;
  101. }
  102. // 没有code,超级管理员,说明不限制
  103. return condition;
  104. }
  105. // 导入
  106. async import(uri) {
  107. assert(uri.url, '未获取到文件地址');
  108. const file = await this.Axios.get(uri.url);
  109. if (!file) {
  110. throw new ServiceError(
  111. '未找到指定文件',
  112. FrameworkErrorEnum.NOT_FOUND_DATA
  113. );
  114. }
  115. const workbook = new Excel.Workbook();
  116. await workbook.xlsx.load(file);
  117. const sheet = workbook.getWorksheet(1);
  118. // 根据excel,将列序号加入meta中
  119. const meta: any = _.get(this.model.schema, 'tree');
  120. const list: any = [];
  121. const head = _.get(sheet.getRow(1), 'values', []);
  122. for (let i = 0; i < head.length; i++) {
  123. const e = head[i];
  124. if (!e) continue;
  125. for (const key in meta) {
  126. if (Object.prototype.hasOwnProperty.call(meta, key)) {
  127. if (e === meta[key].zh) {
  128. meta[key].index = i;
  129. meta[key].key = key;
  130. list.push(meta[key]);
  131. }
  132. }
  133. }
  134. }
  135. const errorList = [];
  136. const dataList = [];
  137. sheet.eachRow(async (row, index) => {
  138. if (index !== 1) {
  139. const values = row.values;
  140. const obj = {};
  141. for (const m of list) {
  142. const { required, key, zh, index } = m;
  143. const value = values[index];
  144. if (required && !value) {
  145. // 必填且没值的情况
  146. errorList.push({
  147. message: `第${index}行数据,缺少必填项 ${zh};`,
  148. });
  149. continue;
  150. }
  151. obj[key] = value;
  152. }
  153. dataList.push(obj);
  154. }
  155. });
  156. for (const data of dataList) {
  157. try {
  158. await this.model.create(data);
  159. } catch (error) {
  160. errorList.push(error);
  161. }
  162. }
  163. return errorList;
  164. }
  165. // 导出
  166. async export(headList, filter) {
  167. // 查询位置
  168. let skip = 0;
  169. // 一次处理多少条数据
  170. const limit = 500;
  171. const total = await this.model.count();
  172. // 循环次数
  173. const times = _.ceil(_.divide(total, limit));
  174. const nowDate = new Date().getTime();
  175. // 文件 名称 及 路径
  176. const filename = `个人用户导出-${nowDate}.xlsx`;
  177. if (!fs.existsSync(this.root_path)) {
  178. // 如果不存在文件夹,就创建
  179. this.mkdir(this.root_path);
  180. }
  181. const excel_path = `${sep}excel${sep}`;
  182. const path = `${this.root_path}${excel_path}`;
  183. if (!fs.existsSync(path)) {
  184. // 如果不存在文件夹,就创建
  185. this.mkdir(path);
  186. }
  187. const workbook = new Excel.Workbook();
  188. const sheet = workbook.addWorksheet('sheet');
  189. const eMeta: any = headList;
  190. const needList: any = eMeta.map(i => i.key);
  191. for (let i = 1; i <= times; i++) {
  192. const data = await this.model
  193. .find(filter, '+password')
  194. .skip(skip)
  195. .limit(limit);
  196. const list = [];
  197. for (const val of data) {
  198. const info: any = {};
  199. for (const i of needList) {
  200. if (i === 'password') info[i] = _.get(val[i], 'secret');
  201. info[i] = val[i];
  202. }
  203. if (info.password) info.password = info.password.secret;
  204. list.push(info);
  205. }
  206. sheet.columns = eMeta;
  207. sheet.addRows(list);
  208. skip += limit;
  209. }
  210. // 生成excel
  211. const filepath = `${path}${filename}`;
  212. await workbook.xlsx.writeFile(filepath);
  213. return `/files/excel/${filename}`;
  214. }
  215. // 创建文件夹
  216. mkdir(dirname) {
  217. if (fs.existsSync(dirname)) {
  218. return true;
  219. }
  220. if (this.mkdir(Path.dirname(dirname))) {
  221. fs.mkdirSync(dirname);
  222. return true;
  223. }
  224. }
  225. exportMeta(exportMeta) {
  226. const arr = [];
  227. if (exportMeta && exportMeta.length > 0) {
  228. for (const val of exportMeta) {
  229. const info: any = {};
  230. if (val.model === 'password') {
  231. info.header = val.label;
  232. info.key = val.model;
  233. info.type = '1';
  234. info.width = 30;
  235. info.style = {
  236. alignment: {
  237. wrapText: true,
  238. vertical: 'middle',
  239. horizontal: 'center',
  240. },
  241. };
  242. } else {
  243. info.header = val.label;
  244. info.key = val.model;
  245. info.width = 30;
  246. info.style = {
  247. alignment: {
  248. wrapText: true,
  249. vertical: 'middle',
  250. horizontal: 'center',
  251. },
  252. };
  253. }
  254. arr.push(info);
  255. }
  256. } else {
  257. throw new ServiceError(
  258. '未找到下载参数',
  259. FrameworkErrorEnum.NOT_FOUND_DATA
  260. );
  261. }
  262. return arr;
  263. }
  264. }