Skip to content

Widget 用户会话列表 ​

发布状态 · 2026-09-14

用户会话列表、消息摘要和未读数已部署至 api.open4x.com 与 widget.open4x.com,生产数据库已升级至 0054。商户仍需完成自己的身份授权、Session 接口和业务验收;本次功能发布不代表 SLA、DPA 或商业生产验收已完成。SDK 仍通过确认版本的交付包提供,不代表公共 npm 包已发布。

Widget 2.3.7 起,用户可查看本人获授权的个人咨询和订单客服会话,不要求每一条都曾在 Widget 中打开。原有有效绑定继续使用;没有绑定的普通客服会话按活动 customer 身份列出,唯一客服接收人时首次打开自动建立绑定,多接收人需商户明确配置。已撤销绑定不自动恢复。详见统一 Session和用户分组。

图片与文件是独立扩展,开通条件见聊天图片与文件。列表 Token 不能直接上传附件。

两种接入方式 ​

如需后端决定个人、客服或管理员身份,前端仍使用同一个 Widget,见统一 Session 接入。

方式用途
Widget 内置列表商户签发用户列表 Token,Widget 自动获取列表、分页和切换
商户自有列表商户后端调用列表 API,自行展示页面;进入会话仍需业务授权及短期 Session

这里的用户是商户网站的用户,不是 Open4X Console 账号。列表不复用租户管理员 Inbox API,也不需要给用户 conversation:supervise。

1. 网站后端签发列表 Token ​

网站实现自己的 POST /api/open4x/customer-session。校验登录、CSRF/来源、速率限制,从服务端登录态取得 external_user_id,然后调用:

http
POST /v1/conversations/customer-session
Authorization: Bearer <服务端 Bridge Key>
Content-Type: application/json

{"external_user_id":"site-a:user-123","ttl_seconds":1800}

需要 conversation:read 和 conversation:write,TTL 为 900–3600 秒。响应:

json
{"data":{"session_token":"<用户列表短期JWT>","expires_in":1800}}

只把此短期 Token 返回给当前用户,设置 Cache-Control: no-store,不记录 Token。它不是 Bridge Key,也不是某一会话的聊天 Token。网站退出或切换账号时必须调用 Widget destroy(),重新登录后签发新 Token。

同一租户的不同网站应给用户 ID 加稳定站点前缀。必须与之前创建 Widget Session 时的 external_user_id 完全一致,不能每次随机生成。

2. Widget 自动显示“我的会话” ​

沿用本地交付的 React 组件,只将 Session 地址指向上一步:

tsx
<Open4XSupportWidget
  sessionUrl="/api/open4x/customer-session"
  widgetUrl="https://widget.open4x.com"
  gatewayUrl="https://api.open4x.com"
  autoOpen
/>

以上为本功能已部署的正式域名。staging 使用配套交付地址,不与生产数据混用。组件仍来自已确认的 SDK 交付包,不保证公共 npm 发布。

Widget 按 Token 类型选择列表或单会话。列表支持加载、空状态、失败重试、分页、返回列表、Token 过期提示;选择会话后重新挂载单会话界面,避免旧消息混入下一会话。列表 Token 仅保留在内存,Loader 使用 URL fragment 而不是查询参数传递 Token。不要把含 Token 的完整浏览器地址分享到聊天或截图。

服务器端 SDK 新增 createCustomerSession、listCustomerConversations;Fetch 框架可使用 createOpen4XCustomerSessionHandler。其 resolve(request) 必须完成商户登录、CSRF 和业务校验,返回可信身份或 null,不能照抄浏览器提供的用户 ID。

3. API 合同 ​

可选左侧栏与入口未读提醒(已发布) ​

已于 2026-09-16 部署至正式 Widget 和 Gateway。使用本地 SDK 的商户需同步更新 SDK 类型与组件;自托管 Widget 的商户需升级静态资源。 使用用户列表 Token 时,宽度超过 620px 会显示左侧会话列表和右侧原有聊天组件;手机与小窗口在列表和聊天之间切换。 showConversationList 默认 true。2.3.7 起设为 false 时隐藏侧栏和返回列表按钮;conversationId 可指定默认会话,没有默认会话时打开最新一条。这只是布局,不改变凭证权限。重新配置为 true 可恢复列表入口。

