Files
frontend-app/uni_modules/hashmall-customer-service/docs/PRODUCT_REQUIREMENTS.md
T
2026-07-23 14:03:35 +08:00

20 KiB

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/kefu/kefu.vue.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. 信息架构

独立前台客服项目建议规划以下产品模块:

客服聊天页
├─ 顶部导航与连接状态
├─ 服务时间/系统公告
├─ 历史消息区
│  ├─ 文本消息
│  ├─ 图片消息
│  ├─ 商品卡片
│  ├─ 订单卡片
│  └─ 时间分隔与状态提示
├─ 场景上下文提示条
├─ 消息输入区
│  ├─ 文本输入
│  ├─ 图片选择
│  ├─ 表情入口(P1)
│  └─ 更多功能
├─ 商品选择面板(P1)
├─ 订单选择面板(P1)
└─ 图片预览

建议正式接入商城后的页面路由为:

/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 与小程序平台差异通过条件编译或适配器隔离。
  • 公共请求、认证和上传能力直接复用宿主工程;平台差异由插件内部适配。

插件代码目录结构:

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 鉴权和历史消息分页三项后端收口。否则即使前台页面能够运行,也不满足正式上线的数据安全和完整体验要求。