'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;