docs/prds/remote/channels/channels.md
本文档覆盖「设置 → 远程连接」页面 Channels Tab 的全部功能,包括渠道卡片总览、各 IM 渠道配置(Telegram/Lark/DingTalk/WeChat/WeCom)、Agent/模型选择、配对授权通用流程、扩展渠道支持。 基于静态代码分析和动态 UI 验证综合整理。
WebUI Tab 相关内容见 webui.md。
用户故事:作为用户,我希望在"远程连接"设置页面中浏览所有支持的 IM 渠道,了解每个渠道的状态,并展开配置面板。
正常流程(用户视角):
collapseKeys 默认 true);点击卡片 header 展开详细配置面板渠道列表与排序:
| 顺序 | 渠道 | pluginId | 状态 |
|---|---|---|---|
| 1 | Telegram | telegram_default | active |
| 2 | Lark / Feishu | lark_default | active |
| 3 | DingTalk | dingtalk_default | active |
| 4 | weixin_default | active | |
| 5 | WeCom | wecom_default | active |
| 6+ | 扩展渠道 | 动态(extensionMeta) | active |
| 末尾 | Slack | - | coming_soon |
| 末尾 | Discord | - | coming_soon |
说明:Slack/Discord 若已被扩展渠道实现(extensionTypeSet 包含 slack/discord),则隐藏对应 coming_soon 占位卡片。
异常情况:
channel.getPluginStatus.invoke() 失败:仅记录日志,渠道状态保持初始值(未启用/未连接)channel.pluginStatusChanged.on() 事件推送:实时更新对应渠道的状态(启用/连接/botUsername 等)验收标准:
用户故事:作为用户,我希望通过输入 Telegram Bot Token 连接 Telegram,并管理通过 Telegram 与 AionUi 交互的授权用户。
前置条件:用户已在 Telegram @BotFather 创建 Bot 并获取 Token
正常流程(用户视角):
123456:ABC-DEF...enablePlugin),刷新状态channel.pairingRequested.on 事件推送)tokenLocked tooltip:"请先关闭渠道并删除所有授权用户后才能修改配置")异常情况:
验收标准:
用户故事:作为用户,我希望通过配置飞书应用凭据连接 Lark/飞书,与 AionUi 进行 IM 对话。
前置条件:用户已在飞书开放平台创建应用并获取 App ID 和 App Secret
正常流程(用户视角):
* 标记)* 标记)https://open.feishu.cn/document/develop-an-echo-bot/introduction异常情况:
touched 状态)pluginStatusChanged 事件实时更新(Connected/Error/Connecting 带颜色编码徽标)验收标准:
*用户故事:作为用户,我希望通过配置钉钉应用凭据连接 DingTalk,与 AionUi 进行 IM 对话。
前置条件:用户已在钉钉开放平台创建应用并获取 Client ID 和 Client Secret
正常流程(用户视角):
* 标记)* 标记)异常情况:
验收标准:
用户故事:作为用户,我希望通过微信扫码登录连接 WeChat 渠道,无需手动输入复杂凭据。
正常流程(用户视角):
loading_qr)window.electronAPI.weixinLoginStart() 启动登录weixinLoginOnQR 事件接收 QR 码(base64 data URL)EventSource('/api/channel/weixin/login') SSE 接收事件qr 事件接收 QR 码数据(raw ticket string)QRCodeSVG 组件渲染 QR 码(160x160px)scanned:显示 Spin loading + "Scanned, waiting for confirmation..."enableWeixinPlugin(accountId, botToken) 启用渠道connected:显示绿色对钩 + "Connected" + "Disconnect"按钮登录状态机:
idle → loading_qr → showing_qr → scanned → connected
↑ ↓ ↓ ↓
←─── (error/expired) ←───┴──────────┘
异常情况:
验收标准:
用户故事:作为用户,我希望通过配置企业微信机器人 ID 和密钥连接 WeCom 渠道,使用 WebSocket 长连接模式无需回调 URL。
前置条件:用户已在企业微信管理后台创建应用并获取 Bot ID 和 Secret
正常流程(用户视角):
* 标记,有授权用户时 disabled)* 标记,有授权用户时 disabled)https://developer.work.weixin.qq.com/document/path/101463异常情况:
验收标准:
用户故事:作为用户,我希望为每个 IM 渠道独立选择使用的 Agent,以便不同渠道使用不同的 AI 后端。
正常流程(用户视角):
acpConversation.getAvailableAgents.invoke(),过滤掉 preset Agent){ backend: 'gemini' })ConfigStorage.set('assistant.{platform}.agent', agent) 持久化channel.syncChannelSettings.invoke({ platform, agent }) 同步到后端异常情况:
验收标准:
用户故事:作为用户,我希望为每个 IM 渠道独立设置默认使用的 AI 模型,以便控制不同渠道的回复质量和速度。
前置条件:当前 Agent 为 Gemini 兼容类型(backend === 'gemini' 或 'aionrs')
正常流程(用户视角):
GeminiModelSelector 组件渲染模型下拉选择ConfigStorage.set('assistant.{platform}.defaultModel', { id, useModel }) 持久化channel.syncChannelSettings.invoke({ platform, agent, model }) 同步到后端useChannelModelSelection hook,最多重试 5 次匹配 provider)条件渲染:
异常情况:
验收标准:
用户故事:作为用户,我希望通过配对码机制控制哪些 IM 用户可以与我的 AionUi 交互,保证安全性。
适用渠道:Telegram、Lark、DingTalk、WeChat、WeCom(全部 5 个已实现渠道共享此流程)
正常流程(用户视角):
channel.pairingRequested.on() 实时推送到设置页面displayName,未知则显示"Unknown User")code)+ 复制按钮expiresAt,单位 min)channel.approvePairing.invoke({ code }) → 成功 toast → 用户移入"Authorized Users"channel.userAuthorized.on() 实时推送,自动从 pending 列表移除并添加到 authorized 列表channel.revokeUser.invoke({ userId }) → 成功 toast → 用户从列表移除凭据锁定机制:当 authorizedUsers.length > 0 时,凭据输入框和测试按钮变为 disabled,tooltip 提示"请先关闭渠道并删除所有授权用户后才能修改配置"。此规则适用于 Telegram(Token)、Lark(AppID/Secret)、DingTalk(ClientID/Secret)、WeCom(BotID/Secret)。
异常情况:
验收标准:
用户故事:作为扩展开发者,我希望通过扩展 manifest 注册自定义 IM 渠道,使用动态表单配置凭据。
正常流程(用户视角/开发者视角):
extensionMeta 声明 credentialFields 和 configFields,定义表单字段getPluginStatus 返回的非内置类型中识别isExtension: true)extensionMeta 的字段 schema 动态渲染表单支持的字段类型:
| 类型 | 渲染组件 | 说明 |
|---|---|---|
text | Input | 普通文本输入 |
password | Input[type=password] | 密码输入 |
select | Select | 下拉选择,options 来自 schema |
number | InputNumber | 数值输入 |
boolean | Switch | 开关切换 |
启用前校验:遍历 credentialFields 中 required: true 的字段,若有未填写的(空字符串或 undefined),warning toast 提示"Please fill required field: {fieldLabel}"
特殊处理 — ext-wecom-bot 扩展:当扩展类型为 ext-wecom-bot 时,显示橙色提示横幅说明回调 URL(本机/局域网/公网),包含 WebUI 状态(localUrl/networkUrl)。
异常情况:
extensionMeta.description 或 "No extra configuration required."验收标准:
field.default 初始化┌──────────────────────────────────────────────────────────────────────┐
│ ChannelModalContent.tsx (Channels Tab): │
│ 渠道状态: │
│ ├─ channel.getPluginStatus.invoke() [加载全部渠道状态] │
│ └─ channel.pluginStatusChanged.on() [实时监听状态变更] │
│ 渠道启停: │
│ ├─ channel.enablePlugin.invoke({ pluginId, config }) [启用] │
│ ├─ channel.disablePlugin.invoke({ pluginId }) [禁用] │
│ └─ channel.testPlugin.invoke({ pluginId, token, extraConfig? }) │
│ 配对授权: │
│ ├─ channel.getPendingPairings.invoke() [加载待配对] │
│ ├─ channel.getAuthorizedUsers.invoke() [加载已授权] │
│ ├─ channel.approvePairing.invoke({ code }) [批准] │
│ ├─ channel.rejectPairing.invoke({ code }) [拒绝] │
│ ├─ channel.revokeUser.invoke({ userId }) [撤销] │
│ ├─ channel.pairingRequested.on() [实时配对请求] │
│ └─ channel.userAuthorized.on() [实时授权通知] │
│ Agent/模型: │
│ ├─ acpConversation.getAvailableAgents.invoke() [加载 Agent 列表] │
│ ├─ channel.syncChannelSettings.invoke({ platform, agent, model }) │
│ └─ ConfigStorage.get/set('assistant.{platform}.agent/defaultModel')│
│ WeChat 登录: │
│ ├─ electronAPI.weixinLoginStart() [Electron IPC] │
│ ├─ electronAPI.weixinLoginOnQR/OnScanned/OnDone [IPC 事件] │
│ └─ EventSource('/api/channel/weixin/login') [WebUI SSE] │
└──────────────────────────────────────────────────────────────────────┘
| 触发操作 | Toast 类型 | i18n Key |
|---|---|---|
| 渠道插件启用成功 | success | settings.assistant.pluginEnabled / settings.{platform}.pluginEnabled |
| 渠道插件禁用成功 | success | settings.assistant.pluginDisabled / settings.{platform}.pluginDisabled |
| 渠道插件启用/禁用失败 | error | settings.assistant.enableFailed / settings.{platform}.enableFailed |
| 连接测试成功 | success | settings.assistant.connectionSuccess / settings.lark.connectionSuccess |
| 连接测试失败 | error | settings.assistant.connectionFailed / 后端错误信息 |
| Token 为空测试 | warning | settings.assistant.tokenRequired |
| 凭据为空(Lark/DingTalk/WeCom) | warning | settings.{platform}.credentialsRequired |
| 配对批准成功 | success | settings.assistant.pairingApproved |
| 配对拒绝 | info | settings.assistant.pairingRejected |
| 用户撤销成功 | success | settings.assistant.userRevoked |
| Agent 切换成功 | success | settings.assistant.agentSwitched |
| 模型切换成功 | success | settings.assistant.modelSwitched |
| 模型保存失败 | error | settings.assistant.modelSaveFailed |
| WeChat 登录过期 | warning | settings.weixin.loginExpired |
| WeChat 登录失败 | error | settings.weixin.loginError |
| WeCom 保存启用成功 | success | settings.wecom.pluginEnabled |
| # | 功能点 | 局限描述 | 来源 |
|---|---|---|---|
| 1 | F-WEBUI-13 | Telegram Token 锁定机制依赖 authorizedUsers.length > 0,如果后端授权数据丢失但 Token 实际在用中,用户可能误修改 Token 导致断连 | R2 初稿 |
| 2 | F-WEBUI-16 | WeChat 扫码登录的 EventSource(WebUI 模式)在组件卸载时关闭,但 Electron IPC 模式中 weixinLoginStart 是 await Promise,组件卸载不会取消该 Promise | R2 初稿 |
| 3 | F-WEBUI-18 | Agent 列表通过 acpConversation.getAvailableAgents.invoke() 加载,每个渠道独立调用,无缓存共享(5 个渠道 = 5 次相同 IPC 调用) | R2 初稿 |
| 4 | F-WEBUI-19 | useChannelModelSelection 恢复保存的 provider 时最多重试 5 次,provider 被删除后静默降级为默认模型,无用户提示 | R2 初稿 |
| 5 | F-WEBUI-20 | 配对请求的 expiresAt 由后端生成,UI 显示剩余时间为 Math.ceil((expiresAt - Date.now()) / 60000),无自动倒计时刷新(显示值仅在组件渲染时计算) | R2 初稿 |
| 6 | F-WEBUI-17 | WeCom "Save & Enable" 按钮 warning 提示 "Please save Token and EncodingAESKey first" 与实际字段名 (Bot ID / Secret) 不一致 | R2 初稿 |
| 7 | F-WEBUI-21 | 扩展渠道字段值存储在组件 state(extensionFieldValues),页面离开后丢失;已启用的扩展字段值不从后端恢复显示 | R2 初稿 |