123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- '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 moment = require('moment');
- // 客服相关
- class CustomerService extends CrudService {
- constructor(ctx) {
- super(ctx, 'customer');
- this.mq = this.ctx.mq;
- this.status = this.ctx.model.Status;
- this.record = this.ctx.model.Record;
- this.chatRecord = this.ctx.model.CustomerChat;
- // 1分钟检查1次
- this.time = 1;
- this.unit = 'm';
- }
- /**
- * 发送消息
- * @param {Object} body 参数
- * @property _tenant 项目
- * @property client_id 客户id
- * @property client_name 客户名
- * @property customer_id 客服id
- * @property customer_name 客服名
- * @property sender_id 发送人id
- * @property sender_name 发送人
- * @property content 内容
- */
- async chat(body) {
- const { _tenant, client_id, customer_id } = body;
- assert(_tenant, '缺少项目标识');
- assert(client_id, '缺少客户信息');
- assert(customer_id, '缺少客服信息');
- if (!this.mq) throw new BusinessError(ErrorCode.SERVICE_FAULT, 'mq配置错误');
- body.send_time = moment().format('YYYY-MM-DD HH:mm:ss');
- // 向项目存这条对话数据,再mq执行
- await this.chatRecord.create(body);
- // await this.ctx.service.util.httpUtil.$post('/customerChat', 'hnhmain', body);
- const exchange = _tenant;
- const routeKey = `customer.${client_id}.${customer_id}`;
- const mqBody = JSON.stringify(body);
- const param = { durable: true };
- await this.mq.topic(exchange, routeKey, mqBody, param);
- }
- /**
- * 客服获取正在服务的客户列表
- * @param {Object} query 参数
- */
- async getRecord(query) {
- const { _tenant, customer_id } = query;
- assert(_tenant, '缺少项目标识');
- assert(customer_id, '缺少客服信息');
- const list = await this.record.find(query);
- return list;
- }
- /**
- * 客服登陆/续时,此函数不处理工作状态,只处理时间失效与否
- * @param {Object} query 参数
- */
- async customerLog(query) {
- const { _tenant, customer_id } = query;
- assert(_tenant, '缺少项目标识');
- assert(customer_id, '缺少客服信息');
- let customer = await this.status.findOne({ _tenant, customer_id });
- if (customer) {
- // 该客服已经上线
- customer.logout_time = this.addTime();
- await customer.save();
- } else {
- // 没上线
- const obj = { ...query, status: '0', logout_time: this.addTime() };
- customer = await this.status.create(obj);
- }
- return customer;
- }
- /**
- * 客户咨询,查找指定项目的空闲客服,如果没有,那就找到所有客服,
- * 并且找其同时接待最少的客服,让他接待
- * @param {Object} query 参数
- */
- async clientApply(query) {
- const { _tenant, client_id, client_name } = query;
- assert(_tenant, '缺少项目标识');
- assert(client_id, '缺少客户信息');
- const freeList = await this.status.find({ _tenant, status: '0' });
- let customer;
- if (freeList.length > 0) {
- customer = _.head(freeList);
- // 修改状态,加次时间
- customer.status = '1';
- customer.logout_time = this.addTime();
- await customer.save();
- } else {
- // 没有闲的了,那就找不闲的
- let list = await this.status.find({ _tenant });
- if (list.length > 0) {
- list = JSON.parse(JSON.stringify(list));
- for (const i of list) {
- const { customer_id } = i;
- const num = await this.record.count({ customer_id, _tenant });
- i.num = num;
- }
- list = _.orderBy(list, [ 'num' ], [ 'asc' ]);
- customer = _.head(list);
- customer.status = '1';
- customer.logout_time = this.addTime();
- await this.customerLog({ _tenant, customer_id: customer.customer_id });
- } else return '当前没有客服在线';
- }
- // 添加记录
- const obj = { customer_id: customer.customer_id, customer_name: customer.customer_name, _tenant, client_id, client_name };
- let record = await this.record.findOne(obj);
- if (record) {
- record.out_time = this.addTime();
- await record.save();
- } else {
- obj.out_time = this.addTime();
- record = await this.record.create(obj);
- }
- if (this.mq) {
- const exchange = _tenant;
- const routeKey = `customer.${customer.customer_id}`;
- const mqBody = 'research';
- const param = { durable: true };
- await this.mq.topic(exchange, routeKey, mqBody, param);
- }
- return record;
- }
- /**
- * 客户续时
- * @param {Object} query 参数
- */
- async clientContinue(query) {
- const { _tenant, client_id, customer_id } = query;
- assert(_tenant, '缺少项目标识');
- assert(client_id, '缺少客户信息');
- assert(customer_id, '缺少客服信息');
- const record = await this.record.findOne({ _tenant, client_id, customer_id });
- if (!record) return '服务已经结束';
- record.out_time = this.addTime();
- const r = await record.save();
- if (r) {
- // 同时给客服续航
- await this.customerLog({ _tenant, customer_id });
- }
- return 'ok';
- }
- // 结束服务
- async serverEnd(query) {
- const { _tenant, client_id, customer_id } = query;
- assert(_tenant, '缺少项目标识');
- assert(client_id, '缺少客户信息');
- assert(customer_id, '缺少客服信息');
- await this.record.deleteOne({ _tenant, client_id, customer_id });
- this.checkStatus();
- return 'ok';
- }
- // 查询并修改客服状态
- async checkStatus() {
- const list = await this.status.find();
- for (const i of list) {
- const num = await this.record.count({ customer_id: i._id });
- if (num <= 0) {
- i.status = '0';
- i.save();
- }
- }
- }
- // 定时清理
- async clear() {
- // 所有状态和工作记录,对比失效时间,过了就删了
- console.log('in function:clear');
- await this.status.deleteMany({ logout_time: { $lte: moment().format('YYYY-MM-DD HH:mm:ss') } });
- // await this.record.deleteMany({ out_time: { $lte: moment().format('YYYY-MM-DD HH:mm:ss') } });
- }
- // 续
- addTime() {
- const t = moment().add(this.time, this.unit).format('YYYY-MM-DD HH:mm:ss');
- return t;
- }
- }
- module.exports = CustomerService;
|