html
<script src="https://widget.open4x.com/widget.js"
  data-lazy="true"
  data-show-conversation-list="true"
  data-show-unread-badge="true"></script>

从网站后端取得短期列表 Token 后初始化,也可随时修改:

js
Open4XWidget.init(customerSessionToken, {
  gatewayUrl: 'https://api.open4x.com',
  showConversationList: true,
  showUnreadBadge: true
});
Open4XWidget.configure({ showConversationList: false });
const unread = Open4XWidget.getUnreadCount();

React 组件支持同名属性;自定义标签支持 show-conversation-list="false" 和 show-unread-badge="false"。 右下角角标默认开启,超过 99 显示 99+。它统计当前用户全部可访问会话,不只是列表第一页,也不会因为打开窗口就归零。 页面可见且在线时,每 30 秒查询一次;页面隐藏/离线时暂停网络请求,错误时退避,401/403 或 Token 到期时停止,退出/切换账号清除旧计数和请求。 关闭角标同时关闭 Loader 的未读轮询。这里只保证用户列表 Token 的跨会话汇总,单会话 Token 不会获得其他会话权限,也不自动启用该汇总。

http
GET /v1/apps/bot/widget/conversations/unread
Authorization: Bearer <用户列表Token>
json
{"data":{"unread_count":12}}

响应 Cache-Control: no-store;不返回正文、不修改已读记录,不接受浏览器覆盖用户身份。此查询不分页,排除自己发送的消息、内部备注、发给其他人的消息及已撤销会话。沿用 Widget 限流,不承诺即时推送或无限调用。

商户服务端查询 ​

http
GET /v1/conversations/customer-conversations?external_user_id=site-a%3Auser-123&limit=20
Authorization: Bearer <服务端 Bridge Key>

需要 conversation:read,只能从商户服务端使用。Bridge Key 可以查询该租户的不同网站用户,因此商户必须在后端固定为当前登录身份,不能提供任意用户查询代理。

Widget 或自有浏览器 UI 查询 ​

http
GET /v1/apps/bot/widget/conversations?limit=20
Authorization: Bearer <用户列表Token>
json
{
  "data": [{"id":"conv_example","conversation_type":"general_support","status":"open","created_at":"2026-09-14 00:00:00","unread_count":1,"last_message":{"id":"msg_example","text":"您好,您的问题已收到。","created_at":"2026-09-14 01:00:00","sender_role":"support_agent"}}],
  "pagination": {"has_more":false,"next_cursor":null}
}

limit 为 1–100,默认 20。下一页原样传响应的 next_cursor 作为 cursor,不要自行拼接游标。不能通过查询参数改变 Token 中的用户身份。

客服分组扩展 已于 2026-09-16 发布到生产,新增 context_type/context_id,并改为按本人最新可见公开消息时间降序,无消息使用创建时间,同时间按 ID 升序。其他环境请单独确认版本。新消息到来后应刷新第一页,分页不是固定快照。

恢复原聊天 ​

http
POST /v1/apps/bot/widget/conversations/conv_example/session
Authorization: Bearer <用户列表Token>

无请求体。返回 data.conversation_id、data.session_token、data.expires_in。这里返回的是单会话聊天 Token,其有效期不超过列表 Token。复用原有 Chat ID 和服务端收件人,不重新创建会话、不自动恢复被撤销的权限,也不改变已关闭工单的业务状态。

通用错误:400 参数错误;401 Token/签发 Key 失效;403 类型或 Scope 不符;404 会话不存在或不再可访问;409 原收件人为空或失效,需商户重新配置;429 限流。失败时不要扩大权限重试。沿用平台 request_id 和错误规范。

权限和限制 ​

消息摘要与已读 ​

