Skip to content

安装反馈组件 ​

反馈组件将 FeedLog Agent 接入你的产品。用户可以提问、阅读帮助文章、提交反馈并查看进展。用户侧体验见FeedLog Agent 介绍,工作区配置见配置并上线 Agent。

安装 ​

bash
npm install @feedlog/widget

这个包提供 ES 模块和 TypeScript 类型声明,适用于使用打包器的应用,没有运行时依赖。SDK 显示反馈按钮,并从你的 FeedLog 工作区加载反馈界面。

使用 Coding Agent 接入

将反馈组件接入 Prompt复制到已打开项目的 Coding Agent 中。Agent 会检查代码、完成接入并验证结果。

配置反馈组件 ​

在设置 → 反馈组件中启用组件,然后选择用户的使用方式。

仅使用访客模式 ​

在工作区开启访客提交,并在客户端初始化:

ts
import { createWidget } from '@feedlog/widget'

createWidget({
  baseUrl: 'https://acme.feedlog.ai',
  theme: 'auto',
})

填写你的工作区地址;配置了自定义域名时,也可以使用该域名。访客投票和评论分别由工作区权限控制。仅使用访客模式时,可以跳过下方登录与令牌相关章节。

接入产品已有账号 ​

提供 auth,让用户使用产品里的账号身份。下面的示例需要配合服务端令牌接口:

ts
import { createWidget } from '@feedlog/widget'

createWidget({
  baseUrl: 'https://acme.feedlog.ai',
  auth: {
    getToken: async () => {
      const res = await fetch('/api/feedlog-token')
      if (!res.ok) throw new Error('Token endpoint unavailable')
      const { token } = await res.json()
      if (token === null || (typeof token === 'string' && token.length > 0)) return token
      throw new Error('Invalid token response')
    },
    login: () => new Promise<void>((resolve) => {
      openYourSignInModal({ onClose: resolve })
    }),
  },
  theme: 'auto',
})

openYourSignInModal 代表应用自己的登录方法。用户完成登录或取消时,都需要触发关闭回调。未登录用户能否使用访客模式,由工作区权限决定。

该在哪里调用 ​

在浏览器中,每个页面初始化一次 createWidget()。放在仅客户端运行的入口,例如 Nuxt 的 .client 插件或 React 的 useEffect。服务端渲染时可以导入这个包,初始化只在浏览器中执行。

重复调用会被忽略。后续显示设置通过 updateWidget() 修改。调用 createWidget() 后即可使用控制方法,无需等待组件加载完成。

报告当前登录状态 ​

auth.getToken() 用于报告当前用户。SDK 在打开面板及刷新身份时会调用它,因此这个函数应尽快返回。

返回结果含义组件行为
JWT 字符串已登录,身份由令牌中的 email 确定以该身份建立 FeedLog 会话
null确认未登录清除登录会话,根据工作区权限提供访客访问或登录入口
抛错或 reject临时失败保留会话,在需要时提供重试入口

只有确认未登录时才返回 null

网络错误、超时和异常响应都应抛出错误。这些情况下返回 null 会清除用户缓存的登录会话。

打开应用的登录界面 ​

当用户在组件内选择登录,且 getToken() 确认未登录时,SDK 会调用 auth.login。将它连接到应用已有的登录弹窗、独立窗口或登录路由。

使用弹窗或独立窗口时,返回一个 Promise,在登录交互结束时完成,包括用户取消的情况。等待期间,组件暂时隐藏面板和按钮;交互结束后重新调用 getToken(),再恢复显示。resolve 或 reject 都会结束等待,是否登录成功由获取到的令牌决定。

回调返回 void 时,组件保持显示,并立即重新检查身份。整页跳转时沿用应用自己的返回地址处理;用户在约五分钟内回到页面,反馈面板会重新打开。

会话刷新会静默调用 getToken()。只有用户明确选择登录时,才会打开登录界面。

在服务端签发令牌 ​

在开发者 → 单点登录中创建 SSO 密钥。后端从应用已验证的会话读取用户信息,使用 HS256 签名 JWT。email 和 exp 必填,name 和 picture 可选;有效期不能超过 24 小时。

