mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-07-09 06:23:36 +08:00
feat(channels): add LINE and Mattermost config
This commit is contained in:
@@ -91,6 +91,43 @@ export default {
|
||||
zalouserAllowFromHint: _('推荐使用 Zalo 用户 ID;只有确认安全时才开启名称匹配。', 'Zalo user IDs are recommended; enable name matching only when you understand the risk.'),
|
||||
zalouserGroupAllowFromPh: _('可选,逗号分隔群组 ID 或精确群名', 'Optional, comma-separated group IDs or exact group names'),
|
||||
zalouserManualLoginHint: _('插件安装并保存配置后,在终端运行此命令完成二维码登录。多账号请追加 --account 账号标识。', 'After installing the plugin and saving config, run this command in your terminal to complete QR login. For multi-account setup, append --account account-id.'),
|
||||
lineDesc: _('接入 LINE Messaging API,支持私聊、群组和 webhook 回调', 'Connect LINE Messaging API with DM, group, and webhook support'),
|
||||
lineGuide1: _('前往 <a href="https://developers.line.biz/console/" target="_blank" rel="noopener">LINE Developers Console</a> 创建或打开 Messaging API Channel', 'Open <a href="https://developers.line.biz/console/" target="_blank" rel="noopener">LINE Developers Console</a> and create or open a Messaging API Channel'),
|
||||
lineGuide2: _('在「Messaging API」页获取 <strong>Channel Access Token</strong>,在「Basic settings」页获取 <strong>Channel Secret</strong>', 'Get <strong>Channel Access Token</strong> from Messaging API and <strong>Channel Secret</strong> from Basic settings'),
|
||||
lineGuide3: _('如果凭证由外部文件或 SecretRef 管理,可分别填写 Token File 与 Secret File', 'If credentials are managed by files or SecretRef, use Token File and Secret File instead'),
|
||||
lineGuide4: _('配置 Webhook URL 指向 Gateway 暴露的 LINE webhook path,并在 LINE 控制台启用 Webhook', 'Set the Webhook URL to the Gateway LINE webhook path and enable Webhook in LINE Console'),
|
||||
lineGuide5: _('设置私信/群组策略与允许列表,保存后面板会安装插件并重载 Gateway', 'Set DM/group policy and allowlists; after saving, the panel installs the plugin and reloads Gateway'),
|
||||
lineGuideFooter: _('<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">LINE 至少需要 Channel Access Token 或 Token File 其中一项,并且需要 Channel Secret 或 Secret File 其中一项。</div>', '<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">LINE requires either Channel Access Token or Token File, and either Channel Secret or Secret File.</div>'),
|
||||
lineAccessTokenPh: _('LINE Channel Access Token', 'LINE Channel Access Token'),
|
||||
lineAccessTokenHint: _('与 Token File 二选一;如果当前值来自 SecretRef,保持占位不变即可保留引用。', 'Use either this or Token File; keep the SecretRef placeholder unchanged to preserve the reference.'),
|
||||
lineTokenFilePh: _('可选,例如 /etc/openclaw/line-token.txt', 'Optional, e.g. /etc/openclaw/line-token.txt'),
|
||||
lineTokenFileHint: _('当 Channel Access Token 由文件管理时填写;在线校验只会直接校验表单 Token。', 'Use this when Channel Access Token is file-managed; online verification only checks the form token directly.'),
|
||||
lineChannelSecretPh: _('LINE Channel Secret', 'LINE Channel Secret'),
|
||||
lineChannelSecretHint: _('与 Secret File 二选一,用于校验 LINE webhook 签名。', 'Use either this or Secret File; used to verify LINE webhook signatures.'),
|
||||
lineSecretFilePh: _('可选,例如 /etc/openclaw/line-secret.txt', 'Optional, e.g. /etc/openclaw/line-secret.txt'),
|
||||
lineSecretFileHint: _('当 Channel Secret 由文件管理时填写。', 'Use this when Channel Secret is file-managed.'),
|
||||
lineAllowFromPh: _('可选,逗号分隔 LINE 用户 ID', 'Optional, comma-separated LINE user IDs'),
|
||||
lineAllowFromHint: _('LINE 用户 ID 通常以 U 开头;留空表示按策略默认处理。', 'LINE user IDs usually start with U; leave empty to use policy defaults.'),
|
||||
lineGroupAllowFromPh: _('可选,逗号分隔群组或聊天室 ID', 'Optional, comma-separated group or room IDs'),
|
||||
lineTokenOrFile: _('Channel Access Token 或 Token File', 'Channel Access Token or Token File'),
|
||||
lineSecretOrFile: _('Channel Secret 或 Secret File', 'Channel Secret or Secret File'),
|
||||
mattermostDesc: _('接入自托管 Mattermost,支持私信、频道、slash command 和交互按钮', 'Connect self-hosted Mattermost with DMs, channels, slash commands, and interactions'),
|
||||
mattermostGuide1: _('在 Mattermost 中创建 Bot Account,并复制 Personal Access Token 作为 Bot Token', 'Create a Bot Account in Mattermost and copy its Personal Access Token as Bot Token'),
|
||||
mattermostGuide2: _('填写 Mattermost 站点 Base URL,例如 <code>https://mattermost.example.com</code>', 'Fill the Mattermost site Base URL, for example <code>https://mattermost.example.com</code>'),
|
||||
mattermostGuide3: _('如启用 slash command,配置 Callback Path / URL,并确保 Mattermost 服务端能访问 Gateway', 'If slash commands are enabled, configure Callback Path / URL and ensure the Mattermost server can reach Gateway'),
|
||||
mattermostGuide4: _('自托管内网地址需要显式开启 Private Network 开关,避免误连不受信任地址', 'For self-hosted private-network URLs, explicitly enable Private Network to avoid unsafe internal access'),
|
||||
mattermostGuide5: _('设置私信/频道策略与允许列表,保存后面板会安装插件并重载 Gateway', 'Set DM/channel policy and allowlists; after saving, the panel installs the plugin and reloads Gateway'),
|
||||
mattermostGuideFooter: _('<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">Mattermost 最小配置需要 Bot Token 与 Base URL。</div>', '<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">Mattermost minimally requires Bot Token and Base URL.</div>'),
|
||||
mattermostBotTokenPh: _('Mattermost Bot Personal Access Token', 'Mattermost Bot Personal Access Token'),
|
||||
mattermostBaseUrlHint: _('填写站点根地址,不要包含 /api/v4;末尾斜杠会在运行时自动归一化。', 'Use the site root URL without /api/v4; trailing slash is normalized at runtime.'),
|
||||
mattermostAllowFromPh: _('可选,逗号分隔用户名或用户 ID', 'Optional, comma-separated usernames or user IDs'),
|
||||
mattermostAllowFromHint: _('用户名可带 @;选择“允许所有私信”时会自动加入 *。', 'Usernames may include @; choosing Allow all DMs automatically adds *.'),
|
||||
mattermostGroupAllowFromPh: _('可选,逗号分隔频道 ID 或频道名称', 'Optional, comma-separated channel IDs or channel names'),
|
||||
mattermostCallbackPathHint: _('用于 slash command/交互回调的 Gateway HTTP path。', 'Gateway HTTP path for slash command and interaction callbacks.'),
|
||||
mattermostNameMatching: _('允许名称匹配', 'Allow Name Matching'),
|
||||
mattermostNameMatchingHint: _('关闭时优先使用稳定 ID,避免同名用户或频道误匹配。', 'When disabled, prefer stable IDs to avoid wrong matches with duplicate users or channels.'),
|
||||
mattermostPrivateNetwork: _('允许内网地址', 'Allow Private Network'),
|
||||
mattermostPrivateNetworkHint: _('仅在 Mattermost 部署于可信内网时开启。', 'Enable only when Mattermost is deployed on a trusted private network.'),
|
||||
discordDesc: _('接入 Discord Bot,支持服务器频道和私信', 'Connect a Discord Bot, supports server channels and DMs', '接入 Discord Bot,支援伺服器頻道和私信', 'Discord Bot に接続'),
|
||||
discordGuide1: _('前往 <a href="https://discord.com/developers/applications" target="_blank" rel="noopener">Discord Developer Portal</a> 创建 Application', '前往 <a href="https://discord.com/developers/applications" target="_blank" rel="noopener">Discord Developer Portal</a> 创建 Application', '前往 <a href="https://discord.com/developers/applications" target="_blank" rel="noopener">Discord Developer Portal</a> 建立 Application'),
|
||||
discordGuide2: _('在 Bot 页面点击「Reset Token」获取 <strong>Bot Token</strong>', 'Click "Reset Token" on the Bot page to get the <strong>Bot Token</strong>', '在 Bot 頁面点擊「Reset Token」取得 <strong>Bot Token</strong>'),
|
||||
@@ -127,6 +164,7 @@ export default {
|
||||
groupDisabled: _('禁用群组', 'Disable groups', '停用群組'),
|
||||
allowFromPh: _('可选,逗号分隔用户/频道 ID', 'Optional, comma-separated user/channel IDs', '可選,逗號分隔使用者/頻道 ID'),
|
||||
allowFromHint: _('限制允许的用户或频道 ID,留空不限制', 'Restrict to specific user or channel IDs; leave empty for no restriction', '限制允許的使用者或頻道 ID,留空不限制'),
|
||||
accountName: _('账号名称', 'Account Name'),
|
||||
weixinLabel: _('微信', 'WeChat'),
|
||||
weixinDesc: _('通过 openclaw-weixin 插件接入个人微信', 'Connect personal WeChat via the openclaw-weixin plugin', '通過 openclaw-weixin 外掛接入個人微信'),
|
||||
weixinGuide1: _('本功能基于 <strong>openclaw-weixin</strong> 插件', 'This feature is powered by the <strong>openclaw-weixin</strong> plugin', '本功能基於 <strong>openclaw-weixin</strong> 外掛'),
|
||||
@@ -171,7 +209,7 @@ export default {
|
||||
groupAllRooms: _('所有房间', 'All rooms', '所有房間'),
|
||||
groupAllTeams: _('所有团队', 'All teams', '所有團队'),
|
||||
groupMentionBot: _('仅 @机器人时', 'Only when @bot', '僅 @機器人時'),
|
||||
optionalEg: _('可选,如', 'Optional, e.g.', '可選,如'),
|
||||
optionalEg: _('可选,如 {example}', 'Optional, e.g. {example}', '可選,如 {example}'),
|
||||
editAccountLabel: _('编辑 {id}', 'Edit {id}', '編輯 {id}'),
|
||||
bound: _('已绑定', 'Bound', '已綁定'),
|
||||
notBoundAgent: _('未绑定 Agent', 'No Agent bound', '未綁定 Agent'),
|
||||
|
||||
@@ -195,6 +195,78 @@ const PLATFORM_REGISTRY = {
|
||||
pluginRequired: '@openclaw/zalouser@latest',
|
||||
pluginId: 'zalouser',
|
||||
},
|
||||
line: {
|
||||
label: 'LINE',
|
||||
iconName: 'message-circle',
|
||||
desc: t('channels.lineDesc'),
|
||||
guide: [
|
||||
t('channels.lineGuide1'),
|
||||
t('channels.lineGuide2'),
|
||||
t('channels.lineGuide3'),
|
||||
t('channels.lineGuide4'),
|
||||
t('channels.lineGuide5'),
|
||||
],
|
||||
guideFooter: t('channels.lineGuideFooter'),
|
||||
fields: [
|
||||
{ key: 'channelAccessToken', label: 'Channel Access Token', placeholder: t('channels.lineAccessTokenPh'), secret: true, required: false, hint: t('channels.lineAccessTokenHint') },
|
||||
{ key: 'tokenFile', label: 'Token File', placeholder: t('channels.lineTokenFilePh'), required: false, hint: t('channels.lineTokenFileHint') },
|
||||
{ key: 'channelSecret', label: 'Channel Secret', placeholder: t('channels.lineChannelSecretPh'), secret: true, required: false, hint: t('channels.lineChannelSecretHint') },
|
||||
{ key: 'secretFile', label: 'Secret File', placeholder: t('channels.lineSecretFilePh'), required: false, hint: t('channels.lineSecretFileHint') },
|
||||
{ key: 'webhookPath', label: 'Webhook Path', placeholder: '/line/webhook', required: false },
|
||||
{ key: 'dmPolicy', label: t('channels.dmPolicy'), type: 'select', options: DM_POLICY_OPTIONS, required: false },
|
||||
{ key: 'groupPolicy', label: t('channels.groupPolicy'), type: 'select', options: GROUP_POLICY_OPTIONS(t('channels.groupAllGroups')), required: false },
|
||||
{ key: 'allowFrom', label: 'Allow From', placeholder: t('channels.lineAllowFromPh'), required: false, hint: t('channels.lineAllowFromHint') },
|
||||
{ key: 'groupAllowFrom', label: 'Group Allow From', placeholder: t('channels.lineGroupAllowFromPh'), required: false, hint: t('channels.groupAllowFromHint') },
|
||||
{ key: 'mediaMaxMb', label: 'Media Max MB', placeholder: '50', required: false },
|
||||
{ key: 'responsePrefix', label: 'Response Prefix', placeholder: t('channels.optionalEg', { example: '[AI]' }), required: false },
|
||||
],
|
||||
requiredAny: [
|
||||
{ keys: ['channelAccessToken', 'tokenFile'], label: t('channels.lineTokenOrFile') },
|
||||
{ keys: ['channelSecret', 'secretFile'], label: t('channels.lineSecretOrFile') },
|
||||
],
|
||||
configKey: 'line',
|
||||
pairingChannel: 'line',
|
||||
pluginRequired: '@openclaw/line@latest',
|
||||
pluginId: 'line',
|
||||
},
|
||||
mattermost: {
|
||||
label: 'Mattermost',
|
||||
iconName: 'message-square',
|
||||
desc: t('channels.mattermostDesc'),
|
||||
guide: [
|
||||
t('channels.mattermostGuide1'),
|
||||
t('channels.mattermostGuide2'),
|
||||
t('channels.mattermostGuide3'),
|
||||
t('channels.mattermostGuide4'),
|
||||
t('channels.mattermostGuide5'),
|
||||
],
|
||||
guideFooter: t('channels.mattermostGuideFooter'),
|
||||
fields: [
|
||||
{ key: 'botToken', label: 'Bot Token', placeholder: t('channels.mattermostBotTokenPh'), secret: true, required: true },
|
||||
{ key: 'baseUrl', label: 'Base URL', placeholder: 'https://mattermost.example.com', required: true, hint: t('channels.mattermostBaseUrlHint') },
|
||||
{ key: 'name', label: t('channels.accountName'), placeholder: t('channels.optionalEg', { example: 'ops' }), required: false },
|
||||
{ key: 'dmPolicy', label: t('channels.dmPolicy'), type: 'select', options: DM_POLICY_OPTIONS, required: false },
|
||||
{ key: 'groupPolicy', label: t('channels.groupPolicy'), type: 'select', options: GROUP_POLICY_OPTIONS(t('channels.groupAllChannels'), { mention: true }), required: false },
|
||||
{ key: 'allowFrom', label: 'Allow From', placeholder: t('channels.mattermostAllowFromPh'), required: false, hint: t('channels.mattermostAllowFromHint') },
|
||||
{ key: 'groupAllowFrom', label: 'Group Allow From', placeholder: t('channels.mattermostGroupAllowFromPh'), required: false, hint: t('channels.groupAllowFromHint') },
|
||||
{ key: 'replyToMode', label: 'Reply To Mode', type: 'select', required: false, options: [
|
||||
{ value: '', label: t('channels.policyDefault') },
|
||||
{ value: 'off', label: t('channels.disable') },
|
||||
{ value: 'first', label: 'First' },
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'batched', label: 'Batched' },
|
||||
] },
|
||||
{ key: 'callbackPath', label: 'Slash Callback Path', placeholder: '/api/channels/mattermost/command', required: false, hint: t('channels.mattermostCallbackPathHint') },
|
||||
{ key: 'callbackUrl', label: 'Slash Callback URL', placeholder: 'https://panel.example.com/api/channels/mattermost/command', required: false },
|
||||
{ key: 'dangerouslyAllowNameMatching', label: t('channels.mattermostNameMatching'), type: 'select', options: BOOLEAN_OPTIONS, required: false, hint: t('channels.mattermostNameMatchingHint') },
|
||||
{ key: 'dangerouslyAllowPrivateNetwork', label: t('channels.mattermostPrivateNetwork'), type: 'select', options: BOOLEAN_OPTIONS, required: false, hint: t('channels.mattermostPrivateNetworkHint') },
|
||||
{ key: 'responsePrefix', label: 'Response Prefix', placeholder: t('channels.optionalEg', { example: '[AI]' }), required: false },
|
||||
],
|
||||
configKey: 'mattermost',
|
||||
pairingChannel: 'mattermost',
|
||||
pluginRequired: '@openclaw/mattermost@latest',
|
||||
pluginId: 'mattermost',
|
||||
},
|
||||
discord: {
|
||||
label: 'Discord',
|
||||
iconName: 'hash',
|
||||
@@ -505,7 +577,7 @@ function applyRouteIntent(page, state) {
|
||||
// ── 已配置平台渲染 ──
|
||||
|
||||
// ── 多账号支持的平台:与 OpenClaw 的 accounts/defaultAccount 配置模型保持一致 ──
|
||||
const MULTI_INSTANCE_PLATFORMS = ['telegram', 'discord', 'slack', 'feishu', 'dingtalk', 'dingtalk-connector', 'qqbot', 'zalo', 'zalouser']
|
||||
const MULTI_INSTANCE_PLATFORMS = ['telegram', 'discord', 'slack', 'feishu', 'dingtalk', 'dingtalk-connector', 'qqbot', 'zalo', 'zalouser', 'line', 'mattermost']
|
||||
|
||||
function supportsMessagingMultiAccount(pid) {
|
||||
return MULTI_INSTANCE_PLATFORMS.includes(pid)
|
||||
|
||||
Reference in New Issue
Block a user