帮你快速理解、总结文档立即下载

客户端定制

最近更新时间:2026-10-30 15:27:00
本文档已由 AI 辅助审校
我的收藏
客户端定制用于配置 WorkBuddy 客户端左侧导航菜单与新建对话页的展示内容,帮助企业规范调整客户端导航、自定义对话页欢迎语,或补充 AI 风险说明时使用,打造统一的客户端界面。

导航菜单

自定义导航菜单配置

登录 企业控制台,在左侧导航栏客户端配置中选择客户端定制。页面默认选中导航菜单页签,可配置 WorkBuddy 桌面端左侧导航菜单,菜单清单与客户端左侧导航 1:1 对齐。
客户端定制-01-导航菜单
客户端定制-01-导航菜单

菜单分为两类:
内置菜单:平台预置的 WorkBuddy 标准功能入口(如新建任务、助理、资料库等),开箱即用,由平台统一维护升级。企业可对其启用 / 关闭、排序、自定义显示名称与图标,但不可移除。
自建菜单:企业通过 iframe 嵌入自有 Web 系统,将企业内部系统(如知识门户、流程系统)接入客户端导航,由企业自行创建、编辑、删除。自建菜单可绑定 OneID 自建应用,成员单击时按登录态自动识别身份并免登进入,无需二次输入账号。
不同菜单类型可编辑的内容如下:
菜单类型
可编辑内容
限制
内置菜单
启用 / 关闭、排序、显示名称(中 / 英文)、图标
不可移除;禁用项不参与排序,沉到列表底部
内置菜单的子菜单
启用 / 关闭、显示名称(中 / 英文)、图标
平台预置,不可移除
自建菜单
菜单名称(中 / 英文)、iframe URL、图标、说明、绑定的 OneID 自建应用
名称需同时填写中英文;iframe URL 必须为 https;绑定自建应用后成员免登进入
说明:
两类菜单整体编辑、整体发布,单击发布后客户端免重新打包生效。
显示名称的自定义仅在本客户端生效;客户端按当前界面语言渲染对应名称(留空则沿用平台默认)。
图标支持 PNG / JPG / SVG,建议 1:1,单文件不超过 200KB。

自建菜单免登录功能配置

企业管理员在企业控制台配置 WorkBuddy 客户端自定义菜单时,可以选择关联自建应用,实现菜单页面访问免登录的能力。关联之后,企业员工通过 WorkBuddy 客户端访问该菜单时,会在 WorkBuddy 内直接打开页面内容,无需再登录一次。

步骤1:创建并配置自建应用

1. 创建自建应用
在自建应用页面单击创建应用,选择应用图标,输入应用名称和应用描述,单击确认,完成创建。
logo:应用图标
名称:应用的名字
描述:一句话说明应用的用途

2. 查看和维护应用信息
完成创建后,会进入应用详情页。系统会自动生成集成所需的凭证信息、端点信息、认证配置以及 Scope 配置,管理员可根据实际需求调整认证配置。
通讯录权限:管理应用可以访问的通讯录范围
Client ID:应用的身份标识
Client Secret:应用凭证

查看自建应用的配置指引
3. 配置免登录地址
单击认证配置模块的编辑入口,配置免登回调地址。

配置项
必填
说明
免登回调地址 sso_entry_uri
是
应用接收免登落地的地址,须 HTTPS,不带 fragment。为空则本能力不可用。

步骤2:编辑自定义菜单,并关联自建应用

1. 新建自定义菜单
在客户端定制页面单击编辑菜单,进入编辑模式,单击新建自定义菜单,打开新建页面。

2. 自定义菜单关联自建应用
在新建页面中,完成菜单信息配置,并发布:
菜单名称(中文):菜单的中文名称。
菜单名称(English):菜单的英文名称,切换英文界面时展示。
iframe URL:单击菜单打开的页面。
绑定自建应用:用于实现免登录及菜单后端服务的自建应用。
上传图标:菜单 icon。
说明:描述菜单的主要功能。


步骤3:应用开发改造

前提:自建应用需允许被 WorkBuddy 嵌入
企业员工登录 WorkBuddy 客户端,打开菜单时,WorkBuddy 会使用员工在 WorkBuddy 登录态 Cookie,请求 WorkBuddy 认证系统获取一次性授权码
(code),并通过菜单关联的自建应用配置,返回免登入口 URL。WorkBuddy 把该 URL 作为页签内容加载。
自建应用需要实现以下能力:
使用接收到的 code 向 WorkBuddy 认证系统换取身份令牌
建立自己的会话
渲染菜单目标页面
1. 接收免登请求
页签加载的地址形态:
{sso_entry_uri}?code=<code>&iss=< WorkBuddy 认证系统>&target_link_uri=<业务目标页>
参数
是否总有
说明
code
是
一次性授权码,60 秒内有效
iss
是
本企业的 WorkBuddy 认证系统签发方标识:https://oauth2.account.tencent.com/authz/oidc/v2/<account_id>
target_link_uri
否
WorkBuddy 指定的页签内落地页,即菜单配置的 iframeURL
2. 用 code 兑换令牌
自建应用在服务端向 WorkBuddy 认证系统发起请求,换取 access_token :
POST {iss}/token

Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)
grant_type=authorization_code
&code=<code>
&redirect_uri=<业务目标页>
成功响应:
{
"token_type": "Bearer",
"expires_in": 7200,
"access_token": "...",
"id_token": "eyJ..."
}

