客服系统 2.0

前言

此文借以北京住范儿客服系统为原型撰写
强烈建议入门选手先看看这一篇写给产品经理的《零基础IM开发入门》

客服系统 2.0 是什么?

支持小程序网页、Web 网页实时通信的管理系统,部分效果如下(插图):

C端

B端

技术堆栈

  • PHP

  • Laravel

  • Workerman(GatewayWorker)

  • Redis

  • Mysql

流程图

功能组成与实践

上面简单描述了一下客服系统交互流程,下面就展开讲讲要实现的细节。

联系人列表

这里的联系人列表是指某一时间段下客服接待的用户列表,实质上就是绑定客服这个 Socket Client 的所有用户 Client。需要注意的是这个列表不会分页,因为方便搜索定位。

聊天界面

这里主要就是发消息(Message),包含文本、图片、商品、订单,需要划分类型,所以我们需要定义一个消息结构体。

未读消息

联系人列表上需要统计未读消息数

离线消息

当用户给客服发消息时,如果 Socket 连接可用,需要判断这个连接是否在线,如果不在线,先把消息发到离线数据库里,等对应的客服上线之后,主动向服务器拉取离线消息

如何保证客服系统的实时性、可靠性、一致性、安全性

| 特征 | 前后端 |

| :— | :— | :— |

| 实时性 | 多进程消费 | |

| 可靠性 | 重传-确认机制 | |

| 安全性 | HTTPS+TOKEN | |

| 一致性 | 消息去重、服务器时间同步、哈希进程 | |

心跳保活

正常的情况客户端断开连接会向服务端发送一个fin包,服务端收到fin包后得知客户端连接断开,则立刻触发onClose事件回调。
但是有些极端情况如客户端掉电、网络关闭、拔网线、路由故障等,这些极端情况客户端无法发送fin包给服务端,服务端便无法知道连接已经断开。如果客户端与服务端定时有心跳数据传输,则会比较及时的发现连接断开,触发onClose事件回调。

多端登陆

简单点说就是假如一个客服用同一个账号即登陆了电脑端又登陆了手机端,那么当电脑端再给用户回消息的时候,服务器也需要给自己的手机端推送一次消息。

架构图

附录

为什么 TCP 保证不了 IM 通信的可靠传输

举个例子,当 TCP 成功将消息报文发送到服务器之后,在消息入库之前服务器挂掉了,那么这个消息也就没有被存下来,当然这一次通信就算事不可靠的了。

消息结构体

| 字段 | 说明 | 可选值 | 描述 |

| — | — | — | — |

| 字段 | 说明 | 可选值 | 描述 |

| category | 所属分类 | | |

| | | system | 系统推送的消息 |

| | | customer | 客户发送的消息 |

| | | manager | 客服发送的消息 |

| | | heartbeat | 心跳检测(不需入库) |

| | | ack | 响应消息回执(不需入库) |

| | | receive | 确认收到响应回执(不需入库) |

| action | 执行的动作 | | |

| | | send | 正常发送 |

| | | revoke | 撤回 |

| | | delete | 删除 |

| | | read | 已读 |

| | | auth | 用户验证 |

| style | 消息展示样式 | | |

| | | normal | 一般的纯文本消息框 |

| | | card | 卡片风格(场景:商品链接) |

| | | order | 商品订单风格(场景:客户订单) |

| | | assess | 客服评价的风格 |

| | | toast | 灰色提示性样式(场景:客服接入时的提示) |

| kind | 内容的格式 | | |

| | | text | 一般的纯文本格式(包含emoji表情) |

| | | picture | 图片格式(包含.jpg/.jpeg/.png/.gif等) |

| | | video | 视频格式(包含.mp4/.mkv/.rmvb等) |

| | | audio | 音频格式(包含.mp3/.raw等) |

| | | file | 其他文件格式(包含.xml/.ppt/.docx/.dwg等) |

| | | unknown | 未知的文件格式 |

| id | 消息ID | -- | 每条消息都有全局唯一的ID(对应数据库的主键ID) |

| task_id | 任务ID | -- | 指解决一次问题。从客户转入人工开始,会生成一个task_id,直到最后一个客服点击「结束服务」为止。在客服点击「,同一客户多次转入人工,task_id都是同一个。 |

| content | 正文内容 | -- | 纯文本内容(如图片src地址、视频src地址) |

| from | 主发送人 | -- | 发送方的唯一标识 |

| to | 被接收人 | -- | 接收方的唯一标识 |

| url | 链接 | -- | 点击消息后,跳转到目标链接 |

| created_at | 发送时间 | -- | 消息的生成时间 |

| is_read | 是否已读 | -- | 此消息是否已被用户看到 |

| is_revoke | 是否已撤回 | -- | 此消息是否已被用户撤回 |

| is_delete | 是否删除 | -- | 此消息是否已被用户删除 |

| quote | 引用消息ID | -- | 引用指定的消息(场景:撤回消息时,这里应填写被撤回消息的消息ID) |

| ext | 其他扩展字段 | -- | json结构化数据 |

Author

Frank Wang

Posted on

2022-09-06

Updated on

2022-09-06

Licensed under

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.