lrf402788946 4 anni fa
parent
commit
e1ea42ec90

+ 60 - 0
app/controller/.achieve_expert.js

@@ -0,0 +1,60 @@
+module.exports = {
+  create: {
+    requestBody: [
+      "!expert_user_id",
+      "expert_name",
+      "!apply_id",
+      "phone",
+      "password",
+    ],
+  },
+  destroy: {
+    params: ["!id"],
+    service: "delete",
+  },
+  update: {
+    params: ["!id"],
+    requestBody: [
+      "expert_user_id",
+      "expert_name",
+      "phone",
+      "apply_id",
+      "password",
+      "status",
+      "verify",
+    ],
+  },
+  show: {
+    parameters: {
+      params: ["!id"],
+    },
+    service: "fetch",
+  },
+  index: {
+    parameters: {
+      query: {
+        phone: "phone",
+        expert_name: "expert_name",
+        expert_user_id: "expert_user_id",
+        apply_id: "apply_id",
+        status: "status",
+        "create_time@start": "create_time@start",
+        "create_time@end": "create_time@end",
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: "query",
+    options: {
+      query: ["skip", "limit"],
+      sort: ["meta.createdAt"],
+      desc: true,
+      count: true,
+    },
+  },
+  login: {
+    requestBody: ["!phone", "!password"],
+    service: "login",
+  },
+};

+ 52 - 0
app/controller/.achieve_verify_record.js

@@ -0,0 +1,52 @@
+module.exports = {
+  create: {
+    requestBody: [
+      "!apply_id",
+      "desc",
+      "status",
+      "!verify_id",
+      "verify_phone",
+      "verify",
+    ],
+  },
+  destroy: {
+    params: ["!id"],
+    service: "delete",
+  },
+  update: {
+    params: ["!id"],
+    requestBody: [
+      "apply_id",
+      "desc",
+      "status",
+      "verify_id",
+      "verify_phone",
+      "verify",
+    ],
+  },
+  show: {
+    parameters: {
+      params: ["!id"],
+    },
+    service: "fetch",
+  },
+  index: {
+    parameters: {
+      query: {
+        apply_id: "apply_id",
+        "create_time@start": "create_time@start",
+        "create_time@end": "create_time@end",
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: "query",
+    options: {
+      query: ["skip", "limit"],
+      sort: ["meta.createdAt"],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 13 - 0
app/controller/achieve_expert.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./.achieve_expert.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+// 专家临时
+class Achieve_expertController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.achieveExpert;
+  }
+}
+module.exports = CrudController(Achieve_expertController, meta);

+ 13 - 0
app/controller/achieve_verify_record.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./.achieve_verify_record.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose/lib/controller');
+
+// 审核记录
+class Achieve_verify_recordController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.achieveVerifyRecord;
+  }
+}
+module.exports = CrudController(Achieve_verify_recordController, meta);

+ 7 - 3
app/model/achieve_apply.js

@@ -2,8 +2,9 @@
 const Schema = require('mongoose').Schema;
 const Schema = require('mongoose').Schema;
 const moment = require('moment');
 const moment = require('moment');
 const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
 const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+const { ObjectId } = require('mongoose').Types;
 // 基本信息
 // 基本信息
-const base = new Schema({
+const basic = new Schema({
   achieve_name: { type: String }, // 成果名称
   achieve_name: { type: String }, // 成果名称
   achieve_type: { type: String }, // 成果类别
   achieve_type: { type: String }, // 成果类别
   achieve_num: { type: String }, // 成果编号
   achieve_num: { type: String }, // 成果编号
@@ -23,7 +24,8 @@ const base = new Schema({
   profit: { type: String }, // 经济效益利润
   profit: { type: String }, // 经济效益利润
   revenue: { type: String }, // 经济效益税收
   revenue: { type: String }, // 经济效益税收
 });
 });
-base.index({ id: 1 });
+basic.index({ id: 1 });
+basic.index({ achieve_num: 1 });
 // 内容简介
 // 内容简介
 const brief = new Schema({
 const brief = new Schema({
   achieve_brief: { type: String }, // 成果简介
   achieve_brief: { type: String }, // 成果简介
@@ -71,7 +73,9 @@ datalist.index({ id: 1 });
 
 
 // 成果评价申请表
 // 成果评价申请表
 const achieve_apply = {
 const achieve_apply = {
-  basic: { type: base },
+  user_id: { type: ObjectId }, // 关联用户
+  status: { type: String, default: '0' }, // 状态
+  basic: { type: basic },
   brief: { type: brief },
   brief: { type: brief },
   research: { type: [ research ] },
   research: { type: [ research ] },
   datalist: { type: datalist },
   datalist: { type: datalist },

+ 33 - 0
app/model/achieve_expert.js

@@ -0,0 +1,33 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const moment = require('moment');
+const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+const { ObjectId } = require('mongoose').Types;
+const { Secret } = require('naf-framework-mongoose/lib/model/schema');
+// 专家临时账号表
+// 使用手机号密码登录
+// 约束条件,不能出现一个专家同时审2个项目,否则登录可能混乱
+const achieve_expert = {
+  expert_user_id: { type: ObjectId }, // 专家的用户id
+  expert_name: { type: String }, // 专家姓名
+  phone: { type: String }, // 电话
+  apply_id: { type: ObjectId }, // 成果申请id
+  password: { type: Secret, select: false },
+  verify: { type: Object }, // 评审详情:分数:score;意见:content
+  status: { type: String, default: '0' }, // 0=>使用中;-1=>禁用中
+  remark: { type: String, maxLength: 200 },
+  create_time: { type: String, default: moment().format('YYYY-MM-DD HH:mm:ss') },
+};
+const schema = new Schema(achieve_expert, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ expert_user_id: 1 });
+schema.index({ expert_name: 1 });
+schema.index({ phone: 1 });
+schema.index({ apply_id: 1 });
+schema.index({ status: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('Achieve_expert', schema, 'achieve_expert');
+};

+ 26 - 0
app/model/achieve_verify_record.js

@@ -0,0 +1,26 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const moment = require('moment');
+const metaPlugin = require('naf-framework-mongoose/lib/model/meta-plugin');
+const { ObjectId } = require('mongoose').Types;
+// 审核记录表
+const achieve_verify_record = {
+  apply_id: { type: ObjectId }, // 成果申请数据id
+  desc: { type: String }, // 本次审核的意见
+  status: { type: String }, // 本次审核的结果
+  verify_id: { type: ObjectId }, // 本次审核人
+  verify_phone: { type: String }, // 本次审核人的联系电话
+  verify: { type: String }, // 本次审核人
+  step: { type: String }, // 初审=>评分
+  remark: { type: String, maxLength: 200 },
+  create_time: { type: String, default: moment().format('YYYY-MM-DD HH:mm:ss') },
+};
+const schema = new Schema(achieve_verify_record, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ apply_id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('Achieve_verify_record', schema, 'achieve_verify_record');
+};

+ 2 - 0
app/router.js

@@ -7,4 +7,6 @@ module.exports = app => {
   const { router, controller } = app;
   const { router, controller } = app;
   router.get('/', controller.home.index);
   router.get('/', controller.home.index);
   require('./router/achieve_apply')(app); // 成果评价申请
   require('./router/achieve_apply')(app); // 成果评价申请
+  require('./router/achieve_verify_record')(app); // 成果评价申请审核记录
+  require('./router/achieve_expert')(app); // 专家临时
 };
 };

+ 12 - 0
app/router/achieve_expert.js

@@ -0,0 +1,12 @@
+'use strict';
+
+
+module.exports = app => {
+  const { router, controller } = app;
+  const profix = '/api/achieve/';
+  const vision = 'v0';
+  const target = 'achieveExpert';
+  router.post(target, `${profix}${vision}/${target}/login`, controller[target].login);
+  router.resources(target, `${profix}${vision}/${target}`, controller[target]); // index、create、show、destroy
+  router.post(target, `${profix}${vision}/${target}/update/:id`, controller[target].update);
+};

+ 11 - 0
app/router/achieve_verify_record.js

@@ -0,0 +1,11 @@
+'use strict';
+
+
+module.exports = app => {
+  const { router, controller } = app;
+  const profix = '/api/achieve/';
+  const vision = 'v0';
+  const target = 'achieveVerifyRecord';
+  router.resources(target, `${profix}${vision}/${target}`, controller[target]); // index、create、show、destroy
+  router.post(target, `${profix}${vision}/${target}/update/:id`, controller[target].update);
+};

+ 22 - 0
app/service/achieve_apply.js

@@ -10,6 +10,28 @@ class Achieve_applyService extends CrudService {
   constructor(ctx) {
   constructor(ctx) {
     super(ctx, 'achieve_apply');
     super(ctx, 'achieve_apply');
     this.model = this.ctx.model.AchieveApply;
     this.model = this.ctx.model.AchieveApply;
+    this.httpUtil = this.ctx.service.util.httpUtil;
+    this.util = this.ctx.service.util.util;
+  }
+
+  async create(body) {
+    // TODO 没有账号需要创建账号
+    const { user_id, basic } = body;
+    let res;
+    if (!user_id) {
+      const { phone, email, contacts, addr } = basic;
+      const personalData = { name: contacts, phone, email, addr };
+      personalData.password = '123456';
+      personalData.code = 'CGPJXTYW';
+      personalData.status = '1';
+      const user = await this.httpUtil.cpost('/users/personal', 'live', personalData);
+      if (!user) throw new BusinessError(ErrorCode.SERVICE_FAULT, '用户创建失败!');
+      body.user_id = user._id;
+      res = await this.model.create(body);
+    } else {
+      res = await this.model.create(body);
+    }
+    return res;
   }
   }
 
 
   async getOne(query) {
   async getOne(query) {

+ 53 - 0
app/service/achieve_expert.js

@@ -0,0 +1,53 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+const jwt = require('jsonwebtoken');
+
+// 临时专家
+class Achieve_expertService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'achieve_expert');
+    this.model = this.ctx.model.AchieveExpert;
+  }
+
+  async create(data) {
+    const { password } = data;
+    data.password = { secret: password };
+    const res = await this.model.create(data);
+    return res;
+  }
+
+  async update({ id }, data) {
+    const { password, verify } = data;
+    const older = await this.model.findById(id);
+    if (!older) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到专家信息');
+    // 此处是检验专家是否可以进行修改
+    const { status } = older;
+    if (status === '1') throw new BusinessError(ErrorCode.SERVICE_FAULT, '您的工作已完成,若有问题请联系平台管理员!');
+    if (password) { data.password = { secret: password }; }
+    // 如果修改时有评审内容,则将该账号毙掉
+    if (verify && verify.score) data.status = '1';
+    await this.model.findByIdAndUpdate(id, data);
+    return await this.model.findById(id);
+  }
+
+  /**
+   * 临时专家账号登录
+   * @param {Object} params 手机号,密码
+   */
+  async login({ phone, password }) {
+    const expert = await this.model.findOne({ phone, status: '0' }, '+password');
+    if (!expert) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '您不存在未完成的工作,无需登录');
+    const { password: op } = expert;
+    const { secret } = op;
+    if (secret !== password) throw new BusinessError(ErrorCode.BAD_PASSWORD, '密码错误');
+    const data = _.omit(JSON.parse(JSON.stringify(expert)), [ 'meta', 'password', '__v', 'verify' ]);
+    const { secret: secrets } = this.config.jwt;
+    const token = jwt.sign(data, secrets);
+    return token;
+  }
+}
+
+module.exports = Achieve_expertService;

+ 31 - 0
app/service/achieve_verify_record.js

@@ -0,0 +1,31 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 审核记录
+class Achieve_verify_recordService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'achieve_verify_record');
+    this.model = this.ctx.model.AchieveVerifyRecord;
+    this.apply = this.ctx.model.AchieveApply;
+  }
+
+  /**
+   * 添加审核记录
+   * @param {Object} data 审核数据
+   */
+  async create(data) {
+    const { status, apply_id } = data;
+    const res = await this.apply.updateOne({ _id: apply_id }, { status });
+    if (res.ok && _.isNumber(res.ok) && res.ok > 0) {
+      const record = await this.model.create(data);
+      return record;
+    }
+    throw new BusinessError(ErrorCode.SERVICE_FAULT, '审核失败');
+
+  }
+}
+
+module.exports = Achieve_verify_recordService;

+ 96 - 0
app/service/util/http-util.js

@@ -0,0 +1,96 @@
+'use strict';
+const { AxiosService } = require('naf-framework-mongoose/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { isNullOrUndefined } = require('naf-core').Util;
+const _ = require('lodash');
+
+//
+class HttpUtilService extends AxiosService {
+  constructor(ctx) {
+    super(ctx, {}, {});
+  }
+
+
+  // 替换uri中的参数变量
+  merge(uri, query = {}) {
+    const keys = Object.keys(query);
+    const arr = [];
+    for (const k of keys) {
+      arr.push(`${k}=${query[k]}`);
+    }
+    if (arr.length > 0) {
+      uri = `${uri}?${arr.join('&')}`;
+    }
+    return uri;
+  }
+
+  /**
+   * curl-get请求
+   * @param {String} uri 接口地址
+   * @param {String} project config中的项目key
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async cget(uri, project, query, options) {
+    return this.toRequest(uri, project, null, query, options);
+  }
+
+  /**
+   * curl-post请求
+   * @param {String} uri 接口地址
+   * @param {String} project config中的项目key
+   * @param {Object} data post的body
+   * @param {Object} query 地址栏参数
+   * @param {Object} options 额外参数
+   */
+  async cpost(uri, project, data = {}, query, options) {
+    return this.toRequest(uri, project, data, query, options);
+  }
+
+  async toRequest(uri, project, data, query, options) {
+    const prefix = _.get(this.ctx.app.config.project, project);
+    if (!prefix) {
+      throw new BusinessError(
+        ErrorCode.SERVICE_FAULT,
+        `未设置用户权限项目的关联:config.project.${project} is undefined`
+      );
+    }
+    query = _.pickBy(
+      query,
+      val => val !== '' && val !== 'undefined' && val !== 'null'
+    );
+    if (!uri) console.error('uri不能为空');
+    if (_.isObject(query) && _.isObject(options)) {
+      const params = query.params ? query.params : query;
+      options = { ...options, params };
+    } else if (_.isObject(query) && !query.params) {
+      options = { params: query };
+    } else if (_.isObject(query) && query.params) {
+      options = query;
+    }
+    // 是否多租户模式,需要改变headers
+    const headers = { 'content-type': 'application/json' };
+    const url = this.merge(`${prefix}${uri}`, options.params);
+    let res = await this.ctx.curl(url, {
+      method: isNullOrUndefined(data) ? 'get' : 'post',
+      url,
+      data,
+      dataType: 'json',
+      headers,
+      ...options,
+    });
+    if (res.status === 200) {
+      res = res.data || {};
+      const { errcode, errmsg, details } = res;
+      if (errcode) {
+        console.warn(`[${uri}] fail: ${errcode}-${errmsg} ${details}`);
+        return { errcode, errmsg };
+      }
+      return res.data;
+    }
+    const { status } = res;
+    console.warn(`[${uri}] fail: ${status}-${res.data.message} `);
+  }
+}
+
+module.exports = HttpUtilService;

+ 66 - 0
app/service/util/rabbitMq.js

@@ -0,0 +1,66 @@
+'use strict';
+
+const Service = require('egg').Service;
+
+class RabbitmqService extends Service {
+
+  constructor(ctx) {
+    super(ctx);
+    this.exType = 'topic';
+    this.durable = true;
+  }
+
+  // 接收消息
+  async receiveQueueMsg(ex) {
+    this.ctx.logger.info('调用mq的' + ex);
+    const self = this;
+    const { mq } = self.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      await ch.assertExchange(ex, 'topic', { durable: true });
+      const q = await ch.assertQueue('', { exclusive: true });
+      await ch.bindQueue(q.queue, ex, '*');
+      await ch.consume(q.queue, msg => this.logMessage(msg, this), { noAck: true });
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+
+  async logMessage(msg) {
+    const result = msg.content.toString();
+    const headers = msg.properties.headers;
+  }
+
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      const queue = 'mission/market';
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    let data = bdata.content.toString();
+    try {
+      data = JSON.parse(data);
+    } catch (error) {
+      this.ctx.logger.error('数据不是object');
+    }
+    const { service, method, ...others } = data;
+    if (service && method) this.ctx.service[service][method](others);
+
+  }
+}
+
+module.exports = RabbitmqService;

+ 72 - 0
app/service/util/util.js

@@ -0,0 +1,72 @@
+'use strict';
+const _ = require('lodash');
+const moment = require('moment');
+const { CrudService } = require('naf-framework-mongoose/lib/service');
+const { ObjectId } = require('mongoose').Types;
+const fs = require('fs');
+class UtilService extends CrudService {
+  constructor(ctx) {
+    super(ctx);
+    this.mq = this.ctx.mq;
+  }
+  async utilMethod(query, body) {
+    console.log('in function: util method');
+  }
+
+  /**
+   * 整理参数
+   * @param {Object} query 参数
+   */
+  dealQuery(query) {
+    return this.turnFilter(this.turnDateRangeQuery(query));
+  }
+
+  /**
+   * 将查询条件中模糊查询的标识转换成对应object
+   * @param {Object} filter 查询条件
+   */
+  turnFilter(filter) {
+    const str = /^%\S*%$/;
+    const keys = Object.keys(filter);
+    for (const key of keys) {
+      const res = key.match(str);
+      if (res) {
+        const newKey = key.slice(1, key.length - 1);
+        filter[newKey] = new RegExp(filter[key]);
+        delete filter[key];
+      }
+    }
+    return filter;
+  }
+  /**
+   * 将时间转换成对应查询Object
+   * @param {Object} filter 查询条件
+   */
+  turnDateRangeQuery(filter) {
+    const keys = Object.keys(filter);
+    for (const k of keys) {
+      if (k.includes('@')) {
+        const karr = k.split('@');
+        //  因为是针对处理范围日期,所以必须只有,开始时间和结束时间
+        if (karr.length === 2) {
+          const type = karr[1];
+          if (type === 'start') {
+            filter[karr[0]] = {
+              ..._.get(filter, karr[0], {}),
+              $gte: filter[k],
+            };
+          } else {
+            filter[karr[0]] = {
+              ..._.get(filter, karr[0], {}),
+              $lte: filter[k],
+            };
+          }
+          delete filter[k];
+        }
+      }
+    }
+    return filter;
+  }
+
+}
+module.exports = UtilService;

+ 13 - 0
config/config.default.js

@@ -5,6 +5,7 @@
 /**
 /**
  * @param {Egg.EggAppInfo} appInfo app info
  * @param {Egg.EggAppInfo} appInfo app info
  */
  */
+const { jwt } = require('./config.secret');
 module.exports = appInfo => {
 module.exports = appInfo => {
   /**
   /**
    * built-in config
    * built-in config
@@ -60,6 +61,18 @@ module.exports = appInfo => {
     },
     },
   };
   };
 
 
+  config.project = {
+    mission: 'http://127.0.0.1:4001',
+    live: 'http://127.0.0.1:9101/api/live/v0',
+    site: 'http://127.0.0.1:9102',
+  };
+
+  config.jwt = {
+    ...jwt,
+    expiresIn: '1d',
+    issuer: 'test',
+  };
+
   return {
   return {
     ...config,
     ...config,
     ...userConfig,
     ...userConfig,

+ 7 - 0
config/config.secret.js

@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = {
+  jwt: {
+    secret: 'Ziyouyanfa!@#',
+  },
+};