Skip to content

商品、订单与文章选择器 ​

客户点几下就能把「我说的是这个沙发」「我问的是这笔订单」发给客服,省掉来回追问的过程。

做出来是什么样 ​

客户点输入框旁边的 📎(手机上是 ➕),菜单里多出一项「选商品」。点开是一个半屏列表,选中某个商品就直接把商品卡片发给了客服。

列表数据全部由你的系统提供,所以这件事必须写代码,工作台里没有对应的开关。

什么时候用 ​

  • 电商网站,客户咨询往往围绕某件商品或某笔订单
  • 客服需要知道对方在看什么才能给出准确答复
  • 你有商品、订单或文章的数据接口

开始之前 ​

  • 已完成接入代码的接入,能在 window.hecong(cb) 里拿到命令对象
  • 下面的代码片段都写在 window.hecong(function (hc) { ... }) 内部

入口放在哪 ​

整件事分两步:先往输入区加一个入口,再把列表数据交给合从。这一节讲第一步,下面的「两步接上」给完整代码。

两个位置任选,区别在显眼程度,能挂的动作完全一样。

方法位置电脑上手机上什么时候用
hc.registerComposerAction(action)附件面板,收着📎 菜单里追加一项➕ 九宫格里追加一格低频动作,不打扰主流程
hc.registerQuickReply(action)快捷按钮区,常驻输入框正上方那排的末尾同电脑希望客户一眼看到并点它

呈现形态自动适配,你不用判断客户在用什么设备。

js
hc.registerComposerAction({
  id: 'my-order',
  label: '发送我的订单',
  onClick: function () { hc.openPicker('order') }
})

字段说明 ​

字段必填说明
id✅唯一标识。用同一个 id 再注册一次会覆盖前一个
label✅显示文字。多语言需要你自己按客户语言传对应文案
icon内联 SVG 字符串,要以 <svg 开头。不传则用通用图标
onClick✅点击回调

入口追加在末尾,内置的图片、视频、文件排在自定义项前面。注册顺序就是显示顺序,想调整先后,把两行代码对调即可。

移除入口 ​

两个方法都返回一个注销函数:

js
const off = hc.registerComposerAction({ /* … */ })

// 不再需要时
off()

多语言的文字 ​

label 不走聊天窗的语言包,需要你自己判断客户语言后传对应文案:

js
const labels = { 'zh-CN': '发送我的订单', en: 'Send my order' }
hc.registerQuickReply({
  id: 'my-order',
  label: labels[navigator.language] || labels.en,
  onClick: () => hc.openPicker('order')
})

两步接上 ​

第一步,往输入区加一个入口;第二步,把列表数据交给合从。

js
// 1) 加入口 —— 收在附件面板里
hc.registerComposerAction({
  id: 'products',
  label: '选商品',
  onClick: function () { hc.openPicker('product') }
})

// 2) 给数据 —— 客户点开时才去你的接口拿
hc.on('picker:request', function (e) {
  fetch('/api/my-products')
    .then(function (r) { return r.json() })
    .then(function (list) { hc.setPickerData(e.type, list) })
})

入口放在哪 ​

有两个位置可选,用法一样,区别只是显眼程度:

方法入口出现在
registerComposerAction(action)附件面板里(电脑端是回形针菜单的一项,手机端是加号面板的一格)
registerQuickReply(action)输入框正上方那排快捷按钮,比附件面板显眼

两个方法都返回一个注销函数,调用它就把入口撤掉:

js
const off = hc.registerQuickReply({
  id: 'orders',
  label: '选订单',
  onClick: function () { hc.openPicker('order') }
})

off()   // 撤掉这个入口

几条要点:

  • id 相同就是覆盖。重复注册同一个 id 会替换掉之前那个,旧的注销函数不会误删新入口
  • 注册顺序就是显示顺序。附件面板里内置项永远在前、你注册的在后;快捷按钮区不提供排序参数
  • icon 必须是内联 SVG 字符串,以 <svg 开头才会渲染,其他值一律回落到通用图标
  • 缺 id、label 或 onClick 会被静默忽略,注册不报错,只是入口不出现

openPicker 会顺带把聊天窗打开

网页接入渠道上,openPicker() 和 open() 一样会触发聊天窗加载并打开。想在客户没点开聊天窗时先备好数据,用 setPickerData(),它不会打开窗口。