id_token 主要声明:
claim
说明
iss
与落地参数 iss 一致
aud
本应用 client_id
sub
用户在本企业内的唯一标识(稳定,可作为主键)
tid
企业标识
auth_time / amr
用户本次登录的时间与认证方式,可用于敏感操作二次确认
exp / iat
有效期
其他:如需要头像、邮箱、部门等信息时,可以使用 access_token 请求{iss}/userinfo 获取。
3. 页签内落地要求
拿到 id_token 后,按顺序完成:
3.1 校验 id_token 签名(公钥取自 {iss}/.well-known/openid-configuration 的 jwks_uri)、iss、aud、exp;
3.2 建立应用自己的会话
注意:
不要把 code、id_token 继续暴露在页签 URL 上;
3.3 渲染目标页:有 target_link_uri 且校验通过则落到该页,否则渲染首页。
注意:
跳转须留在页签内完成(相对路径或同窗跳转),不要 target=_top / window.top.location;
3.4 兑换失败时不要在页签里弹出应用自己的整页登录。向 WorkBuddy 返回可识别的失败态,由 WorkBuddy 决定提示或引导重新登录。
注意事项
因内容嵌在 WorkBuddy 页签内,应用还须满足:
要求
说明
允许被嵌入
响应头允许 WorkBuddy 父页面嵌入。不要使用 X-Frame-Options: DENY / SAMEORIGIN;Content-Security-Policy 的 frame-ancestors 需包含 WorkBuddy 域名
Cookie 可在嵌入页生效
若会话走 Cookie,须 Secure,且跨域嵌入时使用 SameSite=None。仅 Lax / Strict 时,页签内后续请求可能带不上会话
适配嵌入布局
不要依赖整页顶栏/登录墙;敏感操作的二次确认在页签内完成,不要顶层跳出
4. 登录态失效后重新免登并刷新
从客户端版本 5.11.0 起,WorkBuddy 开放了 wb.reload() 方法:若自建菜单内登录态过期失效,自建菜单页面可调用,WorkBuddy 会重新免登并重建当前菜单页。
相关能力说明:
事项
行为
自建菜单绑定了自建应用
重新换取一次性 login_uri,页面带新 ticket 重新进入
自建菜单未绑定自建应用
按后台配置的 URL 重新加载页面
生效范围
只对发起调用的菜单页生效,并且必须是当前激活的菜单页
节流
同一个菜单页 5 秒内只接受一次,超出会被拒绝(RATE_LIMITED),避免出现“401 → reload → 401”的死循环
存储
WorkBuddy 不会清理页面的 localStorage / Cookie,页面拿到新 ticket 后要自己覆盖旧的登录态
页面切换
新地址准备好之前,Desktop 端会保留旧页面,避免白屏
调用返回
调用成功即表示请求已被接受,当前页面马上会被替换,之后的代码不要再依赖页面状态
不支持的容器
Buddy 工作台等没有提供重载能力的容器会返回 NOT_SUPPORTED
接入方式 A:Embed SDK(推荐)
页面已经引入 WorkBuddy Embed SDK(wb 对象)时使用;
import { wb } from '@genie/workbuddy-core/sdk/embed';
// 裸 HTML 页面可以引入 embed.js,SDK 会自动挂到全局 `wb`


async function relogin(): Promise<void> {
try {
await wb.reload();
// resolve 后当前页面马上会被替换,这里不要再执行业务逻辑
} catch (err: any) {
switch (err?.code) {
case 'RATE_LIMITED': // 5 秒内重复调用
case 'CONFLICT': // 当前菜单页没有处于激活状态
case 'NOT_SUPPORTED': // 所在容器不支持(例如 Buddy 工作台)
default:
showReloginTip(); // 提示用户手动切换菜单或重启客户端
}
}
}
类型签名:
type WBEmbedReload = () => Promise<void>; // 底层 channel:wb:page:reload
接入方式 B:旧版 postMessage 协议
存量页面不方便引入 SDK 时使用。
请求和响应格式:
// 请求(页面 → WorkBuddy)
{ type: 'wb:reload', requestId: string }

// 响应(WorkBuddy → 页面)
{ type: 'wb:reload:response', requestId: string, code: 0 | 1, message: string }
// code = 0:已接受,页面马上会被替换
// code = 1:被拒绝,原因见 message(例如被节流)

