@jiangyifen
2017-08-08T10:24:54.000000Z
字数 20719
阅读 770
全渠道
组织架构权限
客户管理
系统配置(自定义表,系统选项,过滤器,渠道【邮箱服务器,呼叫中心,短信,微信】)
呼叫中心(外呼任务、问卷、弹屏)
工单()
知识库
公告
即时通讯(微信公众号、微信小程序、网页、APP)
即时通讯机器人
快速搜索框,通过客户id或电话号码打开【具体客户addTab】
【签入/签出】
直接调用rsmw-java.bind() unbind()
【绑定成功】、【解绑】后需要【开启】、【停止】每秒一次的ajax请求
【拨号input】
【拨号12宫格】-- button onClick时,把button对应的值append到【拨号input】中去
【呼叫/挂断】,【hold/unhold】,【转接】--点击【呼叫/挂断】,【hold/unhold】调用rsmw-java里相应的函数。点击【转接】弹出联动的select2组件,选择需要转接的目标对象类型(默认选中sipphone)和对象分机号
【置忙/置闲】--调用rsmw-java里相应的函数
技能组:数据
技能组:数据
……
技能组:数据
微信客服状态显示和操作:
参考其他全渠道微信客服系统
待嵌入软电话后实现(二期)
SIP.js
头像!!
勾选列,保存在html5 localstorage
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Company | id | 主键 | bigint | 20 | PK | 是 |
Company | name | 公司名称 | varchar | 64 | 唯一 | 是 |
Company | description | 备注 | varchar | 512 | 是 | |
Company | domain | 域名 | varchar | 512 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Customer | id | 主键 | bigint | 20 | PK | 是 |
Customer | phoneNumber | 电话 | varchar | 64 | 唯一 | 是 |
Customer | 邮箱 | varchar | 64 | 唯一 | ||
Customer | name | 姓名 | varchar | 64 | 是 | |
Customer | sex | 性别 | varchar | 16 | 是 | |
Customer | birthday | 生日 | datetime | 是 | ||
Customer | countryId | 国籍 | bigint | 20 | 是 | |
Customer | provinceId | 省份 | bigint | 20 | 是 | |
Customer | cityId | 城市 | bigint | 20 | 是 | |
Customer | address | 地址 | varchar | 256 | ||
Customer | creatorId | 创建者 | bigint | 20 | 是 | 是 |
Customer | createDate | 创建日期 | datetime | 是 | 是 | |
Customer | ownerId | 拥有者 | bigint | 20 | 是 | |
Customer | typeId | 类型 | bigint | 20 | 是 | 是 |
Customer | sourceId | 来源 | bigint | 20 | 是 | 是 |
Customer | companyId | 公司 | bigint | 20 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerType | id | 主键 | bigint | 20 | PK | 是 |
CustomerType | name | 客户类型名称 | varchar | 64 | 唯一 | 是 |
CustomerType | canDelete | 是否允许删除 | tinyint | 1 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerSource | id | 主键 | bigint | 20 | PK | 是 |
CustomerSource | name | 客户来源名称 | varchar | 64 | 唯一 | 是 |
CustomerSource | canDelete | 是否允许删除 | tinyint | 1 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Country | id | 主键 | bigint | 20 | PK | 是 |
Country | name | 国家名称 | varchar | 64 | 唯一 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Province | id | 主键 | bigint | 20 | PK | 是 |
Province | name | 省份名称 | varchar | 64 | 唯一 | 是 |
Province | countryId | 所属国家 | bigint | 20 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
City | id | 主键 | bigint | 20 | PK | 是 |
City | name | 城市名称 | varchar | 64 | 唯一 | 是 |
City | provinceId | 所属省份 | bigint | 20 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerBatch | id | 主键 | bigint | 20 | PK | 是 |
CustomerBatch | name | 批次名 | varchar | 64 | 是 | 是 |
CustomerBatch | description | 描述 | varchar | 64 | ||
CustomerBatch | creatorId | 创建者 | bigint | 20 | 是 | 是 |
CustomerBatch | createDate | 创建日期 | datetime | 是 | 是 | |
CustomerBatch | ownerId | 拥有者 | bigint | 20 | 是 | 是 |
CustomerBatch | state | 状态 | int | 11 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerCustomerBatchLink | id | 主键 | bigint | 20 | PK | 是 |
CustomerCustomerBatchLink | customerId | 客户id | bigint | 20 | 联合 | 是 |
CustomerCustomerBatchLink | customerBatchId | 客户批次id | bigint | 20 | 联合 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerContactHistory | id | 主键 | bigint | 20 | PK | 是 |
CustomerContactHistory | customerId | 客户id | bigint | 20 | 是 | 是 |
CustomerContactHistory | creatorId | 创建者 | bigint | 20 | 是 | |
CustomerContactHistory | createDate | 创建日期 | datetime | 是 | 是 | |
CustomerContactHistory | type | 类型 | varchar | 64 | 是 | 是 |
CustomerContactHistory | content | 内容(相关对象,如cdr.uuid) | varchar | 512 | ||
CustomerContactHistory | categoryId1 | 分类1 | bigint | 20 | 是 | |
CustomerContactHistory | categoryId2 | 分类2 | bigint | 20 | 是 | |
CustomerContactHistory | categoryId3 | 分类3 | bigint | 20 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CustomerContactHistoryCategory | id | 主键 | bigint | 20 | PK | 是 |
CustomerContactHistoryCategory | name | 名称 | varchar | 64 | 是 | |
CustomerContactHistoryCategory | parentId | 上级category | bigint | 20 | 是 |
datatable套路
注意:客户和客户批次是多对多。
需要按照批次来查询
权限控制:
mod_customer_listAllCustomer:当有此项权限时,就能查看所有客户(现在就这样);当没有此项权限时,只能查看【owner=自己】的客户
mod_customer_modifyCustomerOwner:当有此项权限时,就能随意修改客户端ownerId字段(现在就这样);当没有此项全显示,只能当{【ownwerId=自己】或【ownerId=空】}时,才能修改ownerId(也就是说,能把自己的customer给别人,不能把别人的抢过来给自己),若不满足{【ownwerId=自己】或【ownerId=空】}的条件,首先界面上owner的select2要禁用,其次后台相关的set函数不执行
查询,勾选,另存为,选择另存到“新批次”或另存到“现有批次”(操作通导入)
注意:不用起线程后台操作,controller同步调用。
页面ajax请求CustomerBatchService.getWaitingAndImportingCustomerBatch(),获取最新状态,以便前台显示“转圈”。
导出套路:勾选,导出
【查看所有客户信息】作为一个权限,通过角色勾选。未勾选的,只能查看自己部门范围(归属人是自己部门的)的客户信息。
【暂不需要】
表单:当前客户姓名(label展示),目标客户(select2,ajax加载数据,绝不能一次性全部加载),文字提示:(目标客户查询仅支持姓名和电话;合并后,所有的工单、通话记录、都将被合并到目标客户;当前客户将被删除)
操作:将现有客户所有关联记录的customerId全部update成目标客户customerId(批次,工单,历史记录等表),最后删除当前客户记录
入口:弹屏页面button
datatable套路
openWizard({
showModalInDiv:$("#div_id"),
customerBatchId:1
})
向导:1下载示例--> 2整理数据-->3上传数据(导入到现有批次,新建批次)
全局单线程导入,并注意批量提交(synchronize)
下载示例csv,编码gb2312,注意测试中文乱码问题。表头包含:1)固定表的相关字段;2)所有自定义字段
重复定义:和客户表中的电话号码重复算重复。
导入到现有批次:和现有批次中的的customerId不重复
注意:起线程后台操作,controller直接返回。页面ajax请求CustomerBatchService.getWaitingAndImportingCustomerBatch(),获取最新状态,以便前台显示“转圈”。
勾选,取名,合并(创建合并后的批次,合并,删除原有批次)
a,b,c合并到c:
开始合并时,将abc的状态置为importing
合并后,保留c,删除ab。删除ab前
清空CustomerCustomerBatchLink相关记录
正向:在CustomerCustomerBatchLink内指定的批次范围做比较,把指定批次和其他批次中重叠的customerid【从指定批次中去除】
反向:在CustomerCustomerBatchLink内指定的批次范围做比较,把指定批次和其他批次中重叠的customerid【从其他批次中去除】
实现
public Integer removeDuplicateLink(Long batchId, List batchIdList, Boolean mode);true=正向
1)select customerId,count(*) c from CustomerCustomerBatchLink where batchId in (batchId & batchIdList) group by customerId; idList = select where c>1
2) delete from CustomerCustomerBatchLink where customerId in idList and batchid ==/!= batchId
界面:
datatable最后一列,操作【去重】,点击后弹出modal
1)选择模式:正向,反向,并配合文字说明
2)选择范围:【所有批次】,【指定批次】
3)当选择【指定批次】时,显示左右list
4)确定
datatable套路
删除,需要问用户,原先关联到被删除值的相关记录怎么处理(全库update成其他值后,再行删除)
在弹屏中展现
记录有手工输入的(备注),也有系统自动插入的(通话记录,短信记录)
客户跟进记录类型(枚举值):备注,通话记录,短信记录,
插入时机:
备注(手工填写)
通话记录(收到cdr时插入)
短信记录(发送短信时插入)
客户跟进记录的3个category字段,页面体现为三个联动的select
category管理页面类似部门,有上级关系,自关联表
客户跟进记录管理,主要用于查询和删除
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
PauseReason | id | 主键 | bigint | 20 | PK | 是 |
PauseReason | name | 名称 | varchar | 64 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OutboundTask | id | 主键 | bigint | 20 | PK | 是 |
OutboundTask | name | 外呼任务名 | varchar | 64 | 是 | 是 |
OutboundTask | maxItemCount | 单人任务数上限 | int | 11 | 是 | |
OutboundTask | description | 描述 | varchar | 64 | ||
OutboundTask | creatorId | 创建者 | bigint | 20 | 是 | 是 |
OutboundTask | createDate | 创建日期 | datetime | 是 | 是 | |
OutboundTask | ownerId | 拥有者 | bigint | 20 | 是 | 是 |
OutboundTask | questionnaireId | 问卷 | bigint | 20 | 是 | |
OutboundTask | state | 状态 | int | 11 | 是 | 是 |
OutboundTask | enable | 是否启用 | tinyint | 1 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OutboundTaskItem | id | 主键 | bigint | 20 | PK | 是 |
OutboundTaskItem | outboundTaskId | 外呼任务id | bigint | 20 | 是 | 是 |
OutboundTaskItem | customerId | 客户id | bigint | 20 | 是 | 是 |
OutboundTaskItem | ownerId | 拥有者 | bigint | 20 | 是 | |
OutboundTaskItem | lastCallDate | 最后一次呼叫时间 | datetime | 是 | ||
OutboundTaskItem | lastCallUuid | 最后一次呼叫Uuid | varchar | 64 | 是 | |
OutboundTaskItem | isAnswered | 是否呼通 | tinyint | 1 | 是 | 是 |
OutboundTaskItem | recordUrl | 录音url | varchar | 256 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OutboundTaskUserLink | id | 主键 | bigint | 20 | PK | 是 |
OutboundTaskUserLink | outboundTaskId | 外呼任务id | bigint | 20 | 联合 | 是 |
OutboundTaskUserLink | userId | 用户id | bigint | 20 | 联合 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OutboundTaskCustomerBatchLink | id | 主键 | bigint | 20 | PK | 是 |
OutboundTaskCustomerBatchLink | outboundTaskId | 外呼任务id | bigint | 20 | 联合 | 是 |
OutboundTaskCustomerBatchLink | customerBatchId | 客户批次id | bigint | 20 | 联合 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
GroupCallTask | id | 主键 | bigint | 20 | PK | 是 |
GroupCallTask | name | 群呼任务名 | varchar | 64 | 是 | 是 |
GroupCallTask | extenType | 接听群呼电话的extenType(ivr,queue) | varchar | 64 | 是 | 是 |
GroupCallTask | exten | 接听群呼电话的exten | varchar | 64 | 是 | 是 |
GroupCallTask | isRunning | 是否正在群呼 | tinyint | 1 | 是 | 是 |
GroupCallTask | accessNumber | 群呼用的accessNumber | varchar | 64 | 是 | 是 |
GroupCallTask | gateway | 群呼用的gateway | varchar | 64 | 是 | 是 |
GroupCallTask | type | 群呼任务类型:动态并发dynamic、固定并发static | varchar | 64 | 是 | 是 |
GroupCallTask | rate | 系数或并发数 | double | 64 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
GroupCallTaskItem | id | 主键 | bigint | 20 | PK | 是 |
GroupCallTaskItem | groupCallTaskId | 群呼任务id | bigint | 11 | 是 | |
GroupCallTaskItem | customerId | 客户id | bigint | 20 | 是 | 是 |
GroupCallTaskItem | customerPhoneNumber | 客户电话 | varchar | 64 | 是 | |
GroupCallTaskItem | ownerId | 拥有者 | bigint | 20 | 是 | |
GroupCallTaskItem | lastCallDate | 最后一次呼叫时间 | datetime | 是 | ||
GroupCallTaskItem | lastCallUuid | 最后一次呼叫Uuid | varchar | 64 | 是 | 是 |
GroupCallTaskItem | isAnswered | 是否呼通 | tinyint | 1 | 是 | 是 |
GroupCallTaskItem | recordUrl | 录音url | varchar | 256 | ||
GroupCallTaskItem | ivrKeyPressed | 客户按键 | varchar | 16 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
GroupCallTaskCustomerBatchLink | id | 主键 | bigint | 20 | PK | 是 |
GroupCallTaskCustomerBatchLink | groupCallTaskId | 群呼任务id | bigint | 20 | 联合 | 是 |
GroupCallTaskCustomerBatchLink | customerBatchId | 客户批次id | bigint | 20 | 联合 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Questionnaire | id | 主键 | bigint | 20 | PK | 是 |
Questionnaire | name | 问卷名称 | varchar | 64 | 是 | 是 |
Questionnaire | description | 问卷描述 | varchar | 64 | ||
Questionnaire | creatorId | 创建者 | bigint | 20 | 是 | 是 |
Questionnaire | createDate | 创建日期 | datetime | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
QuestionnaireDetail | id | 主键 | bigint | 20 | PK | 是 |
QuestionnaireDetail | questionnaireId | 问卷id | bigint | 20 | 是 | 是 |
QuestionnaireDetail | sequence | 题目序号 | bigint | 20 | 是 | 是 |
QuestionnaireDetail | title | 题目标题 | varchar | 64 | ||
QuestionnaireDetail | type | 题目类型 | varchar | 64 | 是 | 是 |
QuestionnaireDetail | options | 题目选项(仅针对单选多选,这里可以包含跳转到第几题的id) | varchar | 512 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
QuestionnaireAnswer | id | 主键 | bigint | 20 | PK | 是 |
QuestionnaireAnswer | questionnaireId | 问卷id | bigint | 20 | 是 | 是 |
QuestionnaireAnswer | isComplete | 题目标题 | tinyint | 1 | 是 | 是 |
QuestionnaireAnswer | customerId | 答题者id | bigint | 20 | 是 | 是 |
QuestionnaireAnswer | creatorId | 创建者 | bigint | 20 | 是 | 是 |
QuestionnaireAnswer | createDate | 创建日期 | datetime | 是 | 是 | |
QuestionnaireAnswer | mark | 小结 | varchar | 512 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
QuestionnaireAnswerDetail | id | 主键 | bigint | 20 | PK | 是 |
QuestionnaireAnswerDetail | questionnaireId | 问卷id | bigint | 20 | 是 | 是 |
QuestionnaireAnswerDetail | questionnaireDetailId | 问卷DetailId | bigint | 20 | 是 | 是 |
QuestionnaireAnswerDetail | questionnaireAnswerId | 问卷答案id | bigint | 20 | 是 | 是 |
QuestionnaireAnswerDetail | customerId | 答题者id | bigint | 20 | 是 | 是 |
QuestionnaireAnswerDetail | content | 答案内容 | varchar | 512 | ||
QuestionnaireAnswerDetail | comments | 答案的备注 | varchar | 512 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
RecordScoreCategory | id | 主键 | bigint | 20 | PK | 是 |
RecordScoreCategory | name | 名称 | varchar | 64 | 是 | 是 |
RecordScoreCategory | scroeColumnName | 打分项列名 | varchar | 1024 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
RecordScore_${RecordScoreCategory.id} | id | 主键 | bigint | 20 | PK | 是 |
RecordScore_${RecordScoreCategory.id} | cdrId | cdrId | bigint | 20 | 唯一 | 是 |
RecordScore_${RecordScoreCategory.id} | cdrEndtime | cdr日期 | datetime | 是 | 是 | |
RecordScore_${RecordScoreCategory.id} | recordScoreCategoryId | bigint | 20 | 是 | 是 | |
RecordScore_${RecordScoreCategory.id} | agentId | agentId | bigint | 20 | 是 | 是 |
RecordScore_${RecordScoreCategory.id} | score1 | score1 | int | 11 | ||
RecordScore_${RecordScoreCategory.id} | score2 | score2 | int | 11 | ||
RecordScore_${RecordScoreCategory.id} | scoreX | scoreX | int | 11 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Alarm | id | 主键 | bigint | 20 | PK | 是 |
Alarm | name | 预约名称 | varchar | 64 | 是 | 是 |
Alarm | description | 预约描述 | varchar | 128 | ||
Alarm | alarmTimestamp | 提醒时间 | datetime | 是 | 是 | |
Alarm | customerId | 客户Id | bigint | 20 | 是 | 是 |
Alarm | ownerId | 这是哪个坐席的预约 | bigint | 20 | 是 | 是 |
Alarm | needAlarm | 是否需要提醒 | tinyint | 1 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
CallBackTask | id | 主键 | bigint | 20 | PK | 是 |
CallBackTask | voiceMailRecordId | 留言id | bigint | 20 | 是 | 是 |
CallBackTask | ownerId | 这是哪个坐席的回访任务 | bigint | 20 | 是 | |
CallBackTask | callBackDate | 处理时间 | datetime | 是 | ||
CallBackTask | callUuid | cdr的uuid | varchar | 64 | 是 |
datatable套路
新建、修改向导:1)基本信息:任务名、单个人的条目上限;2)关联人;3)关联客户批次;4)关联问卷(可选)
关联人、关联批次注意数据范围权限
修改:
修改人员:
读出修改前关联的人员,和本次表单提交的人员作对比,得出“增加的人”和“删除的人”
对于“增加的人”:插入link
对于“删除的人”:删除link,回收此人任务
修改客户批次:
读出修改前关联的批次,和本次表单提交的批次作对比,得出“增加的批次”和“删除的批次”
对于“增加的批次”:插入link,生成item
对于“删除的批次”:删除link,删除item
分:选人,选分X条/分至X条
回收:选人,选任务类型(未拨打,已打未通,已打已通)
共多少条任务条目 = 呼通多少条 + 未呼通多少条 + 未呼多少条 + 未分配多少条
点击【分配】后弹出modal,select2选择一个人
弹出modal,确定取消
分数记录在cdr上
点击后弹出modal , 包含试听audion、5颗星组件、点评textarea、保存button
座席用来执行外呼任务的页面
datatable列出所有任务
呼过和没呼过的任务,需要一眼就能看出。需要有排序。
select2,切换当前的外呼任务
获取当前外呼任务的数据(输入获取X条)
先勾选,后呼叫
打开外呼界面
datatables套路
增加,删除,移动位置到第X题
题型:单选(radio),多选(checkbox),文字(textarea)
数据库保存单选多选选项的格式:{"A":"你最喜欢的食物是?","B":"你最喜欢的城市是?"}
datatable+filter套路,QuestionnaireAnswerDetail及相关表
用于:根据答案筛选客户,勾选客户进行【另存到批次】的操作
群呼任务类似外呼任务
注意:extenType=ivr的,只能用static;extenType=queue的,可以dynamic,static
勾选,另存为批次,同外呼任务详情的那个操作
static群呼任务线程run的逻辑:
Set<String> 【当前并发数set】= new HashSet<>();//orignate后放入uuid,收到CDR后移除uuid
Cache.groupCall.put(groupCallId, 【当前并发数set】);
public void run() {
【群呼任务】.setIsRunning(true);
while(【群呼任务关闭标记】== 开){
//
sleep(1000);
// 如果已经有呼通的电话已经达到配置的静态并发数,就先不呼,等一下
if(【当前并发数set】.size() >= 【配置的静态并发数】){
continue;
}
// 开始呼叫X个数据
int 【本次应该呼叫的数据条数】 = 【配置的静态并发数】-【当前并发数set】.size();
if(【本次应该呼叫的数据条数】 <=0){
continue;
}
List<【群呼任务数据】> taskList = select number from 【群呼任务数据】.... where 【呼叫标记】=还没呼过 limit 【本次应该呼叫的数据条数】
// 如果没数据了,就跳出while,结束任务
if(taskList.size()==0){
break;
}
for(【群呼任务数据】 task:taskList){
//呼
OriginateResponse originateResponse = rsmwServer.originate(0,"8001","","","","8002","","","");
//如果呼叫失败了(大部分情况是系统达到并发上限了)就终止本次呼叫循环
if(!originateResponse.getErrcode().equals("0")){
break;
}
【当前并发数set】.add(originateResponse.getCallUuid);//在收到cdr时移除
//标记为“已呼过”
task.setCalled(true);
task.setCallTimestamp(new Date());
sleep(200);
}
// 更新到数据库
superDao.update(taskList);
}
Cache.groupCall.remove(groupCallId);
//任务结束,标记
【群呼任务】.setIsRunning(false);
superDao.update(【群呼任务】);
Cache.groupCall.remove(thisGroupCallId);
}
dynamic群呼任务线程run的逻辑:
public void run(){
Set<String> 【当前并发数set】= new HashSet<>();//orignate后放入uuid,收到CDR后移除uuid
Cache.groupCall.put(groupCallId, 【当前并发数set】);
【群呼任务】.set【群呼任务关闭标记】(开);
while(【群呼任务关闭标记】== 开){
// 如果已经有呼通的客户没有被接起,或者所有坐席都忙着,就先不呼,等一下
if(【技能组】有排队 || 【技能组】无空闲坐席){
sleep(1000);
continue;
}
// 开始呼叫X个数据
int 【空闲坐席数量】= 从mycache的queueMap中统计在线的空闲坐席数
int 【本次应该呼叫的数据条数】 = 【空闲坐席数量】*【系数】
List<【群呼任务数据】> taskList = select number from 【群呼任务数据】.... where 【呼叫标记】=还没呼过 limit 【本次应该呼叫的数据条数】
// 如果没数据了,就跳出while,结束任务
if(taskList.size()==0){
break;
}
for(【群呼任务数据】 task:taskList){
//呼
OriginateResponse originateResponse = rsmwServer.originate(0,"8001","","","","8002","","","");
//如果呼叫失败了(大部分情况是系统达到并发上限了)就终止本次呼叫循环
if(!originateResponse.getErrcode().equals("0")){
break;
}
//标记为“已呼过”
task.setCalled(true);
task.setCallTimestamp(new Date());
sleep(1000);
}
// 更新到数据库
superDao.update(taskList);
// 从调用orignate,到对方振铃,到对方接起需要时间,必须等待一下
sleep(8000);
}
//任务结束,标记
【群呼任务】.set【群呼任务关闭标记】(关);
superDao.update(【群呼任务】);
Cache.groupCall.remove(thisGroupCallId);
}
录音质检的打分项用自定义表的套路实现(注意,自定义表的实体类增加了【描述】字段)
能够导出表里的记录
录音质检的打分项用自定义表,但是页面不能用自定义表,要单独做一个简化版的(因为有很多简化项:如字段类型是固定的)
增删改查套路
增和删的同时,需要通过左右列表,选择该标准所包括的打分项(打分项就是扩展字段,从扩展表中取得,存成json)
统计每个人的每个得分项的得分情况(总分、平均分)
增加一个菜单,datatable套路:
save update用的modal表单:input用于输名称,textarea用于输描述,时间日期组件用于输入提醒时间,select2后端模式用于选择客户,owner字段填写当前用户无需在界面出现
后台判断时间,到了时间通过websocket推送一个提醒消息:eventName=alarm,alarmId=x
前端收到websocket后,1)回调发送post,后台将alarmed update成true;2)显示提醒框(不会自动消失),包含两个按钮:【查看】,【关闭】
弹屏处,在【短信】后增加【预约】,点击后出现modal;业务tab,增加【预约】
用现在的addTab(key,name,url)来打开poptab,通过url?p1=v1&p2=v2来传参,参数如下:
customerId //弹屏显示哪个客户【必填】
nextCustomerId //下一个弹屏显示哪个客户
activeBusniessTabKey //默认激活哪个业务tab。默认显示第一个tab
autoStartCall:true //打开弹屏后,是否要自动调用“呼叫”(自动点击呼叫按钮)。默认为false
questionnaireId:1 //问卷tab显示哪个问卷。默认不显示问卷tab
outboundTaskId:1 //外呼任务的id
outboundTaskItemId:2 //外呼任务Item的id
onCloseAction:
弹屏tab的key规则:popScreen_${customerId}
addTab调用时机:
1)客户来电时,rsmw推送event,qqd收到event后通过来电号码得到客户id(发现新客户,自动保存,并获取id),然后通过websocket把customerId推到页面时调用
2)页面直接请求popcontroller
左边3:客户详情。展现形式采用表格key,value,纵向紧凑,带滚动条。以便客户基本信息字段较多时能够显示。每次修改直接操作数据库
左边3操作
操作button:
【呼叫】,带下来的button【带0呼叫】
【短信】,打开发送短信的表单modal
【微信】,打开微信tab,并打开当前客户的微信对话子tab
【关闭】,普通button
【打开下一个】,checkbox(保存在本地js变量中,勾选后,下一个弹屏也勾选)
左边3底部:批次信息。回显当前批次。select2多选模式。编辑select2,取消(恢复回显),保存(操作customerCustomerBatchLink表)
业务tab枚举:客户跟进记录(备注,通话,短信)、问卷、工单、客户变更记录
addTab打开第三方URL(在系统配置中配置),传参为客户电话号码
类似部门,自关联表
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
KnowledgeCategory | id | 主键 | bigint | 20 | PK | 是 |
KnowledgeCategory | name | 类目名称 | varchar | 64 | 是 | 是 |
KnowledgeCategory | parentId | 上级id | bigint | 20 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Knowledge | id | 主键 | bigint | 20 | PK | 是 |
Knowledge | title | 知识名称 | varchar | 64 | 是 | 是 |
Knowledge | content | 知识内容 | text | |||
Knowledge | creatorId | 发布者id | bigint | 20 | 是 | 是 |
Knowledge | creatorDate | 发布时间 | datetime | 是 | 是 | |
Knowledge | expireDate | 过期时间 | datetime | 是 | 是 | |
Knowledge | readCount | 浏览次数 | bigint | 20 | 是 | 是 |
Knowledge | categoryId | 类目Id | bigint | 20 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
KnowledgeReadCount | id | 主键 | bigint | 20 | PK | 是 |
KnowledgeReadCount | userId | 浏览者id | bigint | 20 | 联合唯一 | 是 |
KnowledgeReadCount | knowledgeId | 被浏览的知识id | bigint | 20 | 联合唯一 | 是 |
KnowledgeReadCount | readCount | 浏览次数 | bigint | 20 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
KnowledgeEvaluate | id | 主键 | bigint | 20 | PK | 是 |
KnowledgeEvaluate | userId | 评价者id | bigint | 20 | 联合唯一 | 是 |
KnowledgeEvaluate | knowledgeId | 被评价的知识id | bigint | 20 | 联合唯一 | 是 |
KnowledgeEvaluate | type | 评价类型(好评,差评) | varchar | 16 | 是 | 是 |
KnowledgeEvaluate | evaluateDate | 发布时间 | datetime | 是 | 是 | |
KnowledgeEvaluate | comment | 备注 | varchar | 512 |
datatable套路
datatable套路
知识的分类和搜索
树形分类和搜索框
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Announcement | id | 主键 | bigint | 20 | PK | 是 |
Announcement | title | 公告名称 | varchar | 64 | 是 | 是 |
Announcement | content | 公告内容 | TEXT | |||
Announcement | creatorId | 创建者id | bigint | 20 | 是 | 是 |
Announcement | creatorDate | 创建时间 | datetime | 是 | 是 | |
Announcement | deployId | 发布者id | bigint | 20 | 是 | |
Announcement | deployDate | 发布时间 | datetime | 是 | ||
Announcement | deployed | 是否发布过 | tinyint | 1 | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
AnnouncementDetail | id | 主键 | bigint | 20 | PK | 是 |
AnnouncementDetail | announcementId | 公告id | bigint | 20 | 是 | 是 |
AnnouncementDetail | userId | 接收公告用户的id | bigint | 20 | 是 | 是 |
AnnouncementDetail | readed | 是否已经阅读过 | tinyint | 1 | 是 | 是 |
datatable套路
插入Announcement记录(每个公告一条),插入AnnouncementDetail记录(每个应该受到公告的人一条)
通过websocket推送消息,eventName=announcement,announcementId=x
页面收到websocket消息时,弹出一个提醒框(不会自动消失,需要点击,点击后消失并打开公告的modal)
删除时,同时删除相关AnnouncementDetail
操作:查看阅读情况:发布到那些人,这些人是否打开阅读了这个公告,在modal里列出datatable
点开详情用modal,包括【标题】【发布时间】【发布人】【内容】
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Filter | id | 主键 | bigint | 20 | PK | 是 |
Filter | name | 过滤器名称 | varchar | 64 | 是 | 是 |
Filter | viewTableName | 过滤的表名 | varchar | 64 | 是 | 是 |
Filter | creatorId | 创建者 | bigint | 20 | 是 | 是 |
Filter | createDate | 创建日期 | datetime | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
FilterUserGroupLink | id | 主键 | bigint | 20 | PK | 是 |
FilterUserGroupLink | filterId | 过滤器id | bigint | 20 | 联合 | 是 |
FilterUserGroupLink | userGroupId | 用户组id | bigint | 20 | 联合 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
FilterCondition | id | 主键 | bigint | 20 | PK | 是 |
FilterCondition | filterId | 过滤器id | bigint | 20 | 是 | 是 |
FilterCondition | columnName | 过滤的列 | varchar | 64 | 是 | |
FilterCondition | columnType | 过滤的列数据类型 | varchar | 64 | 是 | |
FilterCondition | operator | 运算符 | varchar | 64 | 是 | |
FilterCondition | value | 运算值 | varchar | 64 | 是 |
字符【等于,不等于,包含,不包含,为空,不为空】
文本【等于,不等于,包含,不包含,为空,不为空】
整数【等于,不等于,大于,小于,介于,不介于,为空,不为空】
浮点数【等于,不等于,大于,小于,介于,不介于,为空,不为空】
枚举【等于,不等于,空,不空】
date【等于,不等于,今天,昨天,近X天,本周,本月,小于,大于,介于,不介于,为空,不为空】
datetime【等于,不等于,今天,昨天,近X天,本周,本月,小于,大于,介于,不介于,为空,不为空】
客户过滤器
工单过滤器
修改过滤器时,若可见范围是较大影响面较广,需要给出提醒。
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
PhoneBook | id | 主键 | bigint | 20 | PK | 是 |
PhoneBook | name | 姓名 | varchar | 64 | 是 | 是 |
PhoneBook | phoneNumber | 电话号码 | varchar | 64 | 是 | 是 |
PhoneBook | departmentId | 部门Id | bigint | 20 | 是 | 是 |
datatable套路
电话机小图标,可以直接点击拨打
主要参考udesk和网易七鱼
WorkOrder
工单(id,客户id,标题,产品id,工单类型,工单状态,工单优先级,负责人,创建人,创建时间,关闭时间,耗时)
WorkOrderComment工单备注(id,工单id,回复内容,回复日期,回复人)
WorkOrderCategoryChangeLog工单类型变更记录(id,工单id,旧类型,新类型,时间戳)
WorkOrderStatusChangeLog工单状态变更记录(id,工单id,旧状态,新状态,时间戳)
WorkOrderPriorityChangeLog工单优先级变更记录(id,工单id,旧优先级,新优先级,时间戳)
WorkOrderOwnerChangeLog工单负责人变更记录(id,工单id,旧负责人,新负责人,时间戳)
WorkOrderCategory工单类型(id,名称)
WorkOrderStatus工单状态(id,名称)
WorkOrderPriority工单优先级(id,名称)
内置工单状态:“关闭”
关闭,填写耗时:时、分
新建和编辑都用tab
菜单红点
发送邮件
smtp邮件服务器配置
看看jira配置邮件服务器的配置
此功能算在呼叫中心模块下
房间
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Room | id | 主键 | bigint | 20 | PK | 是 |
Room | name | 名称 | varchar | 64 | 是 | 是 |
工位
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Desk | id | 主键 | bigint | 20 | PK | 是 |
Desk | name | 名称 | varchar | 64 | ||
Desk | sipPhoneName | 分机号 | varchar | 64 | 是 | |
Desk | positionTop | 平面坐标 x,y 用于决定画在页面上的位置 | int | 11 | 是 | |
Desk | positionLeft | 平面坐标 x,y 用于决定画在页面上的位置 | int | 11 | 是 | |
Desk | roomId | 房间Id | bigint | 20 | 是 | 是 |
datatable 套路
添加/编辑Room及Room里的Desk:
input:用于输入房间名称
左右列表:用于添加工位(同技能组添加成员,列表里的是sip分机)
删除房间:
删除房间时,同时删除相关的所有desk记录
实现 rootService.loadToCache(),并在sys。init里调用
纵向tab表示各房间。
点击切换tab:同时跟新var currentRoomId的值
每个tab内显示的内容:当前room中的所有desk,用ftl依次刷到界面上,用js每秒更新状态。
拖动desk的div时,后台会update postion
工位div用sipphonename作为id
工位上展示的信息:Agent.name,sipPhone.name,通话状态和时长(用颜色),置忙状态(用颜色)
工位上展示的操作图标:暂停,挂断,监听(同中间件的技能组详情)
录音质检打分统计:一段时间里,每个人的各项分数平均分、总分的平均分
不需要中间表,每次都是直接从原始数据计算
输入:年报/月报/日报/总和,时间(年,月,时间段)
select cdrEndtime,agentId, avg(col_149cxxcx), avg(col_149yyyy), col_xxxx+col_yyy from qqd_callcenter_recordscore where cdrEndtime>='' and cdrEndtime<='' group by cdrEndtime,agentId;
日报、月报、年报
2017-05-01 ~ 2017-05-15
日期(日或月或年) | 姓名 | 得分项1(平均分) | 得分项2(平均分) | 得分项X(平均分) | 总得分(平均分) |
---|---|---|---|---|---|
2017-05-01 | 张三 | 10.00 | 10.00 | 8.00 | 28.00 |
2017-05-01 | 李四 | 9.00 | 8.00 | 9.00 | 26.00 |
2017-05-15 | 张三 | 10.00 | 10.00 | 8.00 | 28.00 |
2017-05-15 | 李四 | 9.00 | 8.00 | 9.00 | 26.00 |
总和
2017-05-01 ~ 2017-05-15
姓名 | 得分项1(平均分) | 得分项2(平均分) | 得分项X(平均分) | 总得分(平均分) |
---|---|---|---|---|
张三 | 10.00 | 10.00 | 8.00 | 28.00 |
李四 | 9.00 | 8.00 | 9.00 | 26.00 |
一段时间里,每一类的每天数量及总和数量
select category, count(*) group by category
柱状图,叠加柱状图
输入:年报/月报/日报/总和,时间(年,月,时间段),类型级别(1,2,3)【此项不选,直接画3个表格出来即可】
日报、月报、年报
2017-05-01 ~ 2017-05-15
日期(日或月或年) | 类型 | 数量 |
---|---|---|
2017-05-01 | 投诉 | 12 |
2017-05-01 | 咨询 | 431 |
2017-05-15 | 投诉 | 7 |
2017-05-15 | 咨询 | 265 |
总和
2017-05-01 ~ 2017-05-15
类型 | 数量 |
---|---|
投诉 | 12 |
咨询 | 431 |
投诉 | 7 |
咨询 | 265 |
近日客户新增(某时段【天月年】,【每天、每月、每年】从各【来源】新增的各【类型】客户分别有多少个)
输入:年报/月报/日报/总和,时间(年,月,时间段),类型级别(1,2,3)
日报、月报、年报
2017-05-01 ~ 2017-05-15
日期(日或月或年) | 来源 | 数量 |
---|---|---|
2017-05-01 | 导入 | 12 |
2017-05-01 | 网站 | 431 |
2017-05-15 | 导入 | 7 |
2017-05-15 | 网站 | 265 |
总和
2017-05-01 ~ 2017-05-15
来源 | 数量 |
---|---|
导入 | 19 |
网站 | 696 |
处理的工单数量(C),每个工单的处理时间(P),有效工作时间(T)
T=所有的p累加
平均T=T/C
统计每个人的:【工单处理量】、【每个工单处理时长】
这样能够得出:每个人【总工单处理时长】、【平均工单处理时长】
散点图:
x轴:工单处理量
y轴:工单处理总时长
散点的颜色(绿好、橙中、红差):平均处理时长(y/x),也就是斜率
定义平均时长的两个点:好中x1、中差x2;小于x1的绿色,大于x2的红色,其余橙色
管理技术支持人员的方法:
A:解决每个问题的时间(员工自己记录)
B:解决问题的个数(工单系统自动统计)
C:有效工作时间(就是所有的A之和)
【A的平均值】(即C除以B)越短越好,这代表技术能力强
【B】越多越好,这代表工作量
【C】越长越好,这代表努力程度
这三个指标之间的平衡关系有效地杜绝了员工只关注一点、偏废其他。
比如,
有的员工为了展现技术能力,用2小时解决问题,他记录成1小时。但因为【A平均值】 x【B】得出的C,他的有效工作总时间就会减半,显得很不努力。
有的员工为了展现努力程度,工作8小时,想显得工作了16小时。A x B = C,因此,他必须把用2小时解决的问题,记录成4小时。但这样就显得他的技术能力不行,解决问题时间比同事长很多。
这三个指标的平衡性,几乎杜绝了技术支持员工,只关注一点、偏废其他的可能性。
用户(原有字段,意向客户上限)
此表需要支持自定义字段
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OrderMaster | id | 主键 | bigint | 20 | PK | 是 |
OrderMaster | customerId | 客户id | bigint | 20 | 是 | 是 |
OrderMaster | creatorId | 创建者id | bigint | 20 | 是 | 是 |
OrderMaster | creatDate | 创建时间 | datetime | 是 | 是 |
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
OrderDetail | id | 主键 | bigint | 20 | PK | 是 |
OrderDetail | orderId | 订单id | bigint | 20 | 是 | 是 |
OrderDetail | productId | 产品id | bigint | 20 | 是 | 是 |
OrderDetail | productPrice | 产品价格 | bigint | 20 | 是 | 是 |
OrderDetail | productQty | 产品数量 | int | 11 | 是 |
1)套路
2)弹屏处,增加一个订单的业务tab
目前微信功能,包括操作便捷性的优化
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
PauseReason | id | 主键 | bigint | 20 | PK | 是 |
PauseReason | name | 名称 | varchar | 64 | 是 |
现有表
删除,需要问用户,原先关联到被删除值的相关记录怎么处理(全库update成其他值后,再行删除)
现有表
删除,需要问用户,原先关联到被删除值的相关记录怎么处理(全库update成其他值后,再行删除)
第三方业务的弹屏页URL
待定
是否考虑做成properties文件。因为不同的短信平台配置的内容还是有差异的,没法抽象出相同部分。
已有
实体 | 字段 | 说明 | 类型 | 长度 | 索引 | 必填 |
---|---|---|---|---|---|---|
Product | id | 主键 | bigint | 20 | PK | 是 |
Product | name | 名称 | varchar | 64 | 是 | 是 |
Product | description | 备注 | varchar | 512 | ||
Product | price | 价格 | float | 8,2 | 是 | |
Product | url | 相对url | varchar | 256 | ||
Product | createDate | 创建日期 | datetime | 是 | 是 |
重新上传图片或删除产品时,需要同时删除对应的老的图片文件
上传路径qqd_productimg_upload
枚举值的编辑问题:没有被引用的枚举值,可以删,被引用的枚举值直接删除会导致数据库异常。
处理方式:编辑枚举值时,需要取得【编辑前的枚举值列表】和【本次提交的枚举值列表】,对比出【被删除的值】,并弹出modal询问用户【对于这些被删除的值,若被引用了,替换成哪个值】,让用户用select2选(这个select2是【本次提交的枚举值列表】)。用户选择并提交,后台在做现有的操作之前,增加一个update动作。
自定义字段主要用界面元素描述(单选radio,下拉select2,多选checkbox,日期datapicker,数字input,文字input,多行文字textarea),不要用数据库结构描述(枚举,字符)
长度、是否索引等选项,默认值,点【高级】才展示