# 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. 信息架构 独立前台客服项目建议规划以下产品模块: ```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 鉴权和历史消息分页三项后端收口。否则即使前台页面能够运行,也不满足正式上线的数据安全和完整体验要求。