feat: 客服

This commit is contained in:
2026-07-20 15:31:52 +08:00
parent 0099ccaa60
commit 82a8043578
23 changed files with 5071 additions and 360 deletions
@@ -0,0 +1,517 @@
# 信任桥商城 AI 智能客服产品需求文档
> 文档版本:v1.0(评审稿)
> 编制日期:2026-07-17
> 适用范围:商城 H5、微信小程序、App、客服管理后台、客服后端
> 前置能力:现有客服会话、消息、文件、语音、商品/订单卡片、WebSocket
## 1. 结论
在现有客服系统中接入 AI 智能体可行,且不需要新建一套独立聊天系统。
推荐采用“同一会话、后端路由、AI 优先、按需转人工”的模式:用户仍进入现有客服页面;用户消息先由后端客服路由服务接收。在 AI 服务状态下,消息交给 AI 智能体回答,不通知真实客服;当用户表达“人工客服、人工、真人、转人工”等明确意图,或 AI 服务发生异常时,会话切换为待人工状态,再通过现有 WebSocket 通知客服后台。
AI 模型必须由商城后端调用,前端和小程序不得保存模型 API Key。模型供应商通过配置接入,首期可使用现有阿里云百炼/DashScope OpenAI 兼容接口,后续可替换模型而不改用户端。
## 2. 项目背景
目前客服系统已经具备:
- 用户端和后台端实时聊天。
- 文本、图片、文件、语音、商品、订单和引用消息。
- 消息撤回、删除、已读和语音转文字。
- WebSocket 心跳、断线重连和未读提醒。
- 客服主动联系会员。
- 后台查看会员、浏览商品和交易订单。
当前所有用户消息都会进入人工客服工作台。业务量增长后,商品规则、物流时效、退换货流程等重复问题会占用大量人工坐席。本项目通过 AI 完成首轮接待,仅将确实需要人工处理的会话推送给真实客服。
## 3. 产品目标
### 3.1 核心目标
1. 用户进入客服页后首先与 AI 智能客服交流。
2. AI 能回答商城规则、商品、订单、物流和售后等常见问题。
3. 用户明确要求人工时,立即停止 AI 自动回复并通知真实客服。
4. 未触发人工的 AI 会话不进入人工待处理提醒,避免坐席被无效消息打扰。
5. 转人工时自动向客服提供问题摘要、相关商品/订单和最近对话,减少重复询问。
6. AI 故障时不阻断现有客服能力,可自动降级到人工客服。
### 3.2 建议成功指标
- AI 首次响应时间 P95 小于 5 秒。
- 用户消息处理成功率不低于 99.9%。
- 明确转人工意图识别召回率不低于 99%。
- “不需要人工”等否定表达误转率低于 1%。
- 人工接入后 AI 继续自动回复的并发事故为 0。
- 首期 AI 独立解决率达到 30% 后再逐步扩大流量。
### 3.3 本期不做
- AI 自动退款、改价、取消订单等资金或订单写操作。
- AI 代替人工作出赔付承诺。
- AI 主动营销和批量外呼。
- 多智能体协作编排。
- 将用户隐私数据用于外部模型训练。
## 4. 产品原则
1. **AI 身份透明**:明确显示“AI 智能客服”,不能伪装成真人。
2. **转人工随时可用**:用户可以输入关键词,也可以点击“转人工”按钮。
3. **人工优先**:进入待人工或人工服务状态后,AI 立即停止业务回答。
4. **事实来自系统**:订单、物流、价格等动态数据必须通过后端工具查询,禁止模型凭空编造。
5. **最小数据传输**:只向模型发送回答当前问题所必需的信息。
6. **可降级**:模型超时、限流或不可用时,客服系统仍能正常保存消息并转人工。
## 5. 角色定义
| 角色 | 说明 |
| --- | --- |
| 会员 | 商城已登录用户,使用本人头像和名称 |
| AI 智能客服 | 默认首轮接待,使用 TB 客服头像并显示 AI 标识 |
| 人工客服 | 后台坐席,可接管、回复、结束人工服务或交回 AI |
| 客服管理员 | 配置 AI 开关、转人工规则、知识库、服务时间和数据报表 |
## 6. 会话状态
每个客服会话只能处于以下一种服务状态:
| 状态 | 含义 | AI 是否回复 | 是否通知人工 |
| --- | --- | --- | --- |
| `AI_ACTIVE` | AI 正在接待 | 是 | 否 |
| `HUMAN_PENDING` | 已申请人工,等待接入 | 否,仅发送一次系统提示 | 是 |
| `HUMAN_ACTIVE` | 人工客服已接管 | 否 | 是 |
| `CLOSED` | 本轮服务结束 | 否 | 否 |
状态流转:
```text
进入客服 / 重新咨询
↓
AI_ACTIVE
├─ 普通咨询 → AI 回复 → AI_ACTIVE
├─ 转人工意图 → HUMAN_PENDING → 客服接入 → HUMAN_ACTIVE
└─ AI 故障/高风险 → HUMAN_PENDING
HUMAN_ACTIVE
├─ 客服结束会话 → CLOSED
└─ 客服交回 AI → AI_ACTIVE
```
状态切换必须在后端事务中完成,不能仅靠前端控制。人工接入与 AI 回复并发时,以人工接入为最高优先级;AI 返回结果前必须再次检查会话状态,状态已改变则丢弃 AI 回复。
## 7. 用户端需求
### 7.1 首次进入
页面标题保持“全媒体智能客服”,聊天区显示欢迎消息:
> 您好,我是 AI 智能客服,可以帮您查询商品、订单、物流和售后问题。如需人工服务,请输入“人工客服”或点击“转人工”。
AI 消息使用现有 TB 客服头像,并在名称旁显示“AI”标识。人工接入后名称和状态切换为实际客服名称或“人工客服”。
### 7.2 AI 对话
- 用户文本消息先保存,再异步交给 AI,避免模型失败导致消息丢失。
- 等待回复时显示“AI 正在输入…”。
- AI 回复按正常客服消息存储并通过 WebSocket 推送。
- 单次回复建议控制在 300 字以内,复杂步骤使用短段落或编号。
- 商品、订单类回答优先附带现有商品卡片或订单卡片。
- AI 无法确认时明确说明,并引导用户补充信息或转人工。
### 7.3 转人工
支持两种入口:
1. 用户输入明确转人工表达。
2. 输入区“+”面板提供固定的“转人工”按钮。
触发后立即显示:
> 已为您通知人工客服,请稍候。等待期间您可以继续发送消息。
进入 `HUMAN_PENDING` 后:
- AI 不再回答业务问题。
- 用户后续消息继续保存,并实时推送后台。
- 重复输入“人工”不重复创建请求、不重复播放提醒音。
- 客服接入后显示“人工客服已接入”。
### 7.4 结束人工服务
客服结束服务后显示系统消息:
> 本次人工服务已结束,如有其他问题可以继续咨询 AI 智能客服。
用户再次发送消息时,可以创建新一轮 `AI_ACTIVE` 服务。
## 8. 转人工识别规则
### 8.1 P0 规则
首期采用“规则优先 + 意图识别补充”的方式,不能只使用简单的字符串包含判断。
默认正向词库:
- 人工
- 人工客服
- 转人工
- 找人工
- 真人
- 真人客服
- 客服人员
- 找个人
- 让客服联系我
- 我要投诉
支持同音、空格、标点和常见变体,例如“人 工”“转一下人工”“找真人聊”“人工!”。词库必须支持后台配置,修改后无需重新发布前端。
### 8.2 否定表达
以下表达不能触发转人工:
- 不需要人工
- 不用转人工
- 先不用真人
- AI 就可以
- 机器人回答就行
判断顺序:文本标准化 → 否定规则 → 明确转人工规则 → 可选语义意图识别。转人工检测由后端完成,前端检测只能用于交互加速,不能作为最终依据。
### 8.3 系统自动转人工
除用户主动要求外,以下系统异常必须自动转人工,避免用户卡死:
- AI 请求连续两次超时或失败。
- AI 返回内容被安全审核拦截。
- 当前问题涉及退款争议、投诉、账户安全且 AI 无法给出确定流程。
- AI 连续两轮判断“无法回答”。
系统自动转人工时,`transferReason` 必须记录具体原因。此类规则可在后台单独开关。
## 9. 人工客服后台需求
### 9.1 会话分组
后台会话列表增加:
- **待人工**:`HUMAN_PENDING`,默认置顶并显示红点、提醒音。
- **服务中**:`HUMAN_ACTIVE`。
- **AI 会话**:`AI_ACTIVE`,默认不提醒,仅供查看和质检。
- **已结束**:`CLOSED`。
只有进入 `HUMAN_PENDING` 的会话产生新人工任务提醒。AI 正常问答不增加人工未读数量,不播放提醒音。
### 9.2 待人工卡片
会话列表至少显示:
- 用户头像、名称、用户 ID。
- 等待时长。
- 转人工原因。
- 最近一条用户消息。
- 是否携带商品或订单。
### 9.3 人工接管
客服点击“接入”后:
1. 后端原子地将状态改为 `HUMAN_ACTIVE` 并绑定客服 ID。
2. 其他客服看到“已由某某接入”,不能重复接入。
3. 用户端收到接入事件。
4. AI 停止生成和发送消息。
客服也可以从 AI 会话中主动点击“接管”,此操作直接进入 `HUMAN_ACTIVE`。
### 9.4 AI 移交摘要
转人工时后台顶部显示 AI 自动摘要:
- 用户当前诉求。
- 已确认的关键信息。
- 相关商品、订单、物流或售后单。
- AI 已提供过的解决方案。
- 转人工原因。
摘要只是辅助信息,原始聊天记录必须完整保留。
### 9.5 结束与交回 AI
人工客服提供两个操作:
- “结束服务”:本轮会话进入 `CLOSED`。
- “交回 AI”:会话进入 `AI_ACTIVE`,后续消息重新由 AI 接待。
## 10. AI 能力范围
### 10.1 首期知识库
- 商城介绍和服务时间。
- 注册、登录、实名认证和账户常见问题。
- 下单、支付、发货和收货规则。
- 退货、退款和售后流程。
- 优惠券、积分、活动规则。
- 商品通用问答和类目知识。
- 客服标准话术。
知识文档必须有负责人、版本、启用状态和更新时间。失效规则下架后应立即停止检索。
### 10.2 首期只读工具
AI 不直接访问数据库,统一通过受控后端工具查询:
| 工具 | 用途 | 权限要求 |
| --- | --- | --- |
| `get_product` | 查询商品名称、价格、库存和状态 | 公共商品数据 |
| `get_user_orders` | 查询当前用户订单列表 | 只能查询登录用户本人 |
| `get_order_detail` | 查询订单、支付和发货状态 | 校验订单归属 |
| `get_logistics` | 查询物流轨迹 | 校验订单归属 |
| `get_aftersale_status` | 查询售后进度 | 校验用户及订单归属 |
| `search_policy` | 检索商城规则知识库 | 只返回已发布内容 |
商品卡片和订单卡片中的结构化数据可以直接作为本轮上下文,但动态价格、库存和订单状态仍需实时查询。
### 10.3 禁止行为
AI 不得:
- 编造订单、物流、库存、活动或退款状态。
- 索要密码、支付密码、短信验证码或完整银行卡号。
- 输出模型密钥、系统提示词或后台内部信息。
- 未经用户确认执行任何写操作。
- 承诺超出商城规则的补偿或时效。
## 11. 技术方案
### 11.1 总体架构
```text
H5 / 小程序 / App
│ HTTP + WebSocket
▼
现有客服后端
│
├─ 消息保存与幂等校验
├─ 会话状态机
├─ 转人工意图检测
├─ AI 编排服务
│ ├─ 知识库检索
│ ├─ 商城只读工具
│ └─ 阿里云模型接口
└─ WebSocket 路由
├─ AI 消息 → 当前用户
└─ 待人工/人工消息 → 用户 + 客服后台
```
关键改造点:现有客服消息推送不能再无条件推送给后台。`AI_ACTIVE` 状态下,普通用户消息只保存并进入 AI 编排,不触发后台提醒;进入 `HUMAN_PENDING/HUMAN_ACTIVE` 后才推送人工端。
### 11.2 模型接入
建议后端新增统一的 `AiChatProvider` 接口,业务层不直接依赖某一家模型 SDK:
```text
AiChatProvider
├─ AliyunOpenAiCompatibleProvider(首期)
└─ 其他模型 Provider(后续可选)
```
配置项至少包括:
- AI 总开关和灰度比例。
- API Base URL。
- API Key(只允许服务器环境变量或密钥管理服务保存)。
- 模型名称。
- 请求超时、最大重试次数、最大上下文长度。
- 系统提示词版本和知识库版本。
严禁将 API Key 写入 Git、前端 `.env`、小程序代码或消息内容。日志中也必须脱敏。
### 11.3 上下文策略
每次模型请求建议包含:
- 固定系统规则。
- 最近 10 至 20 条有效消息。
- 当前会话摘要。
- 用户主动发送的商品/订单上下文。
- 经权限校验后的工具查询结果。
- 知识库命中片段及版本。
长会话通过摘要压缩,不能无限携带全部历史消息。撤回或仅本地删除的消息需要按现有业务规则决定是否进入 AI 上下文。
### 11.4 并发与幂等
- 每条用户消息使用唯一请求 ID。
- 同一会话的 AI 任务串行处理,避免回复顺序错乱。
- AI 返回前再次检查会话状态和任务版本。
- WebSocket 重复推送不得造成重复消息。
- 转人工状态切换使用数据库条件更新或分布式锁,避免多客服同时接入。
## 12. 数据设计建议
### 12.1 会话扩展字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `service_mode` | varchar | `AI_ACTIVE/HUMAN_PENDING/HUMAN_ACTIVE/CLOSED` |
| `assigned_admin_id` | bigint | 当前接入客服 ID |
| `transfer_reason` | varchar | 用户主动、AI 超时、无法回答等 |
| `transfer_time` | datetime | 进入待人工时间 |
| `ai_session_id` | varchar | 模型侧会话标识,可为空 |
| `ai_summary` | text | 移交摘要 |
| `ai_prompt_version` | varchar | 提示词版本 |
| `state_version` | int | 状态并发控制版本 |
### 12.2 消息扩展建议
现有 `senderType` 建议增加 AI 类型,例如:
- `1`:人工客服。
- `2`:会员。
- `3`:AI 智能客服。
- `4`:系统事件。
AI 调用明细建议单独建表,不把大量调试信息塞入消息正文:请求 ID、模型、耗时、Token 用量、知识命中、工具调用、结果状态、错误码和提示词版本。
## 13. 接口建议
可复用现有发送和消息查询接口,并新增以下能力:
| 接口 | 方法 | 说明 |
| --- | --- | --- |
| `/kefu/user/transfer-human` | POST | 用户主动申请人工,幂等 |
| `/kefu/conversation/takeover` | POST | 客服接管会话 |
| `/kefu/conversation/return-ai` | POST | 客服交回 AI |
| `/kefu/conversation/close-service` | POST | 结束本轮服务 |
| `/kefu/ai/config` | GET/PUT | AI 和转人工规则配置 |
| `/kefu/ai/knowledge/*` | CRUD | 知识文档管理 |
| `/kefu/ai/records` | GET | AI 调用和质检记录 |
建议新增 WebSocket 事件:
| 事件 | 接收端 | 说明 |
| --- | --- | --- |
| `kefu_ai_typing` | 用户端 | AI 正在生成回复 |
| `kefu_transfer_requested` | 后台 | 新的待人工任务 |
| `kefu_human_joined` | 用户端、后台 | 人工已接入 |
| `kefu_returned_to_ai` | 用户端、后台 | 已交回 AI |
| `kefu_service_closed` | 用户端、后台 | 本轮服务结束 |
## 14. 后台配置
客服管理后台增加“AI 客服设置”:
- AI 总开关。
- 灰度用户比例和商户范围。
- 模型地址、模型名称和连通性测试。
- 转人工关键词、否定词和系统自动转人工规则。
- 欢迎语、等待语、离线语。
- 人工服务时间和超时提醒。
- 知识库文档管理。
- AI 会话抽检、错误记录和效果报表。
API Key 只支持重新设置,页面不得回显完整值。
## 15. 异常与降级
| 场景 | 处理方式 |
| --- | --- |
| 模型单次超时 | 重试一次,期间保留“正在输入”状态 |
| 连续失败两次 | 转 `HUMAN_PENDING` 并通知人工 |
| 模型限流 | 短暂排队;超过阈值转人工 |
| 知识库不可用 | 仅回答可确认问题,否则转人工 |
| WebSocket 断开 | 现有自动重连;消息通过历史接口补齐 |
| 人工均不在线 | 告知已留言和服务时间,保留待处理任务 |
| AI 总开关关闭 | 新消息直接按现有人工客服流程处理 |
## 16. 安全与合规
- 模型调用由后端完成,所有工具调用必须复用登录身份和数据权限。
- 订单、地址、手机号等敏感信息按回答需要最小化传输并脱敏。
- 用户输入、模型输出和工具结果进行安全审查。
- 保存模型调用审计记录,支持按会话追溯。
- 用户删除本人聊天记录不等于删除平台审计记录,具体保留周期需由公司隐私政策确定。
- 测试环境和生产环境使用不同密钥、知识库和日志配置。
## 17. 埋点与报表
建议统计:
- AI 会话数、AI 消息数、平均响应时间。
- AI 独立解决率。
- 转人工率和各转人工原因占比。
- 关键词触发率、否定词拦截率、误转人工率。
- 人工首次响应时间和平均等待时间。
- 模型错误率、超时率和 Token 成本。
- 知识库命中率、未命中问题排行。
- 用户“有帮助/没帮助”评价。
## 18. 验收标准
### 18.1 AI 接待
- 新会话默认进入 `AI_ACTIVE`。
- 普通问题由 AI 回复,后台不产生人工提醒和人工未读数。
- AI 消息正确显示 AI 身份、头像、时间和消息状态。
- 商品和订单问题能使用真实结构化数据回答。
### 18.2 转人工
- 输入“人工客服、人工、真人、转人工”等表达后 1 秒内进入待人工状态。
- 输入“不需要人工、先不用真人”等否定表达不转人工。
- 转人工后 AI 不再发送业务回复。
- 后台只产生一次待人工提醒,并显示原因和等待时长。
- 一名客服接入后,其他客服不能重复接入。
- 用户端及时显示人工已接入。
### 18.3 异常
- 模型超时或不可用时消息不丢失。
- 达到失败阈值后自动转人工。
- WebSocket 重连后不重复显示 AI 消息。
- 关闭 AI 开关后现有人工客服功能完整可用。
### 18.4 跨端
- H5、微信小程序和 App 核心状态、消息和转人工行为一致。
- 小程序前端包内不存在模型 API Key。
- 切后台、弱网和网络恢复后会话状态正确。
## 19. 分阶段实施
### 阶段一:基础路由与转人工
- 增加会话状态机。
- 接入一个后端 AI Provider。
- 实现关键词、否定词和固定转人工按钮。
- 后台增加待人工分组、接入和结束服务。
- AI 暂只回答通用知识库问题。
### 阶段二:商城数据工具
- 接入商品、订单、物流和售后只读工具。
- 增加移交摘要。
- 增加知识库管理、调用日志和基础报表。
### 阶段三:灰度和优化
- 先内部账号和测试环境验证。
- 生产环境按 10% → 30% → 50% → 100% 灰度。
- 根据未命中问题和误转案例优化词库、知识库和提示词。
- 达到稳定指标后再评估有限的写操作能力。
## 20. 开发工作量判断
本项目难度为中等。聊天 UI、消息持久化和 WebSocket 已经具备,主要工作不在重新开发聊天页面,而在后端增加会话状态机、AI 编排、推送路由和后台待人工工作流。
推荐开发顺序:
1. 会话状态和消息发送方扩展。
2. 转人工规则与后台提醒路由。
3. AI Provider 和基础问答。
4. 后台接入/结束/交回 AI。
5. 商品、订单等只读工具。
6. 知识库、摘要、日志、报表与灰度。
首期应优先保证转人工可靠和 AI 可随时关闭,再逐步提高 AI 回答能力。
@@ -0,0 +1,82 @@
# Design System
## Overview
HashMall 客服前台采用轻量、克制的移动产品界面。用户在商城浏览或订单处理过程中进入,因此页面应像商城内部的原生工具,而不是独立活动页。默认使用浅色主题,消息阅读区保持低干扰。
## Color
- Brand primary: `#7934F6`
- Brand pressed: `#6426D8`
- Brand soft: `#F2EBFF`
- Page background: `#F5F5F7`
- Surface: `#FFFFFF`
- Primary text: `#1A1A1D`
- Secondary text: `#5F6068`
- Muted text: `#777983`
- Divider: `#E7E7EC`
- Success: `#168A5B`
- Warning: `#A45A00`
- Error: `#C93636`
品牌色只用于主按钮、本人消息气泡、焦点和少量状态标识。客服消息使用白色表面和清晰正文色。
## Typography
使用平台系统无衬线字体。H5 优先 `-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`,小程序沿用系统字体。
- Page title: 17px / 600
- Section or state title: 16px / 600
- Message body: 15px / 400, line-height 1.55
- Supporting text: 13px / 400
- Caption and timestamp: 12px / 400
消息正文允许换行和长字符串断行,不使用装饰性字体。
## Layout
- 页面采用纵向三段结构:状态/导航、可滚动消息区、固定输入区。
- 内容宽度在桌面 H5 最大 720px,移动端占满视口。
- 页面横向安全间距 16px,气泡最大宽度约 76%。
- 使用 4、8、12、16、24px 的间距节奏。
- 输入区适配底部安全区和软键盘,不用固定像素高度锁死页面。
## Components
### Message bubble
- 本人消息:紫色实底、白字,圆角 14px,右上角保留较小圆角以区分方向。
- 客服消息:白色实底、深色文字,可使用 1px 中性边界,不叠加宽阴影。
- 气泡内文本可选中;URL、图片、卡片按明确组件渲染。
### Composer
- 白色表面与顶部细分隔线。
- 文本输入框使用中性浅灰背景,圆角 12px。
- 图片与更多操作使用至少 44px 的触控区。
- 发送按钮使用品牌色;空文本时为明确禁用状态。
### Context card
- 商品或订单上下文在输入区上方单层展示。
- 使用缩略图、两行标题和一组关键元数据,不嵌套卡片。
- 提供“发送”与“移除”两个清晰动作。
### Status feedback
- 连接中、离线、轮询中显示在顶部状态条,状态文字与图标同时变化。
- 发送失败在对应消息旁展示“重新发送”,不使用全屏弹窗。
- 首屏使用消息骨架,空状态提供简短欢迎语和可执行提示。
## Motion
- 状态切换和新消息定位使用 150 至 220ms 的 ease-out。
- 不做页面入场编排或弹跳动画。
- 系统启用减少动态效果时取消非必要过渡。
## Responsive and platform behavior
- H5 与微信小程序均使用 uni-app 原生组件。
- Socket 使用 `uni.connectSocket`,图片使用 `uni.chooseMedia`/兼容接口和 `uni.previewImage`。
- H5 处理 `100dvh` 与 iOS 软键盘;小程序处理 `safe-area-inset-bottom`、导航栏和 `cursor-spacing`。
- 不使用浏览器全局 `WebSocket`、DOM 文件选择器或 iframe 作为核心能力。
@@ -0,0 +1,88 @@
# 接入 HashMall 商城
独立项目验证完成后,将 `src/pages/customer-service`、`src/components/customer-service`、`src/api`、`src/services`、`src/config`、`src/adapters` 和客服静态资源合入商城工程。
## 1. 注册页面
建议在商城 `pages.json` 中将客服页放入分包:
```json
{
"root": "pages/customer_service_package",
"pages": [
{
"path": "chat/chat",
"style": {
"navigationBarTitleText": "在线客服",
"navigationBarBackgroundColor": "#FFFFFF",
"navigationBarTextStyle": "black"
}
}
]
}
```
合入分包时需要同步调整 `hashmall.js` 中的 `CHAT_ROUTE` 和页面内 `@/` 引用路径。
## 2. 初始化商城适配
商城启动后设置登录页。应用级 Authorization 应由商城现有配置注入,不要复制到客服源码或提交 Git。
```js
configureHashMallIntegration({
loginPage: '/pages/login_package/login/login',
appAuthorization: Authorization
})
```
客服请求会继续读取商城已有的:
- Token:`fcc-token`
- 用户缓存:`fcc-user-data`
- 用户详情接口:`/user/getUserInfo`
## 3. “我的”页入口
把当前客服电话弹窗或第三方客服跳转替换为:
```js
openCustomerService()
```
## 4. 商品详情入口
```js
openProductConsultation({
goodsId: goods.id,
goodsName: goods.name,
goodsMainGraph: goods.mainGraph,
currentPrice: goods.currentPrice
})
```
页面只把该对象作为待发送预览。正式发送前后端仍需按 `goodsId` 校验并补齐可信商品信息。
## 5. 订单入口
```js
openOrderConsultation({
id: order.id,
orderNo: order.orderNo,
goodsName: order.goodsName,
goodsMainGraph: order.goodsMainGraph,
payAmount: order.payAmount
})
```
正式发送前后端必须校验订单归属当前登录用户。
## 6. 小程序配置
微信公众平台需要配置测试或正式环境的:
- request 合法域名
- socket 合法域名
- uploadFile 合法域名
- downloadFile 合法域名
测试环境 API 为 `https://api.o.tbmall.xin`,Socket 使用对应的 `wss://api.o.tbmall.xin`。
@@ -0,0 +1,37 @@
# Product
## Register
product
## Users
HashMall 已登录会员在浏览商品、查看订单或使用个人中心时,通过 H5 或微信小程序联系平台客服。用户通常带着明确问题进入,需要快速恢复历史会话、提供商品或订单上下文,并在弱网或切换应用后继续沟通。
## Product Purpose
提供 HashMall 自有的跨端客服聊天体验,替代电话号码弹窗和第三方 iframe 客服。产品需要可靠完成文本、图片、商品卡片和订单卡片的双向消息收发,复用现有后台客服工作台,并保证用户身份、会话归属与消息恢复正确。
## Brand Personality
清晰、可靠、克制。界面延续商城现有紫色品牌识别,但客服工具的重点是阅读和处理消息,品牌色只用于关键动作、本人消息和连接状态,不用于大面积装饰。
## Anti-references
- 不做第三方网页嵌套式客服,不使用 iframe 作为核心界面。
- 不模仿社交应用的娱乐化皮肤、夸张气泡或装饰动画。
- 不使用大面积渐变、玻璃拟态、过度圆角和层层卡片。
- 不把网络错误、发送失败和登录失效隐藏在无反馈的加载状态中。
- 不依赖仅在浏览器存在的 API,避免 H5 可用而小程序失效。
## Design Principles
1. 消息优先:视觉层级首先服务于消息阅读、输入和状态判断。
2. 失败可恢复:每个网络动作都有明确状态,草稿、失败消息和断线消息能够恢复。
3. 上下文由用户确认:商品和订单信息先展示,再由用户主动发送。
4. 跨端一致,遵循平台:业务能力一致,键盘、导航、图片选择和返回行为遵循终端习惯。
5. 身份来自可信登录态:页面参数只描述咨询场景,不决定用户身份或数据权限。
## Accessibility & Inclusion
以 WCAG 2.1 AA 为基线。正文和状态文字保持足够对比度;连接、失败和已读状态不只依赖颜色;触控区域不小于 44px;支持系统减少动态效果;消息内容允许系统字体缩放,并兼顾长文本、无图片和慢网用户。
@@ -0,0 +1,506 @@
# HashMall 前台客服系统产品需求文档
> 文档状态:已确认插件化方案,进入开发
> 文档版本:v0.2
> 编制日期:2026-07-16
> 插件目录:`frontend-web/uni_modules/hashmall-customer-service/`
> 目标终端:H5、微信小程序,结构上兼容后续 App 接入
## 1. 文档目的
本文档定义 HashMall 商城前台客服系统的产品范围、用户流程、交互要求、接口依赖、跨端兼容、安全前置条件和验收标准。
客服前台以 `uni_modules` 插件形式直接内嵌现有 `frontend-web` 商城工程,复用宿主登录态、请求封装、页面生命周期和构建流程;不创建、部署或运行独立客服前端服务。
## 2. 项目背景
HashMall 已经完成客服系统的主要后端能力和管理后台客服工作台,商城前台目前仍使用第三方 H5 客服页面或电话号码弹窗,没有接入自有客服会话。
现有前台客服入口包括:
- “我的”页服务工具中的“联系客服”。
- 商品详情页的客服入口。
- 订单列表或订单详情中的售后咨询入口。
- 现有 `pages/rwa_package/setting/kefu.vue` 通过 `iframe` 加载第三方客服 H5。
微信小程序不能沿用当前 `iframe` 方案;即使改用小程序 `web-view`,也会受业务域名、登录态透传、返回导航和页面体验限制。因此新客服前台应采用 uni-app 原生页面与组件实现,不依赖 iframe。
## 3. 现状梳理
### 3.1 已完成的后端能力
当前 `backend/JST-ERP` 分支已经包含:
- 客服会话、客服消息、商品浏览历史数据表和 DAO。
- 用户发送消息、查询历史消息、查询浏览记录、查询订单、记录商品浏览等接口。
- 后台会话列表、会话详情、置顶、删除、消息发送和已读接口。
- `/ws/kefu` 与 `/api/ws/kefu` WebSocket 端点。
- 新消息、会话变化、已读状态变化的实时推送。
- 文本、图片、商品卡片和订单卡片四种消息类型。
### 3.2 已完成的管理后台能力
当前管理后台已经包含:
- 会话列表、置顶、删除、未读数量。
- 客服与会员聊天区。
- 文本、表情和图片消息。
- 会员资料、最近浏览和交易订单侧栏。
- WebSocket 实时刷新与断线重连。
- 图片上传后发送可访问 URL。
### 3.3 前台现状与缺口
当前商城前台:
- 没有自有客服聊天页。
- “我的”页客服入口主要弹出电话联系方式。
- 部分入口跳转到第三方 H5 客服页面。
- 没有复用自有客服消息接口。
- 没有接入自有客服 WebSocket。
- 没有发送商品卡片、订单卡片的完整流程。
- 没有客服消息发送状态、失败重试、断线恢复和历史消息分页体验。
- 商品详情页尚未统一接入客服浏览记录上报。
## 4. 产品目标
### 4.1 核心目标
1. 用户能够从商城关键场景进入自有客服聊天页。
2. 用户与后台客服能够实时收发消息并查看历史记录。
3. H5 与微信小程序保持一致的核心功能和主要视觉体验。
4. 用户可以携带商品或订单上下文发起咨询,减少描述成本。
5. 网络异常、切后台、WebSocket 断开时不丢消息,并能自动恢复。
6. 用户只能访问本人的会话和消息,不能通过修改参数读取他人数据。
### 4.2 成功指标
首期上线后建议关注:
- 客服入口点击至聊天页成功率不低于 99.5%。
- 文本消息发送成功率不低于 99.9%。
- 在线情况下新消息端到端可见时间 P95 不超过 2 秒。
- WebSocket 断线后 10 秒内自动恢复率不低于 99%。
- 由商品或订单场景进入时,上下文卡片发送率可被埋点统计。
- 因身份错误导致的跨用户数据访问事件为 0。
## 5. 用户与使用场景
### 5.1 用户角色
- 已登录会员:使用全部客服能力。
- 未登录访客:可看客服说明;发起聊天时必须先登录。
- 后台客服:使用现有管理后台接收和回复消息,不属于本项目前台开发范围。
首期不支持匿名访客会话,避免设备身份、会话合并和隐私归属问题。
### 5.2 主要场景
1. 通用咨询:用户从“我的 → 联系客服”进入聊天页。
2. 商品咨询:用户从商品详情进入,页面展示待咨询商品,可一键发送商品卡片。
3. 订单咨询:用户从订单详情或售后场景进入,可一键发送订单卡片。
4. 历史追问:用户再次进入客服页,继续原有会话并查看历史消息。
5. 客服回复:页面打开时实时收到;页面关闭后,后续可扩展消息角标或订阅消息提醒。
## 6. 产品范围
### 6.1 P0:首期必须完成
- 登录校验与当前用户识别。
- 单一客服会话的创建或恢复。
- 历史消息加载和向上翻页。
- 文本消息发送与接收。
- 图片选择、压缩、上传、发送与预览。
- WebSocket 连接、心跳、断线重连。
- WebSocket 不可用时 3 至 5 秒轮询兜底。
- 发送中、发送成功、发送失败状态。
- 失败消息手动重试,防止重复发送。
- 商品上下文卡片发送。
- 订单上下文卡片发送。
- H5 与微信小程序兼容。
- 空状态、加载状态、错误状态和网络状态提示。
- 基础埋点和错误日志。
### 6.2 P1:建议紧随首期
- 表情面板。
- 从聊天页主动选择最近浏览商品。
- 从聊天页主动选择历史订单。
- 用户侧未读数量与已读回执。
- “客服正在输入”状态。
- 客服在线状态和服务时间提示。
- 小程序订阅消息或站内消息提醒。
### 6.3 本期不做
- 语音、视频和实时音视频通话。
- 多客服技能组、智能分配和排队系统。
- 机器人客服和知识库问答。
- 消息撤回、引用回复、群聊。
- 客服评价、投诉工单和 SLA 统计。
- 独立访客身份体系。
## 7. 信息架构
独立前台客服项目建议规划以下产品模块:
```text
客服聊天页
├─ 顶部导航与连接状态
├─ 服务时间/系统公告
├─ 历史消息区
│ ├─ 文本消息
│ ├─ 图片消息
│ ├─ 商品卡片
│ ├─ 订单卡片
│ └─ 时间分隔与状态提示
├─ 场景上下文提示条
├─ 消息输入区
│ ├─ 文本输入
│ ├─ 图片选择
│ ├─ 表情入口(P1)
│ └─ 更多功能
├─ 商品选择面板(P1)
├─ 订单选择面板(P1)
└─ 图片预览
```
建议正式接入商城后的页面路由为:
```text
/pages/customer-service/chat
```
建议作为分包页面注册,避免客服资源增加商城主包体积。
## 8. 核心用户流程
### 8.1 进入客服页
1. 用户点击客服入口。
2. 系统检查商城登录态。
3. 未登录时跳转登录页,并记录客服目标页及场景参数。
4. 登录成功后返回客服页。
5. 页面从可信登录态获取当前用户,不从 URL 接收用户 ID。
6. 加载最近一页历史消息和会话信息。
7. 建立 WebSocket 并发送心跳。
8. 若入口携带商品或订单上下文,在输入区上方展示待发送卡片,不自动发送。
### 8.2 发送文本消息
1. 用户输入内容,空白内容不能发送。
2. 前端生成本地消息 ID,立即在消息区展示“发送中”。
3. 调用发送接口。
4. 成功后用服务端消息 ID 替换本地状态。
5. 失败后显示失败标识,点击可重试。
6. 重试必须复用幂等键,避免网络超时导致重复消息。
### 8.3 发送图片消息
1. 用户从相册选择图片或在 H5 选择本地文件。
2. 校验格式、大小与数量。
3. 客户端在支持的终端压缩长边和质量。
4. 先上传到现有文件服务,获得 HTTPS 图片 URL。
5. 再发送 `contentType=2` 的客服消息。
6. 上传或发送失败时允许重试。
7. 首期每次最多选择 1 张,单张原图建议不超过 10 MB,压缩后建议不超过 2 MB。
禁止把大图片 Base64 长期写入 `kefu_message.content`。
### 8.4 发送商品卡片
1. 从商品详情进入时携带 `goodsId`,不得在 URL 携带完整商品价格等可篡改展示数据。
2. 客服页通过商品接口获取最新商品信息。
3. 用户点击“发送商品”后发送 `contentType=10`。
4. 卡片至少展示商品主图、名称、规格或价格、商品状态。
5. 点击卡片返回商品详情;商品下架时显示“商品已失效”。
### 8.5 发送订单卡片
1. 从订单场景进入时携带 `orderId`。
2. 客服页通过有权限校验的订单接口获取当前用户的订单摘要。
3. 用户确认后发送 `contentType=11`。
4. 卡片至少展示商品主图、商品名称、订单号、金额和订单状态。
5. 用户只能发送归属于自己的订单。
### 8.6 实时消息与恢复
1. WebSocket 收到 `kefu_message_type` 后按消息 ID 去重并插入列表。
2. 收到 `kefu_conversation_change` 后更新会话摘要。
3. 收到 `kefu_message_read_status_change` 后更新已读状态。
4. 每 25 至 30 秒发送一次 `ping`,收到 `pong` 视为连接存活。
5. 断线按 2、4、8、15、30 秒退避重连,最大间隔 30 秒。
6. 应用切到前台时立即检查连接,并拉取断线期间的新消息。
7. WebSocket 连续失败后启用 3 至 5 秒轮询;恢复连接后停止轮询。
## 9. 页面与交互要求
### 9.1 顶部区域
- 标题默认“在线客服”。
- 可展示“在线”“连接中”“网络异常”等连接状态。
- 服务时间由配置返回,不在前端硬编码。
- 微信小程序使用原生导航栏或自定义导航栏时必须适配安全区。
### 9.2 消息列表
- 客服消息居左,会员消息居右。
- 连续消息按时间间隔展示时间分隔,建议超过 5 分钟显示一次。
- 首次进入滚动到最新消息。
- 用户主动向上滚动时,新消息到达不得强制抢夺滚动位置,应显示“有新消息”按钮。
- 向上触顶加载更早消息,并保持加载前后的视觉位置。
- 文本必须换行并防止超长字符串撑破布局。
- 图片支持缩略图、加载占位、失败占位和全屏预览。
- 商品、订单卡片需要结构化解析失败兜底,不能因单条脏数据导致整页报错。
### 9.3 输入区
- 支持多行输入,最多显示 4 行后内部滚动。
- 文本长度上限首期建议 1000 字,与后端最终限制保持一致。
- 发送按钮仅在有有效内容时可用。
- 微信小程序需适配键盘顶起、底部安全区和 `cursor-spacing`。
- H5 需兼容 iOS Safari 软键盘造成的可视区域变化。
- 页面销毁时停止计时器、轮询和 Socket,防止重复连接。
### 9.4 状态反馈
- 首屏加载:骨架或明确加载状态。
- 无历史消息:欢迎语及常见咨询提示。
- 发送中:消息旁显示加载状态。
- 发送失败:红色失败标识与重试入口。
- 网络离线:顶部非阻塞提示,不清空输入内容。
- 登录失效:保存未发送草稿,重新登录后恢复。
## 10. 跨端兼容要求
| 能力 | H5 | 微信小程序 | 产品要求 |
|---|---|---|---|
| 页面实现 | uni-app 原生页面 | uni-app 原生页面 | 不使用 iframe 承载核心聊天 |
| 网络请求 | `uni.request` | `uni.request` | API 域名必须配置 HTTPS |
| WebSocket | `uni.connectSocket` | `uni.connectSocket` | 不直接依赖浏览器 `WebSocket` 全局对象 |
| 图片选择 | H5 文件选择 | `uni.chooseMedia`/兼容接口 | 统一封装并限制大小 |
| 图片上传 | `uni.uploadFile` | `uni.uploadFile` | 上传域名加入小程序合法域名 |
| 图片预览 | `uni.previewImage` | `uni.previewImage` | 行为保持一致 |
| 键盘适配 | iOS/Android 浏览器 | 微信键盘与安全区 | 真机验收 |
| 返回行为 | 浏览器/uni 路由 | 小程序页面栈 | 从登录返回时恢复上下文 |
| 域名要求 | HTTPS/WSS | request/socket/upload 合法域名 | 发布前配置完成 |
微信小程序发布前必须在平台后台配置:
- `request` 合法域名。
- `socket` 合法域名。
- `uploadFile` 合法域名。
- `downloadFile` 合法域名(如图片预览需要)。
测试环境建议使用 `https://api.o.tbmall.xin` 和对应 `wss` 地址;正式环境使用正式 API 域名。域名必须由环境配置注入,不允许散落硬编码。
## 11. 当前接口依赖
### 11.1 用户消息接口
| 功能 | 方法 | 当前路径 |
|---|---|---|
| 发送消息 | POST | `/kefu/user/send` |
| 查询会话和消息 | GET | `/kefu/user/messages` |
| 最近浏览 | GET | `/kefu/user/browse-history` |
| 交易订单 | GET | `/kefu/user/orders` |
| 记录商品浏览 | POST | `/kefu/user/browse-record` |
后端同时提供部分兼容路径,但新前台只使用一套规范路径,避免后续维护重复接口。
### 11.2 WebSocket
- 端点:`/ws/kefu` 或代理路径 `/api/ws/kefu`。
- 当前会员连接参数:`userType=member`、`userId`、`mchId`、`conversationId`。
- 心跳输入:字符串 `ping`。
- 心跳响应:`{"type":"pong"}`。
当前事件类型:
| 事件 | 说明 |
|---|---|
| `kefu_connected` | 连接建立成功 |
| `kefu_message_type` | 新客服消息 |
| `kefu_conversation_change` | 会话信息变化 |
| `kefu_message_read_status_change` | 消息已读状态变化 |
### 11.3 消息类型
| `contentType` | 类型 | `content` 建议格式 |
|---:|---|---|
| 1 | 文本 | UTF-8 字符串 |
| 2 | 图片 | HTTPS 图片 URL |
| 10 | 商品卡片 | 版本化 JSON |
| 11 | 订单卡片 | 版本化 JSON |
商品和订单卡片建议增加 `schemaVersion`,并定义稳定字段,避免前后台各自猜测 JSON 结构。
## 12. 上线前后端必须补强项
以下问题不影响原型演示,但属于正式开发和上线的前置条件。
### 12.1 身份与数据权限(阻断上线)
当前用户接口允许客户端直接传 `userId`,且接口描述为免后台登录;WebSocket 也直接信任查询参数中的 `userId`。这会产生读取他人消息、订单或浏览记录的风险。
上线前必须:
1. 用户接口强制校验商城 `HSM-AUTH` 登录态。
2. 后端从认证上下文取得会员 ID,忽略客户端提交的 `userId`。
3. 会话、订单、浏览记录均按认证用户和商户双重校验。
4. WebSocket 握手必须校验短期 token 或商城登录 token,并由服务端解析用户身份。
5. 禁止仅通过 `userType=member&userId=...` 建立会员连接。
6. 限制允许来源,正式环境不应保持 `AllowedOriginPatterns("*")`。
### 12.2 历史消息分页(阻断完整体验)
当前消息按 ID 正序分页,直接请求第一页可能得到最早的 80 条而不是最新消息。需要提供以下任一方案:
- 游标分页:`beforeMessageId` + `limit`,默认返回最新一页。
- 倒序查询最新消息,返回前端后再按时间正序展示。
接口还应支持断线补偿参数 `afterMessageId`,只拉取最后已知消息之后的数据。
### 12.3 幂等与消息状态
发送接口建议新增:
- `clientMessageId`:客户端生成且在用户维度唯一。
- 服务端唯一索引或幂等检查。
- 统一 `createdAt` 服务端时间。
- 明确发送失败错误码。
### 12.4 用户侧已读
当前 `readStatus` 主要表达后台是否已读会员消息,不能完整表达会员是否已读客服回复。若 P1 要展示用户未读角标,需要新增用户侧未读数或双向已读字段及接口。
### 12.5 内容安全与限制
- 后端校验允许的 `contentType`。
- 文本长度限制并过滤危险 HTML,前端不得使用未净化的 `v-html`。
- 图片 URL 只允许可信 CDN/OSS 域名。
- 商品、订单卡片必须由服务端校验归属和关键展示信息。
- 按用户和 IP 做发送频率限制。
- 对恶意内容、重复刷屏和超大请求保留审计日志。
## 13. 前台项目技术边界
插件实现遵循:
- 技术栈与商城统一采用 uni-app,避免维护两套终端代码。
- 客服核心逻辑封装在 `hashmall-customer-service` 组件中,由商城客服页直接承载。
- 请求层复用商城 `HSM-AUTH` 与统一错误处理。
- Socket 层使用 `uni.connectSocket` 封装单例连接。
- 不在组件内硬编码 API、WSS、用户 ID、商户 ID 或客服号码。
- H5 与小程序平台差异通过条件编译或适配器隔离。
- 公共请求、认证和上传能力直接复用宿主工程;平台差异由插件内部适配。
插件代码目录结构:
```text
frontend-web/uni_modules/hashmall-customer-service/
├─ components/
│ ├─ hashmall-customer-service/
│ ├─ kefu-message-item/
│ └─ kefu-context-card/
├─ js_sdk/
│ ├─ api.js
│ └─ kefu-socket.js
├─ static/
├─ docs/
├─ package.json
└─ readme.md
```
## 14. 埋点与可观测性
建议埋点:
- `customer_service_entry_click`:入口与场景来源。
- `customer_service_page_view`:页面打开成功。
- `customer_service_ws_connected`:连接耗时与重连次数。
- `customer_service_message_send`:消息类型、结果、耗时,不记录正文。
- `customer_service_card_send`:商品或订单卡片发送。
- `customer_service_history_load`:分页结果与耗时。
- `customer_service_error`:接口、Socket、解析、上传错误码。
日志和埋点不得记录 token、完整消息正文、订单隐私信息和图片内容。
## 15. 验收标准
### 15.1 功能验收
- 已登录用户能从“我的”、商品、订单三个场景进入客服页。
- 未登录用户被引导登录,登录后能返回原咨询场景。
- 首次进入能创建或恢复会话,并展示最新历史消息。
- 文本消息双向实时送达。
- 图片可选择、上传、发送、接收和预览。
- 商品和订单卡片可发送、正确展示并跳回相应详情。
- 发送失败可重试,网络超时不会生成重复消息。
- 向上滚动能连续加载更早消息且无重复、无跳动。
- WebSocket 断开后自动重连,断线消息能够补齐。
- WebSocket 不可用时轮询兜底可继续收取消息。
- 页面重复进入退出不会产生多个 Socket 或重复轮询。
### 15.2 安全验收
- 修改 URL、请求体或 Socket 参数不能访问其他会员数据。
- 失效 token 无法查询和发送消息。
- 用户不能发送不属于自己的订单卡片。
- 用户不能伪造商品关键字段欺骗后台客服。
- 非法消息类型、超长文本、非可信图片 URL 被后端拒绝。
### 15.3 兼容验收
- 微信开发者工具基础功能通过。
- 至少一台 iOS 微信真机和一台 Android 微信真机通过。
- iOS Safari 与 Android Chrome H5 通过。
- 键盘弹起、图片选择、后台切换、弱网和断网恢复通过。
- 小程序合法域名配置完整,正式包无“域名不合法”错误。
## 16. 实施阶段建议
### 阶段 A:接口收口与安全改造
- 用户接口改为从 token 获取用户身份。
- WebSocket 增加认证。
- 消息分页改为最新页/游标模式。
- 增加发送幂等字段。
- 固化商品、订单卡片协议。
### 阶段 B:独立前台客服 MVP
- 完成登录适配、聊天页、文本、图片、历史消息。
- 完成 WebSocket、心跳、重连、轮询兜底。
- 在 H5 和微信小程序独立联调。
### 阶段 C:商城场景接入
- 替换“我的”页电话弹窗和第三方客服 H5。
- 接入商品详情与订单详情上下文。
- 商品详情统一上报浏览记录。
- 完成小程序分包与合法域名配置。
### 阶段 D:灰度与上线
- 测试环境全链路验收。
- 小范围用户灰度。
- 观察连接率、发送成功率和错误率。
- 达标后全量替换旧客服入口。
## 17. 待产品与研发确认
1. 首期是否只支持平台客服,还是区分平台客服、云仓客服和商家客服。
2. 客服服务时间、非工作时间欢迎语及联系电话由谁配置。
3. 商品和订单卡片是否纳入 P0。
4. 是否需要用户侧消息未读角标和小程序订阅消息。
5. 图片上传沿用哪个现有接口及 OSS/CDN 域名。
6. 客服聊天记录保留期限和用户侧是否允许删除。
7. 旧第三方客服系统是一次性替换,还是保留灰度开关。
8. 独立项目最终以分包、源码模块还是私有组件包的方式并入商城。
## 18. 结论
现有后端与管理后台已经具备客服前台 MVP 所需的大部分业务基础,前台开发的主要工作集中在跨端聊天体验、可靠消息状态、Socket 生命周期和商城场景接入。
正式编码前应优先完成用户身份校验、WebSocket 鉴权和历史消息分页三项后端收口。否则即使前台页面能够运行,也不满足正式上线的数据安全和完整体验要求。