ts
import jwt from 'jsonwebtoken'

export default handler(async (req) => {
  const user = await currentUser(req)
  if (!user) return { token: null }

  return {
    token: jwt.sign(
      { email: user.email, name: user.name, picture: user.avatarUrl },
      process.env.FEEDLOG_SSO_SECRET,
      { algorithm: 'HS256', expiresIn: '1h' },
    ),
  }
})

请将 handler 和 currentUser 替换为你的服务端框架方法。SSO 密钥保留在服务端;签名中的身份字段必须来自已验证的会话,不能直接信任浏览器提交的身份信息。

SDK 会用 JWT 换取 FeedLog 会话并缓存。密钥管理、字段要求和交换错误见单点登录。浏览器单点登录和反馈组件可以复用相同的签名代码与密钥。

自定义入口与显示 ​

反馈面板和悬浮按钮分别控制。打开或关闭面板会保留按钮当前的状态;修改按钮状态,也不会改变面板的开合状态。

用自己的按钮打开反馈 ​

将网站已有的帮助或反馈入口连接到 openWidget():

ts
import { openWidget } from '@feedlog/widget'

document.querySelector('#help-entry')?.addEventListener('click', openWidget)

在入口渲染完成后绑定事件,或使用框架的点击事件处理。如果只想保留自己的入口,在首次 createWidget() 时设置 launcher: { state: 'hidden' }。悬浮按钮隐藏时,openWidget() 仍能打开面板。

业务弹窗打开时关闭面板 ​

应用打开需要占用这块空间的业务弹窗时,调用 closeWidget():

ts
import { closeWidget } from '@feedlog/widget'

function showCheckout() {
  closeWidget()
  openCheckoutDialog()
}

关闭会保留对话和草稿。用户可以通过悬浮按钮或自定义入口再次打开反馈。

跟随应用切换主题 ​

auto 跟随操作系统。应用有自己的主题开关时,在初始化时传入当前的 light 或 dark,并在应用切换主题的回调中更新:

ts
import { updateWidget, type WidgetTheme } from '@feedlog/widget'

function onThemeChange(theme: WidgetTheme) {
  updateWidget({ theme })
}

主题切换不会打断当前对话。组件的品牌色来自 FeedLog 工作区设置。

调整按钮位置和状态 ​

在初始化或调用 updateWidget() 时,通过 launcher 配置:

ts
import { updateWidget } from '@feedlog/widget'

updateWidget({
  launcher: { alignment: 'left', bottomOffset: 80, sideOffset: 20 },
})

将 launcher.state 设为 button、tab 或 hidden,分别显示悬浮按钮、显示贴边的 Help 标签或隐藏入口。例如:

ts
updateWidget({ launcher: { state: 'tab' } })

初始化时,优先使用用户保存的拖动位置,其次是 SDK 中指定的位置字段,再次是工作区默认值。通过 updateWidget() 明确修改位置,会覆盖保存的拖动位置,未传入的位置字段保持当前值。只修改状态、主题或层级时,会保留按钮位置。

同一个浏览器标签页内,拖动位置和按钮/标签形态在重新加载后保留。隐藏只对当前页面有效,重新加载后恢复按钮。明确传入的 launcher.state 优先于用户保存的状态,因此每次初始化都传入 hidden 时,按钮每次都会隐藏。后台关闭方式控制用户能否关闭按钮及关闭后的行为;应用仍可通过 SDK 明确设置按钮状态。

设置显示层级 ​

按钮和面板共用 zIndex,默认值为 40。可以在初始化时设置,也可以按应用导航栏和弹窗的层级动态调整:

ts
updateWidget({ zIndex: 100 })

具体值根据应用已有的层级安排选择。

在自定义入口显示未读数 ​

在首次 createWidget() 时提供 onUnreadChange,接收组件角标使用的未读数量:

ts
createWidget({
  baseUrl: 'https://acme.feedlog.ai',
  onUnreadChange: (count) => {
    const badge = document.querySelector<HTMLElement>('#help-unread')
    if (!badge) return
    badge.textContent = String(count)
    badge.hidden = count === 0
  },
})