两种供数方式 ​

静态预置 ​

数据量小、页面加载时就已知的场景,直接塞进去:

js
hc.setPickerData('product', [
  {
    title: '示例商品 A',
    description: '规格 / 颜色',
    imageUrl: 'https://example.com/a.jpg',
    price: { amount: 39900, currency: 'CNY' },
    detailUrl: 'https://example.com/p/a'
  }
])

按需加载 ​

数据要调接口取(比如「我的订单」需要登录态),监听 picker:request 事件,在客户真正打开选择器时再拉:

js
hc.on('picker:request', async function (e) {
  if (e.type !== 'order') return
  const orders = await fetch('/api/my-orders').then(r => r.json())
  hc.setPickerData('order', orders.map(function (o) {
    return {
      orderId: o.orderNo,
      title: '订单 ' + o.orderNo,
      total: { amount: o.totalCents, currency: 'CNY' },
      status: o.status,               // pending / paid / shipped / delivered / refunded / cancelled
      createdAt: o.createdAtMs,       // 毫秒时间戳
      items: o.items.map(function (it) {
        return {
          name: it.productName,
          imageUrl: it.coverUrl,
          quantity: it.quantity,
          price: { amount: it.priceCents, currency: 'CNY' }
        }
      }),
      detailUrl: o.detailUrl
    }
  }))
})

客户第一次打开选择器时,聊天窗发现没有缓存数据就会触发这个事件,你回填后列表随即呈现。

字段定义 ​

product(商品)、order(订单)、article(文章),每类最多 50 条,超出部分不会呈现。

三类的字段各不相同,字段名必须完全一致:写错名字的字段会被静默丢弃,不报错、不提示,只表现为卡片上少了图或少了描述。

product 商品卡 ​

字段类型必填含义
titlestring是商品名,≤200 字符
descriptionstring否规格、卖点等,≤2000 字符
imageUrlstring否商品图外链,必须是合法 URL
priceMoney否现价
originalPriceMoney否划线原价
detailUrlstring否商品详情页,客服点击可跳转
productIdstring否你自己的 SKU 编号,≤128 字符
layout'compact' | 'large'否卡片形态,缺省由聊天窗决定

order 订单卡 ​

字段类型必填含义
orderIdstring是订单号,≤128 字符
titlestring是订单标题,≤200 字符
totalMoney是订单总额
status见下是订单状态
createdAtnumber是下单时间,毫秒时间戳
itemsarray是商品行,≤30 条
items[].namestring是商品名
items[].quantitynumber是数量,正整数
items[].priceMoney是单价
items[].imageUrlstring否商品图外链
detailUrlstring否订单详情页

status 取值:pending(待付款)、paid(已付款)、shipped(已发货)、delivered(已送达)、refunded(已退款)、cancelled(已取消)。传其他值会被拒绝。

商品行超过 30 条,这张卡整个发不出去,不是只显示前 30 条。卡片是摘要不是清单,行数多的订单挑主要商品放进去,其余让客服点 detailUrl 看详情。

article 文章卡 ​

字段类型必填含义
titlestring是文章标题,≤200 字符
descriptionstring是摘要,≤2000 字符
urlstring是文章链接
imageUrlstring否封面图外链
sourcestring否来源站点名,≤100 字符

Money 金额 ​

js
{ amount: 39900, currency: 'CNY' }   // ¥399.00
{ amount: 99, currency: 'USD' }      // $0.99

amount 是最小货币单位的整数(人民币为分),不接受浮点数。currency 用 ISO 4217 代码。展示时由聊天窗按客户语言格式化,你不用自己拼货币符号。

图片一律用外链 ​

卡片图只能传 imageUrl,值是你自己的图片地址。

不要传 imageAttachmentId。那是客服在工作台上传素材时才用的字段,服务端会校验附件归属,用它发出去的卡片客户这边发不成功,而且不会有明确的报错提示。

客户选完之后 ​

点中某一项,卡片直接作为一条消息发给客服,你不需要再做任何事。客服在工作台里看到的是完整卡片,能点进 detailUrl。

从你自己的按钮唤起 ​

除了客户点聊天窗里的入口,你也可以程序化打开:

js
hc.openPicker('order')

比如客户是从订单详情页点进来咨询的,就可以在打开聊天窗时直接弹出订单列表。

下一步 ​