发送请求时请使用 window.parent.postMessage。Web 端菜单页在 <iframe> 里,WorkBuddy 在父窗口监听消息;Desktop 端 <webview> 的顶层页面中 window.parent === window,由 preload 转发消息。所以这一种写法两端都能用:
function wbReload(timeoutMs = 3000) {
return new Promise((resolve, reject) => {
const requestId = `reload-${Date.now()}-${Math.random().toString(36).slice(2)}`;
const timer = setTimeout(() => {
window.removeEventListener('message', onMessage);
reject(new Error('wb:reload timeout'));
}, timeoutMs);


function onMessage(event) {
const data = event.data;
if (!data || data.type !== 'wb:reload:response' || data.requestId !== requestId) {
return;
}
clearTimeout(timer);
window.removeEventListener('message', onMessage);
data.code === 0 ? resolve() : reject(new Error(data.message));
}


window.addEventListener('message', onMessage);
window.parent.postMessage({ type: 'wb:reload', requestId }, '*');
});
}
说明:
请求里只有 type 和 requestId,不含敏感数据,所以 targetOrigin 用 '*' 是安全的。WorkBuddy 会校验消息来源(发送方必须是该菜单的 iframe,并且 origin 和菜单配置的 URL 一致),然后只把响应回投给这个来源。
推荐的接入流程:
业务接口返回 401
│
├─ 清理页面里旧的登录态(token / 用户信息)
│
├─ 调用 wb.reload()(或 wb:reload)
│ ├─ 成功 → 等待页面被替换(不要再继续执行)
│ └─ 失败 → 走兜底提示
│
└─ 页面重新进入后:URL 里有 ticket 就优先用 ticket 换登录态,并覆盖本地存储
要点:
优先使用 URL 里的 ticket。WorkBuddy 不会清理存储。如果页面入口逻辑是“本地有 token 就直接用”,重新进入后还会拿到过期的旧 token,然后继续 401。所以要么在调用 reload 之前先清掉旧 token,要么在入口处优先用 URL 里的 ticket。
全局只发一次。多个接口同时返回 401 时,用一个全局标记合并成一次 reload 调用,避免触发节流。
不要自动重试。WorkBuddy 每次重载都会向 OneID 申请一次性 code。如果 reload 之后还是 401(比如应用授权被收回、账号被禁用),应该提示用户,不要循环调用。可以在 sessionStorage 里记录上次调用的时间,短时间内第二次遇到 401 就直接显示兜底提示。
不要把菜单页的 localStorage 当成跨重启的持久登录态。Desktop 端客户端重启后一定会丢失,页面要能在首屏 401 时调用 reload 恢复登录。
示例(SDK 方式)

let reloading = false;
const RELOAD_MARK = '__wb_reload_at__';

export async function handleUnauthorized(): Promise<void> {
if (reloading) { return; }

const last = Number(sessionStorage.getItem(RELOAD_MARK) || 0);
if (Date.now() - last < 30_000) {
showReloginTip(); // 刚重载过还是 401,不再自动重试
return;
}

reloading = true;
sessionStorage.setItem(RELOAD_MARK, String(Date.now()));
localStorage.removeItem('token'); // 换成页面实际使用的 key

try {
await wb.reload();
} catch {
reloading = false;
showReloginTip();
}
}
错误码
场景
SDK(err.code)
旧协议(code / message)
已接受
resolve
code: 0, message: 'ok'
同一菜单页 5 秒内重复调用
RATE_LIMITED
code: 1, message 含 throttled
当前菜单页未激活 / 已脱离菜单
CONFLICT
code: 1, message 含 only available to the active menu page
所在容器不支持(如 Buddy 工作台)
NOT_SUPPORTED
code: 1

新建对话页

登录 企业控制台,在左侧导航栏客户端配置中选择客户端定制,切换页签到新建对话页,可配置客户端对话页的欢迎语、工作模式与胶囊、AI 风险说明。
客户端定制-02-新建对话页
客户端定制-02-新建对话页


对话页欢迎语

自定义主标题:开启后可自定义主标题(中 / 英文,留空则使用产品默认);关闭时沿用产品默认主标题。
显示副标题(默认关闭):开启后在主标题下方展示副标题(中 / 英文)。

工作模式与胶囊

新建对话页可配置成员进入对话页时展示的工作模式入口与二级胶囊。
工作模式:位于上方,是父级入口,如办公、开发、设计。
胶囊:位于对应工作模式下方,是该工作模式的子入口,如办公下的企业微信、创作文档。每个胶囊只能归属一个工作模式。
配置顺序:先建胶囊,再建工作模式。工作模式配置时从已创建的胶囊中勾选归属项,因此胶囊未创建时工作模式无法保存。
未配置时的表现:两个列表都可以全部删除。全部删除后客户端回落为产品默认配置,仍可正常使用,不会出现空对话页。

AI 风险说明

系统固定前缀(始终展示、不可关闭):内容由 AI 生成,仅供参考。
自定义后段:开启后在前缀后追加企业自定义内容,单行展示,仅支持 [文本](URL) 链接语法;关闭时仅展示系统固定前缀。
说明:
主标题、副标题、后段各不超过 100 个字符,超出时无法保存。
页面右侧提供实时预览;草稿不生效,单击发布后客户端免重新打包即时生效。