将回调加入已有的那一次初始化;接入产品账号时,同时保留 auth。自己的角标初始设为隐藏,在 SDK 报告数量后显示。回调提供数字,入口自行决定显示格式。

API 与配置参考 ​

四个方法均返回 void。

方法用途
createWidget(options)每个页面初始化一次
openWidget()打开反馈面板
closeWidget()关闭面板,保留对话和草稿
updateWidget(options)更新 theme、zIndex 和 launcher 字段

初始化选项 ​

选项说明
baseUrl必填,包含协议头的工作区地址
auth.getToken提供 auth 时必填,类型为 () => Promise<string | null>
auth.login可选,类型为 () => void | Promise<void>,打开应用登录界面
themelight、dark 或 auto,默认 auto
zIndex0 到 2147483647 的整数,默认 40
launcher下表中的位置和状态字段
onUnreadChange可选的 (count: number) => void,用于自定义未读提示

updateWidget() 按字段合并显示设置,包括 launcher 内的各个字段,未传入的字段保持不变。baseUrl、auth 和 onUnreadChange 在初始化时配置。显示更新不修改后台保存的工作区设置。

按钮选项 ​

字段说明
alignmentleft 或 right,省略时使用工作区设置
bottomOffset非负的 JavaScript 安全整数,单位为 CSS 像素,省略时使用工作区设置
sideOffset非负的 JavaScript 安全整数,单位为 CSS 像素,省略时使用工作区设置
statebutton、tab 或 hidden;省略时,在后台关闭方式允许的情况下恢复用户保存的状态,否则显示按钮

工作区的初始位置为右下角,距底部和侧边各 20 px。桌面端与手机端共用位置设置。SDK 会处理设备安全区域,并将入口保持在可见范围内。Help 标签会紧贴屏幕边缘。

自定义嵌入页面

部署了自定义组件页面时,可以在 createWidget() 中传入 embedPath。默认值为 /widget/embed,需要填写与 baseUrl 同源的绝对路径,例如 /custom-widget。

后台设置与浏览器支持 ​

设置 → 反馈组件控制组件是否启用、默认位置和用户关闭按钮后的行为。SDK 在页面加载时读取这些设置。预览与保存步骤见设置反馈按钮。

组件支持当前版本的 Chrome、Firefox、Safari 和 Edge,样式与宿主页面隔离。桌面端面板根据按钮周围的可用空间放置;屏幕宽度不超过 520 CSS 像素时使用全屏面板。浏览器限制存储时,位置、状态和会话缓存仅在当前页面有效。

Agent 页面上下文 ​

用户发送消息时,组件会提供当前页面路径、标题和 meta description,帮助 Agent 理解所在页面。提供的信息不包含查询参数、URL 片段或页面正文。SPA 切换页面后,下一条消息会使用新的页面信息,无需额外配置。

常见错误

反馈按钮不出现。 检查组件是否启用、初始化是否在客户端执行,以及是否明确设置了 launcher.state: 'hidden'。用户也可能在当前页面中暂时隐藏了按钮。如果控制台出现 could not load widget config,检查 baseUrl 是否指向你的工作区,以及其 /api/widget/config 接口能否访问。

用户间歇性退出登录。 检查令牌接口临时失败时,getToken() 是否抛出了错误,而不是返回 null。

应用已登录,但组件仍提示登录。 查看令牌接口的响应,检查它能否读取应用会话。返回 null 会让组件认为用户未登录。

出现“Feedback could not be loaded.”。 在浏览器网络面板中检查令牌接口和 FeedLog 令牌交换接口的响应。单点登录文档列出了令牌要求和交换错误。

修改默认位置后,按钮没有移动。 用户保存的拖动位置优先于初始配置。应用需要主动移动按钮时,通过 updateWidget() 明确更新位置。

导航栏遮住了反馈组件。 对照应用导航栏和弹窗的层级,调整组件的 zIndex。

开源的反馈收集工具。可以自己部署,也可以用我们托管的版本。