personal.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const { ObjectId } = require('mongoose').Types;
  5. const _ = require('lodash');
  6. const jwt = require('jsonwebtoken');
  7. const assert = require('assert');
  8. const Excel = require('exceljs');
  9. // 个人用户
  10. class PersonalService extends CrudService {
  11. constructor(ctx) {
  12. super(ctx, 'personal');
  13. this.redis = this.app.redis;
  14. this.model = this.ctx.model.Personal;
  15. }
  16. /**
  17. * 创建用户
  18. * @param {Object} params 用户信息
  19. */
  20. async create({ password, ...data }) {
  21. data.password = { secret: password };
  22. const { phone } = data;
  23. // 检查手机号
  24. const num = await this.model.count({ phone, isdel: '0' });
  25. if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '已有个人用户使用该手机号');
  26. return await this.model.create(data);
  27. }
  28. /**
  29. * 修改密码
  30. * @param {Object} {id,password} 用户id和密码
  31. */
  32. async password({ id, password }) {
  33. const object = await this.model.findById(id);
  34. if (!object) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的信息');
  35. object.password = { secret: password };
  36. await object.save();
  37. }
  38. /**
  39. * 登陆
  40. * @param {Object} params 登陆信息
  41. * @property phone 手机号
  42. * @property password 密码
  43. */
  44. async login({ phone, password }) {
  45. const object = await this.model.findOne({ phone, isdel: '0' }, '+password');
  46. if (!object) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的信息');
  47. const { password: op, status } = object;
  48. const { secret } = op;
  49. if (status !== '1') throw new BusinessError(ErrorCode.ACCESS_DENIED, '拒绝访问!');
  50. if (secret !== password) throw new BusinessError(ErrorCode.BAD_PASSWORD, '密码错误');
  51. const data = _.omit(JSON.parse(JSON.stringify(object)), ['meta', 'password', '__v']);
  52. const { secret: secrets } = this.config.jwt;
  53. const token = jwt.sign(data, secrets);
  54. // 记录登陆
  55. // let number = await this.redis.get('login_number') || 0;
  56. // number++;
  57. // await this.redis.set('login_number', number);
  58. return token;
  59. }
  60. async delete({ id }) {
  61. const object = await this.model.findById(id);
  62. if (!object) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的信息');
  63. object.isdel = '1';
  64. await object.save();
  65. }
  66. /**
  67. * 个人升变专家
  68. * @param {Object} body 升变数据
  69. * 升级的时候要把所属的信息(产品,需求等)换到升级后的数据上,一种数据迁移
  70. */
  71. async upgrade({ id, ...data }) {
  72. assert(id, '缺少个人用户ID');
  73. const user = await this.model.findOne({ _id: ObjectId(id) }, '+password');
  74. if (!user) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到用户的信息');
  75. data = _.omit(data, ['meta', '__v']);
  76. data.user_id = id;
  77. // 创建专家
  78. const is_expert = await this.ctx.model.Expert.count({ user_id: ObjectId(id) });
  79. if (is_expert > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '已升级为专家,无需再次升级');
  80. await this.ctx.model.Expert.create(data);
  81. user.is_expert = true;
  82. await user.save();
  83. }
  84. async import({ uri }) {
  85. assert(uri, '未获取到文件地址');
  86. let domain = 'http://127.0.0.1';
  87. const file = await this.ctx.curl(`${domain}${uri}`);
  88. if (!(file && file.data)) {
  89. throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定文件');
  90. }
  91. const workbook = new Excel.Workbook();
  92. await workbook.xlsx.load(file.data);
  93. const sheet = workbook.getWorksheet(1);
  94. let meta = this.importMeta();
  95. // 根据excel,将列序号加入meta中
  96. const head = _.get(sheet.getRow(1), 'values', []);
  97. for (let i = 0; i < head.length; i++) {
  98. const e = head[i];
  99. if (!e) continue;
  100. const r = meta.find((f) => f.column === e);
  101. if (r) r.index = i;
  102. }
  103. // 过滤出列表中不必要且不存在的字段
  104. meta = meta.filter((f) => f.required || f.index);
  105. const errorList = [];
  106. const dataList = [];
  107. sheet.eachRow(async (row, index) => {
  108. if (index !== 1) {
  109. const values = row.values;
  110. const obj = {};
  111. for (const m of meta) {
  112. const { required, key, index, method } = m;
  113. const value = values[index];
  114. if (required && !value) {
  115. // 必填且没值的情况
  116. errorList.push({ message: `第${index}行数据,缺少必填项;` });
  117. continue;
  118. }
  119. if (_.isFunction(method)) obj[key] = method(value);
  120. else obj[key] = value;
  121. }
  122. dataList.push(obj);
  123. }
  124. });
  125. if (errorList.length > 0) return errorList;
  126. for (const i of dataList) {
  127. try {
  128. await this.create(i);
  129. } catch (error) {
  130. errorList.push(error);
  131. }
  132. }
  133. return errorList;
  134. }
  135. importMeta() {
  136. return [
  137. { required: true, column: '用户名', key: 'name' },
  138. { required: true, column: '手机号', key: 'phone' },
  139. { required: true, column: '登录密码', key: 'password' },
  140. { required: true, column: '邀请码', key: 'code' },
  141. { required: true, column: '身份证号', key: 'card' },
  142. { column: '电子邮箱', key: 'email' },
  143. { column: '联系地址', key: 'addr' },
  144. { column: '办公电话', key: 'office_phone' },
  145. { column: '所属辖区', key: 'juris' },
  146. { column: '院校', key: 'school' },
  147. { column: '专业', key: 'major' },
  148. { column: '职务职称', key: 'zwzc' },
  149. { column: '审核状态', key: 'status' },
  150. ];
  151. }
  152. }
  153. module.exports = PersonalService;