CsSdk 智能客服

智能客服 SDK(带界面版):提供 <re-cs-chat /> 开箱即用组件与无 UI 核心层 createCsSdk,支持 SSE 流式对话、转人工、满意度评价与 WebSocket 坐席推送

演示

9:41

当前版本:v0.2.1(协议版本 sdk_version 0.1.1)。

基于 uni-app x / UTS 实现的智能客服 SDK,提供无 UI 核心层(createCsSdk)与开箱即用的界面组件(<re-cs-chat />),支持 App(Android / iOS / HarmonyOS)、H5、微信小程序 三端。 聊天协议与 Web 版 @reglow/customer-service SDK 完全同源(/api/v1/cs/*,SSE 流式 + WebSocket 坐席推送),同一后端可直接复用。

特性

  • 协议同源:GET /cs/sdk-config(公开配置/FAQ/二维码/联系方式)、POST /cs/chat(SSE 流式对话)、GET /cs/history(历史恢复)、POST /cs/transfer(转人工)、POST /cs/rating(满意度评价)、POST /cs/upload(图片上传)、WS /cs/ws/user(坐席实时消息)。
  • 带界面组件:<re-cs-chat /> 两种形态——float(默认,内置悬浮球 + 工具菜单 + 全屏弹窗聊天)/ page(整页在线客服)。含消息气泡 / 图片 / 流式追加 / 正在输入 / 转人工 / 满意度评价、FAQ 搜索与提问、历史消息恢复,界面功能对照 Web 版 sdk_template.html。
  • 无 UI 核心层:createCsSdk(config) 返回 CsSdk,纯逻辑可独立用于自定义界面。
  • SSE 流式:H5 端 fetch + ReadableStream 逐行解析 data: 增量实时输出;App / 小程序端自动降级为一次性拉取完整 SSE 文本后顺序回调(见下方「SSE 流式的端差异」)。
  • WebSocket 推送:uni.connectSocket + 30s 心跳 ping + 断线指数退避重连(最多 5 次)。
  • 转人工排队(0.2.1):转人工支持坐席并发容量(默认 5)与 FIFO 派单——无在线坐席时保持 AI 模式并提示「当前人工坐席忙」;在线坐席已满时进入排队,展示位次并每 10s 轮询 GET /cs/queue-status,同时接收 WS queue_update 推送实时刷新位次。
  • 会话持久化:session_id 通过 uni.setStorageSync 持久化,二次进入自动 loadHistory 恢复。
  • 极简 Markdown:客服气泡支持 **加粗**、*斜体*、行内 `code`、换行与代码块等宽显示。
  • 隐私友好:optOut() 持久化退出标记,退出后不再发起任何聊天请求。

安装

  1. 将 uni_modules/reglow-cs-sdk 目录复制到项目的 uni_modules/ 下(HBuilderX 插件市场安装亦同)。
  2. 依赖:本插件依赖 uni_modules/reglow-review(easycom 引用其 re-icon / re-button / re-empty / re-dialog / re-fab 基础组件),需一并安装 reglow-review。

快速接入(带界面)

<re-cs-chat> 支持两种形态(mode),按需选用:

① 悬浮版(默认 mode="float")—— 一行接入

内置悬浮球 + 工具菜单(在线客服 / 常见问题 / 扫码咨询 / 联系方式 / 反馈)与全屏弹窗聊天,无需自行拼装:

<re-cs-chat
  app-id="your-app-id"
  api-base="/api/v1"
  visitor-name="微信用户"
  primary-color="#4f46e5"
/>

② 页面版(mode="page")—— 独立「在线客服」整页

宿主在任意入口(个人中心 / 订单页等)跳转到独立客服页;该页内放 mode="page",聊天面板撑满整页(无悬浮球 / 弹窗):

// 宿主入口
uni.navigateTo({ url: '/pages/cs/cs-page' })
<!-- pages/cs/cs-page.uvue -->
<re-cs-chat
  mode="page"
  app-id="your-app-id"
  api-base="/api/v1"
  visitor-name="微信用户"
/>

关于微信开发者工具:工具对「自定义组件内部 position: fixed」渲染不可靠。页面版不受影响(无 fixed,全端可用);悬浮版的悬浮球 / 弹窗若在开发者工具中显示异常,请以真机 / H5 为准。

Props

名称类型默认值说明
appIdstring必填客服应用 ID,对应协议 app_id
apiBasestring''接口前缀。留空时使用 sdk-config 返回的 api_base,仍为空则取 /api/v1。传 /api/v1(同源)或 https://api.xxx.com/api/v1(跨域)均可自动归一
visitorNamestring''访客昵称,随消息与转人工提交
primaryColorstring''主题色,缺省使用 sdk-config.primary_color,再缺省为 #4f46e5
modestring'float'形态:float(悬浮球 + 菜单 + 全屏弹窗)/ page(整页在线客服)
showFabbooleantrue是否显示悬浮球入口(仅 float)
visiblebooleanfalse面板是否可见(受控,仅 float,配合 v-model:visible)
panelstring'chat'当前面板:chat / faq / qr / contact / feedback

Events

名称载荷说明
update:visibleboolean面板显隐变化(点遮罩 / 关闭时回写,用于 v-model:visible,仅 float)
ready{ appName, faqTitle, faqEnabled, hasQr, hasContact, primaryColor }SDK 配置就绪回调

组件方法(可选,命令式)

方法说明
open(panel?: string)打开指定面板(默认 chat)
close()关闭面板
getSdk() / getConfig()取底层 SDK / 服务端配置

组件默认挂载后即创建 SDK 并拉取公开配置;面板打开(或页面版进入)时自动连接 WS 并恢复历史消息。

无 UI 接入(createCsSdk)

import { createCsSdk } from '@/uni_modules/reglow-cs-sdk/utssdk/index.uts'

const sdk = createCsSdk({
  appId: 'your-app-id',
  apiBase: '/api/v1',            // 可选
  visitorName: '微信用户',        // 可选
  onEvent: (event) => {
    // 处理事件:ready / session / stream / message / done /
    //          transfer / agent_online / session_closed / error
  }
})
sdk.init()                        // 异步拉取 /cs/sdk-config
sdk.send('你好')                   // 发文本,SSE 流式回复通过 onEvent('stream') 增量回调
sdk.sendImage('https://.../a.png') // 发图片(先自行调用 /cs/upload 得到 url)
sdk.requestTransfer()             // 转人工
sdk.rate(5, '很满意')              // 满意度评价
sdk.loadHistory()                 // 恢复历史消息
sdk.connectWS()                   // 建立坐席推送通道
sdk.disconnect()                  // 断开 WS(页面卸载时)
sdk.optOut()                      // 退出(持久化)

CsSdk API 与事件

方法

方法说明
init(): Promise<void>拉取 GET /cs/sdk-config 并合并配置(幂等;重复调用安全)
send(text: string): void发送文本,调 POST /cs/chat 并解析 SSE
sendImage(imageUrl: string): void发送图片消息(image_url 字段)
requestTransfer(): Promise<boolean>请求转人工(POST /cs/transfer);返回 false 表示当前无在线坐席(保持 AI 模式),排队中返回 true 并自动开始轮询位次
getQueueStatus(): Promise<CsQueueInfo | null>查询排队状态(GET /cs/queue-status?session_id=)
rate(rating: number, comment?: string): Promise<boolean>满意度评价 1~5(POST /cs/rating)
loadHistory(): Promise<Array<ChatMessage>>拉取 GET /cs/history 恢复历史
connectWS(): void建立用户端 WebSocket(有 session_id 才生效)
disconnect(): void断开 WS 并停止心跳 / 重连
optOut(): void持久化退出标记,此后不再发起请求
optIn(): void恢复
setVisitorName(name: string): void动态设置访客昵称
getSessionId(): string当前会话 ID
getConfig(): CsSdkConfig | null服务端公开配置(init 后可用)
isStreaming(): boolean是否正在等待 SSE 回复

事件(onEvent(event: CsSdkEvent))

event.type载荷触发时机
readycontent(欢迎语)init() 完成,配置就绪
sessionsessionId首条消息后服务端下发会话 ID(已持久化)
streamcontent(增量)SSE 文本增量(H5 实时;App/小程序一次性到达)
done-一轮回复结束
messagemessage(ChatMessage)完整消息(预留,流式回复由 stream + done 表达)
transfercontent(提示文案)、agentName、status、queuePosition、waitingTotal、onlineAgents命中转人工(SSE transfer_required 或手动 requestTransfer)。status=0 无在线坐席保持 AI;status=1 且有 agentId 已接入;status=1 且无 agentId 进入排队
queue_updatecontent(位次提示)、queuePosition、waitingTotal排队位次变化(WS queue_update 推送或 10s 轮询),同一位次只提示一次
agent_onlineagentNameWS 推送坐席在线
session_closedcontentWS 推送人工会话结束
errorcontent请求失败 / SSE error 事件

CsSdkEvent 结构:{ type, content, sessionId, agentName, message, status, queuePosition, waitingTotal, onlineAgents }(无值字段为空串 / null / 0)。

聊天协议(与 Web 版同源)

接口方法说明
{base}/cs/sdk-config?app_id=GET返回 {app_id, app_name, welcome_message, api_base, primary_color, qr_code:{title,desc,url}, contact:{phone,email,online_url,address,business_hours}, faq_enabled, faq_title, faqs:[{id,title,content}]}
{base}/cs/chatPOSTbody {app_id, session_id?, message?, image_url?, visitor_name?};响应 SSE,每行 data: {json},事件序:session → content(可多次)→ handled_by_agent / transfer_required → done / error
{base}/cs/history?session_id=GETlist[{id, session_id, role, content, content_type, image_url, created_at}]
{base}/cs/transferPOSTbody {app_id, session_id?, agent_key?, visitor_name?} → {session_id, status, agent_id, queue_position, waiting_total, online_agents, message}
{base}/cs/queue-status?session_id=GET查询排队状态 → {status, queue_position, waiting_total, online_agents}
{base}/cs/ratingPOSTbody {session_id, rating(1-5), comment?}
{base}/cs/uploadPOSTmultipart file(≤5MB,jpg/png/gif/webp)→ {url}
{base}/cs/ws/user?session_id=WS服务端推送 agent_message / agent_online / queue_update / session_closed;客户端每 30s 发 ping 保活

{base} 为归一化后的接口前缀,即 apiBase 以 /api/v1 结尾时为 apiBase,否则为 apiBase + '/api/v1';默认 /api/v1。

SSE transfer_required 事件同步携带 status / queue_position,AI 自动触发转人工时同样区分「忙 / 排队 / 已接入」;进入排队后 SDK 每 10s 轮询排队状态,坐席接入、会话结束、退出服务或断开连接时自动停止轮询。

SSE 流式的端差异(重要)

完整实时流式(逐字增量)仅在 H5 端可用:#ifdef H5 下使用 fetch + ReadableStream.getReader() 逐行解析 data: 前缀的 SSE 帧,通过 onEvent('stream') 实时增量回调,UI 呈现打字机效果。

App(Android/iOS/HarmonyOS)与微信小程序:uni.request 不支持流式读取,SDK 自动降级为「一次性拉取」——uni.request(dataType: 'text',超时 120s)等待整个 SSE 响应结束后,一次性解析全部 data: 帧并按原顺序触发 stream → done 回调。界面上表现为:发送后显示「正在输入…」,等待完整回复后一次性展示,功能不缺失、仅非实时。

若需要 App / 小程序端实时流式,可自行改造:将 sse.uts 中 #ifndef H5 分支替换为原生 Socket 代理(由后端 / 网关把 SSE 转推给客户端),SDK 其余部分无需改动;或业务侧改为「发送后按需轮询 /cs/history」。

依赖说明

  • 依赖 reglow-review(package.json 的 uni_modules.dependencies 已声明):界面组件以 easycom 复用其 re-icon / re-button / re-empty / re-dialog / re-fab 基础组件。
  • re-chat 家族(re-chat / re-chat-sender / re-chat-message / re-chat-content)的消息模型仅支持纯文本(content: string),无法承载客服图片消息 / 系统提示 / 评分卡片等混合内容,故本插件消息列表与输入区以自绘为主(对照 Web 版气泡样式),基础组件复用上述 re-*;如你的场景只用纯文本,也可自行换用 re-chat 家族。
  • 不改动 reglow-review 与后端任何代码。

Demo

  • 悬浮版页面:pages/cs/cs-sdk(「智能客服 Demo」,一行接入 <re-cs-chat />,右下角悬浮球体验)。
  • 页面版页面:pages/cs/cs-page(「在线客服」整页,<re-cs-chat mode="page" />),由 Demo 页入口跳转进入。

隐私说明

  • optOut() 持久化退出标记,退出后 send / sendImage / requestTransfer / rate / connectWS / loadHistory 均不再发起请求。
  • SDK 不采集输入框内容之外的任何本地数据;访客昵称由业务侧主动传入。