last_message 是该用户最后一条可见消息,按消息序号确定,文本最多前 200 个 Unicode 字符;无可见消息时为 null。这是文本摘录,不是 AI 摘要,无模型调用费。前端必须作为文本渲染,不能作为 HTML。

unread_count 仅统计其他参与者发出的、当前用户可见且尚无已读记录的消息。自己的消息、内部备注和发给其他人的私聊不计数。状态按用户的参与者外部 ID 持久化,可跨设备共享。用户多个身份的会话按实际恢复的活动 Widget 参与者计算。

进入会话或查询历史本身不会清空未读。Widget 在页面可见且消息进入可视区域后批量上报;自有 UI 使用单会话聊天 Token(不是列表 Token 或 Key)调用:

http
POST /v1/apps/bot/widget/read
Authorization: Bearer <单会话聊天Token>
Content-Type: application/json

{"message_ids":["msg_example"]}

每次 1–50 个消息 ID,返回 {"data":{"acknowledged":true}}。不可见、不存在或其他会话的 ID 被忽略,不披露匹配数量。重复提交安全;只标记提交的可见消息,不推进“全部已读”游标,因此尚未加载的旧消息和同时到达的新消息仍保持未读。收件人权限已撤销时拒绝请求。

返回列表或刷新时从服务器重新获取计数;不会仅靠前端乐观归零。429 按 Retry-After 重试,失败期间可能暂时保留未读。接口使用原有已读回执表,无需新增数据库迁移。

  • 仅列出已存在的 Widget Chat,并且活动渠道记录中的外部用户 ID 匹配。仅作为参与者加入但从未创建 Widget Session 的会话不会出现,旧版无参与者绑定的 Bot Chat 不包含在内。
  • 当前参与者必须是活动的 customer 或 creator,租户、渠道、Chat、参与者和删除状态都会复查。
  • 停用/移除参与者、撤销 Chat、停用渠道或安排会话删除后不可恢复;签发 Key 过期、吊销或丢失 Scope 后,列表及派生聊天令牌失效。
  • 未新增单独撤销某个列表 JWT 的接口。退出时清除客户端,令牌到期自动失效;紧急撤销使用 Key 或对应 Chat/参与者权限。Key 撤销会影响使用同一 Key 的其他用户。
  • 列表返回会话 ID、类型、状态、创建时间,以及用户可见的消息摘录、未读数;不返回内部备注、其他人的私聊、订单元数据、客户姓名和附件内容。
  • 如果商户业务权限发生变化,需同步撤销 Open4X 参与者或 Chat;Open4X 无法自行推断订单授权已失效。
  • AI 关闭不影响本功能。浏览器接口使用已有 Widget 限流,商户服务端接口使用实际 Key 配额;不承诺无限调用。

分步 AI 提示词 ​

让 AI 接入用户会话列表
text
请在当前网站接入 Open4X Widget 用户会话列表,保留指定订单的单会话入口。
先读 https://docs.open4x.com/zh/guide/customer-conversation-list 和 https://docs.open4x.com/openapi/open4x.openapi.json,确认本功能已在目标环境部署;未部署只做 mock,不假定生产可用。
在商户后端实现 /api/open4x/customer-session,校验现有登录、CSRF/Origin 和限流;从服务端取得带站点前缀的稳定用户 ID,与原 Widget Session 身份一致。使用服务端 Bridge Key 调用 /v1/conversations/customer-session,只返回短期列表 Token,响应 no-store。密钥不要进前端或日志。
把本地交付的 Open4XSupportWidget 的 sessionUrl 指向此接口。用户退出或切换账号先 destroy,取消旧请求后重新签发。不要直接把管理员 Inbox 接口开放给浏览器。
测试列表、分页、返回及切换后历史恢复、两用户隔离、内部信息不泄露、参与者/渠道/Key 撤销、空列表和过期。原单会话入口也要测试。列表不会自动创建新会话,创建咨询仍走原来的业务入口。
交付代码、配置位置、测试证据和未验证项。不索要完整 Key,不自动发布生产或发送真实消息。