@xmanrui/dsh-im 4.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/lib/client.js +976 -634
- package/lib/index.js +241 -238
- package/package.json +1 -1
- package/plugin-src/client/access-policy-settings.js +351 -0
- package/plugin-src/client/channel-card-meta.js +2 -1
- package/plugin-src/client/channels/dingtalk/api.js +5 -0
- package/plugin-src/client/channels/dingtalk/index.js +1 -0
- package/plugin-src/client/channels/feishu/api.js +5 -0
- package/plugin-src/client/channels/feishu/index.js +1 -0
- package/plugin-src/client/channels/qq/api.js +5 -0
- package/plugin-src/client/channels/qq/index.js +1 -0
- package/plugin-src/client/channels/shared/token-api.js +5 -0
- package/plugin-src/client/channels/shared/token-channel.js +1 -0
- package/plugin-src/client/channels/telegram/api.js +2 -17
- package/plugin-src/client/channels/telegram/index.js +0 -112
- package/plugin-src/client/channels/telegram/styles.js +0 -28
- package/plugin-src/client/channels/wecom/api.js +5 -0
- package/plugin-src/client/channels/wecom/index.js +1 -0
- package/plugin-src/client/channels/weixin/api.js +5 -0
- package/plugin-src/client/channels/weixin/index.js +1 -0
- package/plugin-src/client/channels/whatsapp/api.js +4 -10
- package/plugin-src/client/channels/whatsapp/index.js +1 -125
- package/plugin-src/client/channels/whatsapp/styles.js +0 -25
- package/plugin-src/client/context-enhancement.js +19 -5
- package/plugin-src/client/delivery-settings.js +61 -9
- package/plugin-src/client/i18n.js +61 -2
- package/plugin-src/client/index.js +1 -0
- package/plugin-src/client/styles.js +50 -4
- package/plugin-src/host/channels/dingtalk/production.mjs +12 -1
- package/plugin-src/host/channels/dingtalk/rpc.mjs +11 -0
- package/plugin-src/host/channels/feishu/production.mjs +39 -1
- package/plugin-src/host/channels/feishu/rpc.mjs +19 -2
- package/plugin-src/host/channels/qq/production.mjs +12 -1
- package/plugin-src/host/channels/qq/rpc.mjs +11 -0
- package/plugin-src/host/channels/shared/access-policy-production.mjs +137 -0
- package/plugin-src/host/channels/shared/access-policy-rpc.mjs +17 -0
- package/plugin-src/host/channels/shared/production.mjs +15 -1
- package/plugin-src/host/channels/shared/rpc.mjs +9 -0
- package/plugin-src/host/channels/slack/production.mjs +12 -1
- package/plugin-src/host/channels/slack/rpc.mjs +10 -0
- package/plugin-src/host/channels/telegram/rpc.mjs +2 -49
- package/plugin-src/host/channels/wecom/production.mjs +12 -1
- package/plugin-src/host/channels/wecom/rpc.mjs +11 -0
- package/plugin-src/host/channels/weixin/production.mjs +12 -1
- package/plugin-src/host/channels/weixin/rpc.mjs +11 -0
- package/plugin-src/host/channels/whatsapp/production.mjs +16 -2
- package/plugin-src/host/channels/whatsapp/rpc.mjs +10 -15
- package/plugin-src/host/modern-harness-api.mjs +3 -0
- package/src/channels/dingtalk/dingtalk-bridge.mjs +70 -12
- package/src/channels/dingtalk/dingtalk-runtime.mjs +4 -0
- package/src/channels/discord/discord-runtime.mjs +29 -1
- package/src/channels/feishu/bridge.mjs +207 -82
- package/src/channels/feishu/feishu-cards.mjs +2 -2
- package/src/channels/feishu/feishu-channel.mjs +36 -6
- package/src/channels/feishu/feishu-runtime.mjs +4 -0
- package/src/channels/qq/qq-bridge.mjs +67 -20
- package/src/channels/qq/qq-runtime.mjs +20 -2
- package/src/channels/shared/access-policy.mjs +210 -0
- package/src/channels/shared/bot-workspace-store.mjs +181 -33
- package/src/channels/shared/command-permission.mjs +32 -0
- package/src/channels/shared/compact-command.mjs +5 -2
- package/src/channels/shared/context-enhancement.mjs +9 -4
- package/src/channels/shared/harness-client.mjs +6 -0
- package/src/channels/shared/i18n-en/feishu.mjs +3 -3
- package/src/channels/shared/i18n-en/shared-a.mjs +2 -1
- package/src/channels/shared/i18n-en/shared-b.mjs +6 -3
- package/src/channels/shared/i18n-en/shared-c.mjs +2 -0
- package/src/channels/shared/inbound-access.mjs +43 -0
- package/src/channels/shared/session-title.mjs +74 -0
- package/src/channels/shared/text-harness-bridge.mjs +54 -6
- package/src/channels/shared/workspace-command.mjs +26 -5
- package/src/channels/shared/workspace-session.mjs +28 -2
- package/src/channels/slack/slack-runtime.mjs +4 -0
- package/src/channels/telegram/telegram-runtime.mjs +6 -13
- package/src/channels/wecom/wecom-bridge.mjs +57 -6
- package/src/channels/wecom/wecom-runtime.mjs +4 -0
- package/src/channels/weixin/weixin-bridge.mjs +67 -19
- package/src/channels/weixin/weixin-runtime.mjs +4 -0
- package/src/channels/whatsapp/whatsapp-runtime.mjs +42 -20
|
@@ -4,34 +4,6 @@ const CSS = String.raw`
|
|
|
4
4
|
.dtg-page { --ddt-accent: #229ed9; --ddt-accent-deep: #1687bd; --ddt-accent-wash: #eaf7fd; }
|
|
5
5
|
.dtg-avatar { color: #fff; background: #229ed9; }
|
|
6
6
|
.dtg-avatar svg { display: block; }
|
|
7
|
-
.dtg-access { min-width: 0; width: 100%; max-width: 100%; display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
-
.dtg-accessHeading { position: relative; min-width: 0; max-width: 100%; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; }
|
|
9
|
-
.dtg-accessHeading > strong { min-width: 0; font-size: 13px; overflow-wrap: anywhere; }
|
|
10
|
-
.dtg-accessStatus { min-width: 0; max-width: 100%; flex: 0 1 auto; display: inline-flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }
|
|
11
|
-
.dtg-accessBadge { min-width: 0; max-width: 100%; flex: 0 1 auto; padding: 3px 8px; border-radius: 999px; color: #1687bd; background: #eaf7fd; font-size: 11px; font-weight: 700; overflow-wrap: anywhere; text-align: center; }
|
|
12
|
-
.dtg-accessBadge[data-mode="private-allowlist"] { color: #a15c00; background: #fff3d6; }
|
|
13
|
-
.dtg-accessHelp { position: static; display: inline-flex; flex: none; }
|
|
14
|
-
.dtg-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #229ed9 28%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #1687bd; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; transition: border-color .15s ease, color .15s ease, background .15s ease, box-shadow .15s ease; }
|
|
15
|
-
.dtg-accessHelpButton:hover { border-color: #229ed9; color: #1178a8; background: #eaf7fd; }
|
|
16
|
-
.dtg-accessHelpButton:focus-visible { outline: none; border-color: #229ed9; box-shadow: 0 0 0 3px color-mix(in srgb, #229ed9 18%, transparent); }
|
|
17
|
-
.dtg-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: min(300px, 100%); max-width: 100%; display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
18
|
-
.dtg-accessTooltipItem { display: grid; gap: 2px; }
|
|
19
|
-
.dtg-accessTooltipItem + .dtg-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
|
|
20
|
-
.dtg-accessTooltipItem strong { color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; line-height: 17px; font-weight: 700; }
|
|
21
|
-
.dtg-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; font-weight: 400; }
|
|
22
|
-
.dtg-accessHelp:hover .dtg-accessTooltip, .dtg-accessHelp:focus-within .dtg-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
23
|
-
.dtg-accessField { min-width: 0; max-width: 100%; display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
24
|
-
.dtg-accessField select, .dtg-accessField textarea { min-width: 0; width: 100%; max-width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
25
|
-
.dtg-accessField select { height: 34px; padding: 0 9px; }
|
|
26
|
-
.dtg-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
27
|
-
.dtg-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
|
|
28
|
-
.dtg-accessField > span, .dtg-accessField small { overflow-wrap: anywhere; }
|
|
29
|
-
.dtg-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
|
|
30
|
-
.dtg-accessWarning, .dtg-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
|
|
31
|
-
.dtg-accessWarning { color: #a15c00; }
|
|
32
|
-
.dtg-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
|
|
33
|
-
.dtg-accessActions { min-width: 0; max-width: 100%; display: flex; justify-content: flex-end; flex-wrap: wrap; }
|
|
34
|
-
.dtg-accessActions .ddt-button { max-width: 100%; white-space: normal; }
|
|
35
7
|
`;
|
|
36
8
|
|
|
37
9
|
export function installTelegramStyles() {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WECOM_RPC_CHANNEL = '/wecom';
|
|
@@ -15,6 +16,7 @@ export const WECOM_ENDPOINTS = Object.freeze({
|
|
|
15
16
|
setWorkspace: 'bot.workspace.set',
|
|
16
17
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
17
18
|
setContextEnhancement: 'bot.context-enhancement.set',
|
|
19
|
+
setAccessPolicy: 'bot.access-policy.set',
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
const PROVISION_STATES = new Set(['starting', 'pending', 'refreshing', 'connecting', 'connected', 'failed', 'cancelled']);
|
|
@@ -99,6 +101,9 @@ function normalizeBot(value) {
|
|
|
99
101
|
workspace: text(value.workspace, '', 4_096),
|
|
100
102
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
101
103
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
104
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
105
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
106
|
+
: {}),
|
|
102
107
|
bot: {
|
|
103
108
|
name: text(value.bot?.name, '企业微信机器人', 100),
|
|
104
109
|
appIdMasked: text(value.bot?.appIdMasked, '应用标识已安全保存', 140),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WEIXIN_RPC_CHANNEL = '/weixin';
|
|
@@ -14,6 +15,7 @@ export const WEIXIN_ENDPOINTS = Object.freeze({
|
|
|
14
15
|
setWorkspace: 'bot.workspace.set',
|
|
15
16
|
setAgentPreset: SET_AGENT_PRESET_ENDPOINT,
|
|
16
17
|
setContextEnhancement: 'bot.context-enhancement.set',
|
|
18
|
+
setAccessPolicy: 'bot.access-policy.set',
|
|
17
19
|
});
|
|
18
20
|
|
|
19
21
|
const ACCOUNT_STATES = new Set(['connected', 'connecting', 'offline', 'error']);
|
|
@@ -124,6 +126,9 @@ function normalizeBot(value) {
|
|
|
124
126
|
workspace: string(value.workspace).slice(0, 4_096),
|
|
125
127
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
126
128
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
129
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
130
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
131
|
+
: {}),
|
|
127
132
|
bot: {
|
|
128
133
|
name: string(value.bot.name, '微信机器人'),
|
|
129
134
|
accountIdMasked: string(value.bot.accountIdMasked, '已安全保存'),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeAgentPresetCatalog, normalizeAgentPresetId, SET_AGENT_PRESET_ENDPOINT } from '../../agent-preset.js';
|
|
2
2
|
import { normalizeLastMessageError } from '../../last-message-error.js';
|
|
3
|
+
import { normalizeAccessPolicy } from '../../../../src/channels/shared/access-policy.mjs';
|
|
3
4
|
import { normalizeContextEnhancementConfig } from '../../../../src/channels/shared/context-enhancement.mjs';
|
|
4
5
|
|
|
5
6
|
export const WHATSAPP_RPC_CHANNEL = '/whatsapp';
|
|
@@ -91,16 +92,9 @@ function normalizeBot(value) {
|
|
|
91
92
|
workspace: text(value.workspace, '', 4_096),
|
|
92
93
|
agentPreset: normalizeAgentPresetId(value.agentPreset),
|
|
93
94
|
contextEnhancement: normalizeContextEnhancementConfig(value.contextEnhancement),
|
|
94
|
-
accessPolicy
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
) ? value.accessPolicy.accessMode : 'self-only',
|
|
98
|
-
allowedNumbers: Array.isArray(value.accessPolicy?.allowedNumbers)
|
|
99
|
-
? [...new Set(value.accessPolicy.allowedNumbers.filter((entry) => (
|
|
100
|
-
typeof entry === 'string' && /^[1-9]\d{4,14}$/.test(entry)
|
|
101
|
-
)))]
|
|
102
|
-
: [],
|
|
103
|
-
},
|
|
95
|
+
...(Object.hasOwn(value, 'accessPolicy')
|
|
96
|
+
? { accessPolicy: normalizeAccessPolicy(value.accessPolicy) }
|
|
97
|
+
: {}),
|
|
104
98
|
bot: {
|
|
105
99
|
name: text(value.bot?.name, 'WhatsApp机器人', 100),
|
|
106
100
|
idMasked: text(value.bot?.idMasked, 'WhatsApp账号', 140),
|
|
@@ -31,119 +31,6 @@ import { installWhatsappStyles } from './styles.js';
|
|
|
31
31
|
|
|
32
32
|
const ACTIVE_STATES = new Set(['pending', 'connecting']);
|
|
33
33
|
|
|
34
|
-
function accessPolicyFor(account) {
|
|
35
|
-
const accessMode = ['self-only', 'private-allowlist', 'open'].includes(
|
|
36
|
-
account?.accessPolicy?.accessMode,
|
|
37
|
-
) ? account.accessPolicy.accessMode : 'self-only';
|
|
38
|
-
return {
|
|
39
|
-
accessMode,
|
|
40
|
-
allowedNumbers: Array.isArray(account?.accessPolicy?.allowedNumbers)
|
|
41
|
-
? account.accessPolicy.allowedNumbers : [],
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function allowedNumbersFromText(value) {
|
|
46
|
-
const entries = value.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
|
|
47
|
-
const normalized = entries.map((entry) => entry.replace(/^\+/, ''));
|
|
48
|
-
if (normalized.some((entry) => !/^[1-9]\d{4,14}$/.test(entry))) {
|
|
49
|
-
throw new TypeError('电话号码必须包含国家或地区代码,每行一个。');
|
|
50
|
-
}
|
|
51
|
-
return [...new Set(normalized)];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function WhatsappAccessSettings({ account, busy = false, onSave }) {
|
|
55
|
-
const policy = accessPolicyFor(account);
|
|
56
|
-
const sourceNumbers = policy.allowedNumbers.join('\n');
|
|
57
|
-
const helpId = React.useId();
|
|
58
|
-
const [accessMode, setAccessMode] = React.useState(policy.accessMode);
|
|
59
|
-
const [allowedNumbers, setAllowedNumbers] = React.useState(sourceNumbers);
|
|
60
|
-
const [error, setError] = React.useState(null);
|
|
61
|
-
|
|
62
|
-
React.useEffect(() => {
|
|
63
|
-
setAccessMode(policy.accessMode);
|
|
64
|
-
setAllowedNumbers(sourceNumbers);
|
|
65
|
-
setError(null);
|
|
66
|
-
}, [policy.accessMode, sourceNumbers]);
|
|
67
|
-
|
|
68
|
-
const save = async (event) => {
|
|
69
|
-
event.preventDefault();
|
|
70
|
-
setError(null);
|
|
71
|
-
try {
|
|
72
|
-
const normalized = allowedNumbersFromText(allowedNumbers);
|
|
73
|
-
if (typeof onSave !== 'function') throw new Error('WhatsApp 访问设置暂不可用。');
|
|
74
|
-
await onSave({ accessMode, allowedNumbers: normalized });
|
|
75
|
-
} catch (caught) {
|
|
76
|
-
setError(caught?.message ?? 'WhatsApp 访问设置保存失败。');
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const allowlistEnabled = accessMode === 'private-allowlist';
|
|
81
|
-
const labels = {
|
|
82
|
-
'self-only': '仅自己模式',
|
|
83
|
-
'private-allowlist': '指定联系人模式',
|
|
84
|
-
open: '开放响应模式',
|
|
85
|
-
};
|
|
86
|
-
return h('form', { className: 'dwa-access', onSubmit: save },
|
|
87
|
-
h('div', { className: 'dwa-accessHeading' },
|
|
88
|
-
h('strong', null, '访问设置'),
|
|
89
|
-
h('span', { className: 'dwa-accessStatus' },
|
|
90
|
-
h('span', { className: 'dwa-accessBadge', 'data-mode': policy.accessMode },
|
|
91
|
-
['已生效:', labels[policy.accessMode]]),
|
|
92
|
-
h('span', { className: 'dwa-accessHelp' },
|
|
93
|
-
h('button', {
|
|
94
|
-
type: 'button',
|
|
95
|
-
className: 'dwa-accessHelpButton',
|
|
96
|
-
'aria-label': '查看 WhatsApp 访问模式说明',
|
|
97
|
-
'aria-describedby': helpId,
|
|
98
|
-
}, h('span', { 'aria-hidden': 'true' }, '?')),
|
|
99
|
-
h('span', { id: helpId, className: 'dwa-accessTooltip', role: 'tooltip' },
|
|
100
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
101
|
-
h('strong', null, '仅自己模式'),
|
|
102
|
-
h('span', null, '只响应已绑定 WhatsApp 账号的自聊消息。')),
|
|
103
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
104
|
-
h('strong', null, '指定联系人模式'),
|
|
105
|
-
h('span', null, '响应自聊和白名单联系人的私聊,忽略群聊。')),
|
|
106
|
-
h('span', { className: 'dwa-accessTooltipItem' },
|
|
107
|
-
h('strong', null, '开放响应模式'),
|
|
108
|
-
h('span', null, '响应所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员的提及或回复。')))))),
|
|
109
|
-
h('label', { className: 'dwa-accessField' },
|
|
110
|
-
h('span', null, '模式'),
|
|
111
|
-
h('select', {
|
|
112
|
-
value: accessMode,
|
|
113
|
-
disabled: busy,
|
|
114
|
-
'aria-label': 'WhatsApp 访问模式',
|
|
115
|
-
onChange: (event) => { setAccessMode(event.target.value); setError(null); },
|
|
116
|
-
},
|
|
117
|
-
h('option', { value: 'self-only' }, '仅自己模式(默认)'),
|
|
118
|
-
h('option', { value: 'private-allowlist' }, '指定联系人模式'),
|
|
119
|
-
h('option', { value: 'open' }, '开放响应模式'))),
|
|
120
|
-
allowlistEnabled
|
|
121
|
-
? h('label', { className: 'dwa-accessField' },
|
|
122
|
-
h('span', null, '允许私聊的 WhatsApp 电话号码'),
|
|
123
|
-
h('textarea', {
|
|
124
|
-
value: allowedNumbers,
|
|
125
|
-
disabled: busy,
|
|
126
|
-
rows: 3,
|
|
127
|
-
placeholder: '每行一个含国家或地区代码的号码',
|
|
128
|
-
'aria-label': '允许私聊的 WhatsApp 电话号码',
|
|
129
|
-
onChange: (event) => { setAllowedNumbers(event.target.value); setError(null); },
|
|
130
|
-
}),
|
|
131
|
-
h('small', null, '可以包含开头的 +,保存时会自动移除。'))
|
|
132
|
-
: null,
|
|
133
|
-
allowlistEnabled && allowedNumbers.trim() === ''
|
|
134
|
-
? h('p', { className: 'dwa-accessWarning', role: 'status' },
|
|
135
|
-
'白名单为空;保存后将只接受自聊消息。')
|
|
136
|
-
: null,
|
|
137
|
-
error ? h('p', { className: 'dwa-accessError', role: 'alert' }, error) : null,
|
|
138
|
-
h('div', { className: 'dwa-accessActions' },
|
|
139
|
-
h('button', {
|
|
140
|
-
type: 'submit',
|
|
141
|
-
className: 'ddt-button',
|
|
142
|
-
'data-kind': 'secondary',
|
|
143
|
-
disabled: busy,
|
|
144
|
-
}, busy ? '正在保存…' : '保存访问设置')));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
34
|
const Button = React.forwardRef(function Button(
|
|
148
35
|
{ children, kind = 'secondary', className = '', ...props },
|
|
149
36
|
ref,
|
|
@@ -300,7 +187,6 @@ export function WhatsappAccountCard({
|
|
|
300
187
|
onWorkspaceSave,
|
|
301
188
|
onAgentPresetSave,
|
|
302
189
|
onContextEnhancementSave,
|
|
303
|
-
onAccessPolicySave,
|
|
304
190
|
onRequestRemove,
|
|
305
191
|
onConfirmRemove,
|
|
306
192
|
onCancelRemove,
|
|
@@ -333,6 +219,7 @@ export function WhatsappAccountCard({
|
|
|
333
219
|
botId: account.botId,
|
|
334
220
|
botName: account.bot.name,
|
|
335
221
|
connected: account.connected,
|
|
222
|
+
accessPolicy: account.accessPolicy,
|
|
336
223
|
}))),
|
|
337
224
|
h(WorkspaceEditor, {
|
|
338
225
|
workspace: account.workspace,
|
|
@@ -349,11 +236,6 @@ export function WhatsappAccountCard({
|
|
|
349
236
|
disabled: Boolean(busy),
|
|
350
237
|
onSave: onContextEnhancementSave,
|
|
351
238
|
}),
|
|
352
|
-
h(WhatsappAccessSettings, {
|
|
353
|
-
account,
|
|
354
|
-
busy: Boolean(busy),
|
|
355
|
-
onSave: onAccessPolicySave,
|
|
356
|
-
}),
|
|
357
239
|
h('div', { className: 'ddt-accountFooter dim-cardFooter' },
|
|
358
240
|
h('div', { className: 'dim-cardFooterLayout' },
|
|
359
241
|
h('div', { className: 'ddt-actions dim-cardActions' },
|
|
@@ -617,12 +499,6 @@ export function WhatsappSettingsTab({ rpcCall }) {
|
|
|
617
499
|
WHATSAPP_ENDPOINTS.setContextEnhancement,
|
|
618
500
|
{ botId: account.botId, config },
|
|
619
501
|
),
|
|
620
|
-
onAccessPolicySave: (accessPolicy) => botAction(
|
|
621
|
-
account,
|
|
622
|
-
'access',
|
|
623
|
-
WHATSAPP_ENDPOINTS.setAccessPolicy,
|
|
624
|
-
{ botId: account.botId, ...accessPolicy },
|
|
625
|
-
),
|
|
626
502
|
onRequestRemove: () => setRemoveTarget(account.botId),
|
|
627
503
|
onCancelRemove: () => setRemoveTarget(null),
|
|
628
504
|
onConfirmRemove: async () => {
|
|
@@ -4,31 +4,6 @@ const CSS = String.raw`
|
|
|
4
4
|
.dwa-page { --ddt-accent: #25d366; --ddt-accent-deep: #128c7e; --ddt-accent-wash: #eafbf0; }
|
|
5
5
|
.dwa-avatar { color: #fff; background: #25d366; }
|
|
6
6
|
.dwa-avatar svg { display: block; }
|
|
7
|
-
.dwa-access { display: grid; gap: 10px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 10px; background: var(--dsw-alias-bg-layer-2, #f7f8fa); }
|
|
8
|
-
.dwa-accessHeading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
|
9
|
-
.dwa-accessHeading > strong { font-size: 13px; }
|
|
10
|
-
.dwa-accessStatus { min-width: 0; display: inline-flex; align-items: center; justify-content: flex-end; gap: 6px; }
|
|
11
|
-
.dwa-accessBadge { flex: none; padding: 3px 8px; border-radius: 999px; color: #08785f; background: #eafbf0; font-size: 11px; font-weight: 700; }
|
|
12
|
-
.dwa-accessBadge[data-mode="private-allowlist"] { color: #0f6f8f; background: #eaf7fd; }
|
|
13
|
-
.dwa-accessBadge[data-mode="open"] { color: #a15c00; background: #fff3d6; }
|
|
14
|
-
.dwa-accessHelp { position: relative; display: inline-flex; flex: none; }
|
|
15
|
-
.dwa-accessHelpButton { width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 1px solid color-mix(in srgb, #25d366 34%, var(--dsw-alias-border-l2, #dfe1e5)); border-radius: 50%; color: #128c7e; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-size: 12px; line-height: 1; font-weight: 750; cursor: help; }
|
|
16
|
-
.dwa-accessTooltip { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: 270px; max-width: min(290px, calc(100vw - 48px)); display: grid; gap: 8px; padding: 10px 11px; border: 1px solid var(--dsw-alias-border-l2, #dfe1e5); border-radius: 9px; color: var(--dsw-alias-label-primary, #1f2329); background: var(--dsw-alias-bg-layer-3, #fff); box-shadow: 0 10px 28px rgb(31 35 41 / 16%); opacity: 0; visibility: hidden; transform: translateY(-3px); pointer-events: none; transition: opacity .15s ease, transform .15s ease, visibility .15s ease; }
|
|
17
|
-
.dwa-accessTooltipItem { display: grid; gap: 2px; }
|
|
18
|
-
.dwa-accessTooltipItem + .dwa-accessTooltipItem { padding-top: 8px; border-top: 1px solid var(--dsw-alias-border-l2, #eef0f3); }
|
|
19
|
-
.dwa-accessTooltipItem strong { font-size: 12px; line-height: 17px; }
|
|
20
|
-
.dwa-accessTooltipItem > span { color: var(--dsw-alias-label-secondary, #646a73); font-size: 11px; line-height: 16px; }
|
|
21
|
-
.dwa-accessHelp:hover .dwa-accessTooltip, .dwa-accessHelp:focus-within .dwa-accessTooltip { opacity: 1; visibility: visible; transform: translateY(0); }
|
|
22
|
-
.dwa-accessField { display: grid; gap: 5px; color: var(--dsw-alias-label-primary, #1f2329); font-size: 12px; font-weight: 600; }
|
|
23
|
-
.dwa-accessField select, .dwa-accessField textarea { width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1, #c9cdd4); border-radius: 7px; color: inherit; background: var(--dsw-alias-bg-layer-1, #fff); font: inherit; font-weight: 400; }
|
|
24
|
-
.dwa-accessField select { height: 34px; padding: 0 9px; }
|
|
25
|
-
.dwa-accessField textarea { min-height: 68px; padding: 8px 9px; resize: vertical; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
26
|
-
.dwa-accessField textarea:disabled { color: var(--dsw-alias-label-tertiary, #8f959e); background: var(--dsw-alias-bg-module-platform, #f2f3f5); cursor: not-allowed; resize: none; opacity: 1; }
|
|
27
|
-
.dwa-accessField small { color: var(--dsw-alias-label-secondary, #646a73); font-weight: 400; }
|
|
28
|
-
.dwa-accessWarning, .dwa-accessError { margin: 0; font-size: 12px; line-height: 1.5; }
|
|
29
|
-
.dwa-accessWarning { color: #a15c00; }
|
|
30
|
-
.dwa-accessError { color: var(--dsw-alias-state-error-primary, #d83931); }
|
|
31
|
-
.dwa-accessActions { display: flex; justify-content: flex-end; }
|
|
32
7
|
`;
|
|
33
8
|
|
|
34
9
|
export function installWhatsappStyles() {
|
|
@@ -16,15 +16,28 @@ const FIELD_LABELS = Object.freeze({
|
|
|
16
16
|
conversationType: '会话类型',
|
|
17
17
|
senderId: '发送者标识',
|
|
18
18
|
senderName: '发送者昵称',
|
|
19
|
+
conversationTitle: '会话标题',
|
|
19
20
|
botId: '机器人标识',
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
const FIELD_HELP = Object.freeze({
|
|
24
|
+
senderName: Object.freeze({
|
|
25
|
+
labelKey: 'senderNameHelpLabel',
|
|
26
|
+
text: '该字段不是每个渠道都能提供。当前消息没有发送者昵称时,即使已选择该字段,<dsh_im_source> 中也会省略 senderName。',
|
|
27
|
+
}),
|
|
28
|
+
conversationTitle: Object.freeze({
|
|
29
|
+
labelKey: 'conversationTitleHelpLabel',
|
|
30
|
+
text: '该字段不是每个渠道都能提供。钉钉群聊会带上群名。当前消息没有会话标题时,即使已选择该字段,<dsh_im_source> 中也会省略 conversationTitle。',
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
22
34
|
const SCOPE_COPY = Object.freeze({
|
|
23
35
|
group: Object.freeze({
|
|
24
36
|
title: '群聊',
|
|
25
37
|
enable: '启用',
|
|
26
38
|
fieldsHelpLabel: '查看群聊来源字段说明',
|
|
27
39
|
senderNameHelpLabel: '查看群聊发送者昵称字段说明',
|
|
40
|
+
conversationTitleHelpLabel: '查看群聊会话标题字段说明',
|
|
28
41
|
guidanceLabel: '增强提示词',
|
|
29
42
|
guidanceHelpLabel: '查看群聊增强提示词使用说明',
|
|
30
43
|
guidanceUsage: '用于告诉模型如何使用当前群聊消息的 <dsh_im_source> 来源字段。只填写正文,插件会自动添加 <dsh_im_source_guidance> 成对标签。',
|
|
@@ -35,6 +48,7 @@ const SCOPE_COPY = Object.freeze({
|
|
|
35
48
|
enable: '启用',
|
|
36
49
|
fieldsHelpLabel: '查看私聊来源字段说明',
|
|
37
50
|
senderNameHelpLabel: '查看私聊发送者昵称字段说明',
|
|
51
|
+
conversationTitleHelpLabel: '查看私聊会话标题字段说明',
|
|
38
52
|
guidanceLabel: '增强提示词',
|
|
39
53
|
guidanceHelpLabel: '查看私聊增强提示词使用说明',
|
|
40
54
|
guidanceUsage: '用于告诉模型如何使用当前私聊消息的 <dsh_im_source> 来源字段。只填写正文,插件会自动添加 <dsh_im_source_guidance> 成对标签。',
|
|
@@ -73,7 +87,6 @@ function ContextEnhancementScopeEditor({
|
|
|
73
87
|
const copy = SCOPE_COPY[kind];
|
|
74
88
|
const unavailableId = `${idPrefix}-${kind}-unavailable`;
|
|
75
89
|
const fieldsHelpId = `${idPrefix}-${kind}-fields-help`;
|
|
76
|
-
const senderNameHelpId = `${idPrefix}-${kind}-sender-name-help`;
|
|
77
90
|
const guidanceId = `${idPrefix}-${kind}-guidance`;
|
|
78
91
|
const guidanceHelpId = `${idPrefix}-${kind}-guidance-help`;
|
|
79
92
|
const disabled = busy || !supported;
|
|
@@ -118,16 +131,17 @@ function ContextEnhancementScopeEditor({
|
|
|
118
131
|
}),
|
|
119
132
|
h('span', { className: 'dim-contextFieldText' },
|
|
120
133
|
h('label', { className: 'dim-contextFieldName', htmlFor: fieldId }, FIELD_LABELS[field]),
|
|
121
|
-
field
|
|
134
|
+
FIELD_HELP[field] ? h('span', { className: 'dim-contextHelp dim-contextFieldHelp' },
|
|
122
135
|
h('button', {
|
|
123
136
|
type: 'button', className: 'dim-contextHelpButton dim-contextFieldHelpButton', disabled,
|
|
124
|
-
'aria-label': copy.
|
|
137
|
+
'aria-label': copy[FIELD_HELP[field].labelKey],
|
|
138
|
+
'aria-describedby': `${idPrefix}-${kind}-${field}-help`,
|
|
125
139
|
}, h('span', { 'aria-hidden': 'true' }, '?')),
|
|
126
140
|
h('span', {
|
|
127
|
-
id:
|
|
141
|
+
id: `${idPrefix}-${kind}-${field}-help`,
|
|
128
142
|
className: 'dim-contextTooltip dim-contextFieldTooltip',
|
|
129
143
|
role: 'tooltip',
|
|
130
|
-
},
|
|
144
|
+
}, FIELD_HELP[field].text)) : null,
|
|
131
145
|
h('label', { className: 'dim-contextFieldKey', htmlFor: fieldId }, field)));
|
|
132
146
|
}))),
|
|
133
147
|
h('div', { className: 'dim-contextGuidance dim-contextScopeBlock' },
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
import { AccessPolicySettingsPage } from './access-policy-settings.js';
|
|
3
4
|
import { h, isEnglish, localizeText } from './i18n.js';
|
|
4
5
|
|
|
5
6
|
export const DELIVERY_RPC_CHANNEL = '/dsh-im-delivery';
|
|
@@ -18,6 +19,11 @@ export const DELIVERY_ENDPOINTS = Object.freeze({
|
|
|
18
19
|
test: 'target.test',
|
|
19
20
|
});
|
|
20
21
|
|
|
22
|
+
export const BOT_SETTINGS_TABS = Object.freeze([
|
|
23
|
+
Object.freeze({ id: 'delivery', label: '投递设置' }),
|
|
24
|
+
Object.freeze({ id: 'access', label: '访问设置' }),
|
|
25
|
+
]);
|
|
26
|
+
|
|
21
27
|
const CHANNEL_DEFINITIONS = Object.freeze({
|
|
22
28
|
weixin: {
|
|
23
29
|
label: '微信',
|
|
@@ -532,8 +538,15 @@ function TargetRow({ definition, target, botId, connected, rpcCall, onChanged, o
|
|
|
532
538
|
: null);
|
|
533
539
|
}
|
|
534
540
|
|
|
535
|
-
export function DeliveryTargetSettingsPage({
|
|
541
|
+
export function DeliveryTargetSettingsPage({
|
|
542
|
+
channel,
|
|
543
|
+
account,
|
|
544
|
+
rpcCall,
|
|
545
|
+
accessRpcCall,
|
|
546
|
+
onBack,
|
|
547
|
+
}) {
|
|
536
548
|
const definition = CHANNEL_DEFINITIONS[channel];
|
|
549
|
+
const [activeTabId, setActiveTabId] = React.useState(BOT_SETTINGS_TABS[0].id);
|
|
537
550
|
const [phase, setPhase] = React.useState('loading');
|
|
538
551
|
const [targets, setTargets] = React.useState([]);
|
|
539
552
|
const [suggestionPhase, setSuggestionPhase] = React.useState('idle');
|
|
@@ -543,8 +556,13 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
543
556
|
const [editor, setEditor] = React.useState(null);
|
|
544
557
|
const [saving, setSaving] = React.useState(false);
|
|
545
558
|
const [botCopyState, setBotCopyState] = React.useState(null);
|
|
559
|
+
const [accessPolicy, setAccessPolicy] = React.useState(account.accessPolicy);
|
|
546
560
|
const mounted = React.useRef(true);
|
|
547
561
|
|
|
562
|
+
React.useEffect(() => {
|
|
563
|
+
setAccessPolicy(account.accessPolicy);
|
|
564
|
+
}, [account.botId, account.accessPolicy]);
|
|
565
|
+
|
|
548
566
|
const invoke = React.useCallback(async (endpoint, payload = {}, signal) => {
|
|
549
567
|
if (typeof rpcCall !== 'function') throw new Error('投递目标设置暂不可用。');
|
|
550
568
|
return unwrapRpcResult(await rpcCall(endpoint, payload, signal));
|
|
@@ -654,13 +672,51 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
654
672
|
}
|
|
655
673
|
};
|
|
656
674
|
|
|
675
|
+
const activeTab = BOT_SETTINGS_TABS.find((tab) => tab.id === activeTabId)
|
|
676
|
+
?? BOT_SETTINGS_TABS[0];
|
|
677
|
+
const activeTabDomId = `dim-bot-settings-${activeTab.id}-tab`;
|
|
678
|
+
const activePanelId = `dim-bot-settings-${activeTab.id}-panel`;
|
|
679
|
+
|
|
657
680
|
return h('section', {
|
|
658
681
|
className: 'dim-deliveryPage',
|
|
659
682
|
'aria-label': `${account.botName || definition.label}机器人设置`,
|
|
660
683
|
},
|
|
661
684
|
h('header', { className: 'dim-deliveryHeader' },
|
|
662
|
-
h(DeliveryButton, { className: 'dim-deliveryBack', onClick: onBack }, '← 返回机器人列表'),
|
|
663
|
-
|
|
685
|
+
h(DeliveryButton, { className: 'dim-deliveryBack', onClick: onBack }, '← 返回机器人列表')),
|
|
686
|
+
h('div', { className: 'dim-botSettingsTabsBar' },
|
|
687
|
+
h('nav', {
|
|
688
|
+
className: 'dim-botSettingsTabs',
|
|
689
|
+
role: 'tablist',
|
|
690
|
+
'aria-label': '机器人设置页签',
|
|
691
|
+
}, BOT_SETTINGS_TABS.map((tab) => h('button', {
|
|
692
|
+
key: tab.id,
|
|
693
|
+
id: `dim-bot-settings-${tab.id}-tab`,
|
|
694
|
+
type: 'button',
|
|
695
|
+
role: 'tab',
|
|
696
|
+
className: 'dim-botSettingsTab',
|
|
697
|
+
'aria-selected': tab.id === activeTab.id,
|
|
698
|
+
'aria-controls': `dim-bot-settings-${tab.id}-panel`,
|
|
699
|
+
tabIndex: tab.id === activeTab.id ? 0 : -1,
|
|
700
|
+
onClick: () => setActiveTabId(tab.id),
|
|
701
|
+
}, tab.label)))),
|
|
702
|
+
h('div', {
|
|
703
|
+
id: activePanelId,
|
|
704
|
+
className: 'dim-botSettingsTabPanel',
|
|
705
|
+
role: 'tabpanel',
|
|
706
|
+
'aria-labelledby': activeTabDomId,
|
|
707
|
+
},
|
|
708
|
+
activeTab.id === 'access'
|
|
709
|
+
? h(AccessPolicySettingsPage, {
|
|
710
|
+
channel,
|
|
711
|
+
account: { ...account, accessPolicy },
|
|
712
|
+
rpcCall: accessRpcCall,
|
|
713
|
+
onSaved: setAccessPolicy,
|
|
714
|
+
})
|
|
715
|
+
: h(React.Fragment, null,
|
|
716
|
+
h('section', { className: 'dim-deliveryIdentity', 'aria-labelledby': 'dim-delivery-bot-title' },
|
|
717
|
+
h('div', { className: 'dim-deliveryIdentityHeading' },
|
|
718
|
+
h('h2', { id: 'dim-delivery-bot-title', className: 'dim-deliveryBotName' },
|
|
719
|
+
account.botName || '机器人设置'),
|
|
664
720
|
h('a', {
|
|
665
721
|
className: 'dim-deliveryDocsLink',
|
|
666
722
|
href: isEnglish() ? DELIVERY_DOCS_URL.en : DELIVERY_DOCS_URL.zh,
|
|
@@ -669,11 +725,7 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
669
725
|
'aria-label': '打开主动投递使用文档',
|
|
670
726
|
},
|
|
671
727
|
h('span', null, '使用文档'),
|
|
672
|
-
h('span', { 'aria-hidden': 'true' }, '↗')))
|
|
673
|
-
h('section', { className: 'dim-deliveryIdentity', 'aria-labelledby': 'dim-delivery-bot-title' },
|
|
674
|
-
h('div', null,
|
|
675
|
-
h('h2', { id: 'dim-delivery-bot-title', className: 'dim-deliveryBotName' },
|
|
676
|
-
account.botName || '机器人设置')),
|
|
728
|
+
h('span', { 'aria-hidden': 'true' }, '↗'))),
|
|
677
729
|
h('div', { className: 'dim-deliveryBotId' },
|
|
678
730
|
h('span', null, 'Bot ID'),
|
|
679
731
|
h('code', { title: account.botId }, account.botId),
|
|
@@ -745,5 +797,5 @@ export function DeliveryTargetSettingsPage({ channel, account, rpcCall, onBack }
|
|
|
745
797
|
rpcCall: invoke,
|
|
746
798
|
onChanged: () => loadTargets({ silent: true }),
|
|
747
799
|
onEdit: () => setEditor({ mode: 'edit', target, source: 'edit' }),
|
|
748
|
-
})))));
|
|
800
|
+
})))))));
|
|
749
801
|
}
|
|
@@ -7,6 +7,62 @@ const EN = Object.freeze({
|
|
|
7
7
|
'IM机器人': 'IM bots',
|
|
8
8
|
'IM机器人设置': 'IM bot settings',
|
|
9
9
|
'更多机器人设置': 'More bot settings',
|
|
10
|
+
'机器人设置': 'Bot settings',
|
|
11
|
+
'机器人设置页签': 'Bot settings tabs',
|
|
12
|
+
'投递设置': 'Delivery settings',
|
|
13
|
+
'访问设置': 'Access settings',
|
|
14
|
+
'查看访问权限说明': 'View access permission details',
|
|
15
|
+
'允许所有用户': 'Allow all users',
|
|
16
|
+
'仅白名单用户': 'Allowlisted users only',
|
|
17
|
+
'默认命令权限': 'Default command permission',
|
|
18
|
+
'命令权限': 'Command permission',
|
|
19
|
+
'可以执行命令': 'Can run commands',
|
|
20
|
+
'不可以执行命令': 'Cannot run commands',
|
|
21
|
+
'白名单用户': 'Allowlisted users',
|
|
22
|
+
'查看白名单说明': 'View allowlist details',
|
|
23
|
+
'命令权限例外': 'Command permission exceptions',
|
|
24
|
+
'当前没有白名单用户,保存后普通用户将无法使用机器人。': 'There are currently no allowlisted users. After saving, regular users will not be able to use the bot.',
|
|
25
|
+
'新增用户': 'Add user',
|
|
26
|
+
'尚未添加用户': 'No users added',
|
|
27
|
+
'当前渠道不支持群聊': 'Group chat is not supported by this channel',
|
|
28
|
+
'原所有者或扫码接入者始终可以访问并执行命令;以下设置仅约束其他用户。': 'The original owner or QR-code operator can always access the bot and run commands; the settings below apply only to other users.',
|
|
29
|
+
'此区域无需配置,保存私聊设置时会保留现有群聊策略。': 'No setup is needed here. Saving direct-message settings keeps the existing group policy.',
|
|
30
|
+
'访问设置已保存。': 'Access settings saved.',
|
|
31
|
+
'访问设置暂不可用。': 'Access settings are currently unavailable.',
|
|
32
|
+
'访问设置保存失败,请稍后重试。': 'Could not save access settings. Try again later.',
|
|
33
|
+
'服务没有返回已保存的访问策略,请刷新后重试。': 'The service did not return the saved access policy. Refresh and try again.',
|
|
34
|
+
'访问策略尚未就绪,请返回机器人列表刷新后重试。': 'The access policy is not ready. Return to the bot list, refresh, and try again.',
|
|
35
|
+
'当前渠道暂不支持访问设置。': 'Access settings are not supported by this channel yet.',
|
|
36
|
+
'用户标识无效。': 'The user ID is invalid.',
|
|
37
|
+
'用户标识必须是字符串。': 'The user ID must be a string.',
|
|
38
|
+
'用户标识不能为空、包含控制字符或超过 256 个字符。': 'The user ID cannot be empty, contain control characters, or exceed 256 characters.',
|
|
39
|
+
'用户条目必须包含用户标识和命令权限。': 'Each user entry must include a user ID and command permission.',
|
|
40
|
+
'命令权限必须是布尔值。': 'Command permission must be a boolean.',
|
|
41
|
+
'访问模式只能是 open 或 allowlist。': 'Access mode must be open or allowlist.',
|
|
42
|
+
'开放模式设置必须完整。': 'Open-mode settings must be complete.',
|
|
43
|
+
'开放模式默认命令权限必须是布尔值。': 'The open-mode default command permission must be a boolean.',
|
|
44
|
+
'开放模式命令权限覆盖用户必须是数组。': 'Open-mode command permission overrides must be an array.',
|
|
45
|
+
'开放模式命令权限覆盖用户不能包含重复的用户标识。': 'Open-mode command permission overrides cannot contain duplicate user IDs.',
|
|
46
|
+
'白名单模式设置必须完整。': 'Allowlist-mode settings must be complete.',
|
|
47
|
+
'白名单模式用户必须是数组。': 'Allowlist-mode users must be an array.',
|
|
48
|
+
'白名单模式用户不能包含重复的用户标识。': 'Allowlist-mode users cannot contain duplicate user IDs.',
|
|
49
|
+
'访问场景设置必须同时包含模式、开放模式设置和白名单模式设置。': 'Each access context must include its mode, open-mode settings, and allowlist-mode settings.',
|
|
50
|
+
'请同时提交完整的私聊和群聊访问设置。': 'Submit complete direct-message and group access settings together.',
|
|
51
|
+
'填写微信用户 ID': 'Enter a WeChat user ID',
|
|
52
|
+
'飞书 Open ID': 'Feishu Open ID',
|
|
53
|
+
'群成员 Open ID': 'Group member Open ID',
|
|
54
|
+
'钉钉用户 ID': 'DingTalk user ID',
|
|
55
|
+
'填写 senderStaffId 或 senderId': 'Enter senderStaffId or senderId',
|
|
56
|
+
'群成员用户 ID': 'Group member user ID',
|
|
57
|
+
'企业微信用户 ID': 'WeCom user ID',
|
|
58
|
+
'填写 userid': 'Enter userid',
|
|
59
|
+
'填写 member_openid': 'Enter member_openid',
|
|
60
|
+
'QQ User Open ID': 'QQ User Open ID',
|
|
61
|
+
'群成员 User ID': 'Group member User ID',
|
|
62
|
+
'填写数字 User ID': 'Enter a numeric user ID',
|
|
63
|
+
'WhatsApp 电话号码或 JID': 'WhatsApp phone number or JID',
|
|
64
|
+
'群成员电话号码或 JID': 'Group member phone number or JID',
|
|
65
|
+
'8613800000000 或完整 JID': '8613800000000 or a full JID',
|
|
10
66
|
'IM 渠道': 'IM channels',
|
|
11
67
|
'让 DeepSeek Harness 触手可及': 'Connecting DeepSeek Harness',
|
|
12
68
|
'当前版本': 'Current version',
|
|
@@ -232,6 +288,10 @@ const EN = Object.freeze({
|
|
|
232
288
|
'查看群聊发送者昵称字段说明': 'View group sender name field details',
|
|
233
289
|
'查看私聊发送者昵称字段说明': 'View direct sender name field details',
|
|
234
290
|
'该字段不是每个渠道都能提供。当前消息没有发送者昵称时,即使已选择该字段,<dsh_im_source> 中也会省略 senderName。': 'This field is not available on every channel. If the current message has no sender name, <dsh_im_source> omits senderName even when the field is selected.',
|
|
291
|
+
'会话标题': 'Conversation title',
|
|
292
|
+
'查看群聊会话标题字段说明': 'View group conversation title field details',
|
|
293
|
+
'查看私聊会话标题字段说明': 'View direct conversation title field details',
|
|
294
|
+
'该字段不是每个渠道都能提供。钉钉群聊会带上群名。当前消息没有会话标题时,即使已选择该字段,<dsh_im_source> 中也会省略 conversationTitle。': 'This field is not available on every channel. DingTalk group chats include the group name. If the current message has no conversation title, <dsh_im_source> omits conversationTitle even when the field is selected.',
|
|
235
295
|
'机器人标识': 'Bot ID',
|
|
236
296
|
'增强提示词': 'Guidance',
|
|
237
297
|
'查看增强提示词使用说明': 'View guidance instructions',
|
|
@@ -259,7 +319,7 @@ const EN = Object.freeze({
|
|
|
259
319
|
'上下文增强保存失败,请重试。': 'Could not save context enhancement. Try again.',
|
|
260
320
|
'请提交完整的上下文增强设置。': 'Submit the complete context enhancement settings.',
|
|
261
321
|
'群聊和私聊开关必须是布尔值。': 'Group and direct switches must be booleans.',
|
|
262
|
-
'
|
|
322
|
+
'来源字段只能选择已定义的六个字段。': 'Source fields must be chosen from the six defined fields.',
|
|
263
323
|
'保存中…': 'Saving…',
|
|
264
324
|
'未设置': 'Not set',
|
|
265
325
|
'工作区修改失败,请重试。': 'Could not update the workspace. Try again.',
|
|
@@ -521,7 +581,6 @@ const EN = Object.freeze({
|
|
|
521
581
|
'先通过 @BotFather 获取 Bot Token,再在这里完成接入。': 'Get a Bot Token from @BotFather, then connect it here.',
|
|
522
582
|
'填写 @BotFather 生成的 Bot Token': 'Enter the Bot Token from @BotFather',
|
|
523
583
|
'访问模式': 'Access mode',
|
|
524
|
-
'访问设置': 'Access settings',
|
|
525
584
|
'Telegram 访问模式': 'Telegram access mode',
|
|
526
585
|
'查看 Telegram 访问模式说明': 'View Telegram access mode details',
|
|
527
586
|
'群聊全部忽略,私聊仅允许白名单用户。': 'All group messages are ignored; only allowlisted users may send DMs.',
|
|
@@ -294,6 +294,7 @@ export function IMSettingsTab({
|
|
|
294
294
|
channel: active.id,
|
|
295
295
|
account: deliverySettings,
|
|
296
296
|
rpcCall: rpcCalls.deliveryRpcCall,
|
|
297
|
+
accessRpcCall: rpcCalls[`${active.id}RpcCall`],
|
|
297
298
|
onBack: () => setDeliverySettings(null),
|
|
298
299
|
})
|
|
299
300
|
: active.id === 'weixin'
|