refactor(dashboard): redesign bot management workspace (#9825)

* refactor(dashboard): redesign bot management workspace

* feat(dashboard): show workspace list loading progress
This commit is contained in:
Soulter
2026-08-27 00:38:33 +08:00
committed by GitHub
parent 5152c09a78
commit 87a1917e80
21 changed files with 2374 additions and 607 deletions
+76 -6
View File
@@ -568,55 +568,121 @@ CONFIG_METADATA_2 = {
# "type": "string",
# "options": ["fullscreen", "embedded"],
# },
"app_id": {
"description": "应用 ID",
"type": "string",
"hint": "消息平台开放平台中的应用 ID。",
"show_key": True,
},
"app_secret": {
"description": "应用密钥",
"type": "string",
"hint": "消息平台开放平台中的应用密钥。请妥善保管,避免泄露。",
"show_key": True,
"secret": True,
},
"domain": {
"description": "开放平台 API 地址",
"type": "string",
"hint": "开放平台 API 的基础地址。使用默认官方服务时通常无需修改。",
"show_key": True,
},
"corpid": {
"description": "企业 ID",
"type": "string",
"hint": "企业微信后台中的企业 ID(CorpID)。",
"show_key": True,
},
"token": {
"description": "回调 Token",
"type": "string",
"hint": "消息平台回调配置中用于验证请求的 Token。",
"show_key": True,
"secret": True,
},
"encoding_aes_key": {
"description": "消息加密密钥",
"type": "string",
"hint": "消息平台回调配置中的 EncodingAESKey,用于加密和解密消息。",
"show_key": True,
"secret": True,
},
"api_base_url": {
"description": "API 基础地址",
"type": "string",
"hint": "消息平台 API 的基础地址。使用默认官方服务时通常无需修改。",
"show_key": True,
},
"client_id": {
"description": "客户端 ID",
"type": "string",
"hint": "消息平台开放平台中的客户端 ID。",
"show_key": True,
},
"client_secret": {
"description": "客户端密钥",
"type": "string",
"hint": "消息平台开放平台中的客户端密钥。请妥善保管,避免泄露。",
"show_key": True,
"secret": True,
},
"start_message": {
"description": "Start 命令回复",
"type": "string",
"hint": "用户向 Telegram 机器人发送 /start 命令时回复的内容。",
"show_key": True,
},
"telegram_api_base_url": {
"description": "API 地址",
"type": "string",
"hint": "Telegram Bot API 的基础地址。使用官方服务时通常无需修改。",
"show_key": True,
},
"telegram_file_base_url": {
"description": "文件 API 地址",
"type": "string",
"hint": "Telegram Bot API 文件下载接口的基础地址。使用官方服务时通常无需修改。",
"show_key": True,
},
"bot_token": {
"description": "Slack Bot Token",
"type": "string",
"hint": "Slack 应用的 Bot User OAuth Token,通常以 xoxb- 开头。",
"show_key": True,
"secret": True,
},
"app_token": {
"description": "Slack App Token",
"type": "string",
"hint": "Slack Socket Mode 使用的 App-Level Token,通常以 xapp- 开头。",
"condition": {
"slack_connection_mode": "socket",
},
"show_key": True,
"secret": True,
},
"signing_secret": {
"description": "Slack Signing Secret",
"type": "string",
"hint": "Slack 应用的 Signing Secret,用于验证 Webhook 请求。",
"condition": {
"slack_connection_mode": "webhook",
},
"show_key": True,
"secret": True,
},
"channel_access_token": {
"description": "LINE Channel Access Token",
"description": "LINE 频道访问令牌",
"type": "string",
"hint": "LINE Messaging API 频道的 Channel Access Token。",
"show_key": True,
"secret": True,
},
"channel_secret": {
"description": "LINE Channel Secret",
"description": "LINE 频道密钥",
"type": "string",
"hint": "LINE Messaging API 频道的 Channel Secret。",
"show_key": True,
"secret": True,
},
"lark_connection_mode": {
@@ -821,24 +887,28 @@ CONFIG_METADATA_2 = {
"hint": "可选。钉钉互动卡片模板 ID。启用后将使用互动卡片进行流式回复。",
},
"telegram_command_register": {
"description": "Telegram 命令注册",
"description": "命令注册",
"type": "bool",
"hint": "启用后,AstrBot 将会自动注册 Telegram 命令。",
"show_key": True,
},
"telegram_command_auto_refresh": {
"description": "Telegram 命令自动刷新",
"description": "命令自动刷新",
"type": "bool",
"hint": "启用后,AstrBot 将会在运行时自动刷新 Telegram 命令。(单独设置此项无效)",
"show_key": True,
},
"telegram_command_register_interval": {
"description": "Telegram 命令自动刷新间隔",
"description": "命令自动刷新间隔",
"type": "int",
"hint": "Telegram 命令自动刷新间隔,单位为秒。",
"show_key": True,
},
"telegram_polling_restart_delay": {
"description": "Telegram 轮询重启延迟",
"description": "轮询重启延迟",
"type": "float",
"hint": "当轮询意外结束尝试自动重启时的延迟时间,理论上越短恢复越快,但过短(<0.1s)可能导致死循环针对 API 服务器的请求阻断。单位为秒。默认为 5s。",
"show_key": True,
},
"id": {
"description": "机器人名称",
@@ -31,12 +31,14 @@ LINE_CONFIG_METADATA = {
"type": "string",
"hint": "LINE Messaging API 的 channel access token。",
"secret": True,
"show_key": True,
},
"channel_secret": {
"description": "LINE Channel Secret",
"type": "string",
"hint": "用于校验 LINE Webhook 签名。",
"secret": True,
"show_key": True,
},
}
@@ -1,4 +1,4 @@
/* Auto-generated MDI subset 270 icons */
/* Auto-generated MDI subset 272 icons */
/* Do not edit manually. Run: pnpm run subset-icons */
@font-face {
@@ -644,6 +644,10 @@
content: "\F0339";
}
.mdi-link-variant-plus::before {
content: "\F1100";
}
.mdi-loading::before {
content: "\F0772";
}
@@ -892,6 +896,10 @@
content: "\F167A";
}
.mdi-routes::before {
content: "\F046A";
}
.mdi-send-outline::before {
content: "\F1165";
}
@@ -1419,6 +1419,7 @@ export default {
}
try {
const createdPlatformId = this.selectedPlatformConfig.id;
// 先保存平台配置
const res = await botApi.create(this.selectedPlatformConfig);
@@ -1428,7 +1429,7 @@ export default {
this.loading = false;
this.showDialog = false;
this.resetForm();
this.$emit("refresh-config");
this.$emit("refresh-config", createdPlatformId);
this.showSuccess(
res.data.message || this.tm("messages.addSuccessWithConfig"),
);
File diff suppressed because it is too large Load Diff
@@ -105,6 +105,14 @@
</v-list-item>
</StyledMenu>
</div>
<v-progress-linear
v-if="loading"
class="provider-sources-progress"
color="primary"
height="2"
indeterminate
/>
</div>
<div v-if="displayedProviderSources.length > 0" class="provider-sources-list">
@@ -154,7 +162,7 @@
</button>
</div>
<div v-else class="provider-sources-empty">
<div v-else-if="!loading" class="provider-sources-empty">
<v-icon size="44" color="grey-lighten-1">mdi-api-off</v-icon>
<p class="provider-sources-empty__text">
{{ emptyText || tm('providerSources.empty') }}
@@ -196,6 +204,10 @@ const props = defineProps({
type: String,
default: ''
},
loading: {
type: Boolean,
default: false
},
tm: {
type: Function,
required: true
@@ -284,6 +296,14 @@ const selectSourceByValue = (value) => {
justify-content: space-between;
gap: 12px;
padding: 20px 20px 12px;
position: relative;
}
.provider-sources-progress {
bottom: 0;
left: 0;
position: absolute;
right: 0;
}
.provider-sources-head__copy {
@@ -188,7 +188,8 @@ function hasVisibleItemsAfter(items, currentIndex) {
<template>
<div class="config-section" v-if="iterable && metadata[metadataKey]?.type === 'object'">
<v-list-item-title class="config-title">
{{ resolveConfigText(currentConfigPath, 'description', metadata[metadataKey]?.description) }} <span class="metadata-key">({{ metadataKey }})</span>
{{ resolveConfigText(currentConfigPath, 'description', metadata[metadataKey]?.description) }}
<span v-if="metadata[metadataKey]?.show_key" class="metadata-key">({{ metadataKey }})</span>
</v-list-item-title>
<v-list-item-subtitle class="config-hint">
<span v-if="metadata[metadataKey]?.obvious_hint && metadata[metadataKey]?.hint" class="important-hint"></span>
@@ -237,7 +238,7 @@ function hasVisibleItemsAfter(items, currentIndex) {
<v-list-item-title class="config-title">
<span v-if="metadata[metadataKey].items[key]?.description">
{{ resolveConfigText(getItemPath(key), 'description', metadata[metadataKey].items[key]?.description) }}
<span class="property-key">({{ key }})</span>
<span v-if="metadata[metadataKey].items[key]?.show_key" class="property-key">({{ key }})</span>
</span>
<span v-else>{{ key }}</span>
</v-list-item-title>
@@ -272,7 +273,7 @@ function hasVisibleItemsAfter(items, currentIndex) {
<v-list-item-title class="property-name">
<span v-if="metadata[metadataKey].items[key]?.description">
{{ resolveConfigText(getItemPath(key), 'description', metadata[metadataKey].items[key]?.description) }}
<span class="property-key">({{ key }})</span>
<span v-if="metadata[metadataKey].items[key]?.show_key" class="property-key">({{ key }})</span>
</span>
<span v-else>{{ key }}</span>
</v-list-item-title>
@@ -332,7 +333,7 @@ function hasVisibleItemsAfter(items, currentIndex) {
<v-list-item density="compact">
<v-list-item-title class="property-name">
{{ resolveConfigText(getItemPath(metadataKey), 'description', metadata[metadataKey]?.description) }}
<span class="property-key">({{ metadataKey }})</span>
<span v-if="metadata[metadataKey]?.show_key" class="property-key">({{ metadataKey }})</span>
</v-list-item-title>
<v-list-item-subtitle class="property-hint">
@@ -420,10 +421,10 @@ function hasVisibleItemsAfter(items, currentIndex) {
}
.metadata-key, .property-key {
font-size: 0.85em;
opacity: 0.7;
color: rgba(var(--v-theme-on-surface), 0.45);
font-size: 0.82em;
font-weight: normal;
display: none;
margin-left: 4px;
}
.important-hint {
@@ -284,7 +284,7 @@ function getSpecialSubtype(value) {
<v-list-item density="compact">
<v-list-item-title class="property-name">
{{ getItemDescription(itemKey, itemMeta) }}
<span class="property-key">({{ itemKey }})</span>
<span v-if="itemMeta?.show_key" class="property-key">({{ itemKey }})</span>
</v-list-item-title>
<v-list-item-subtitle class="property-hint">
@@ -371,7 +371,7 @@ function getSpecialSubtype(value) {
<v-list-item density="compact">
<v-list-item-title class="property-name">
{{ getItemDescription(itemKey, itemMeta) }}
<span class="property-key">({{ itemKey }})</span>
<span v-if="itemMeta?.show_key" class="property-key">({{ itemKey }})</span>
</v-list-item-title>
<v-list-item-subtitle class="property-hint">
@@ -489,10 +489,10 @@ function getSpecialSubtype(value) {
.metadata-key,
.property-key {
font-size: 0.85em;
opacity: 0.7;
color: rgba(var(--v-theme-on-surface), 0.45);
font-size: 0.82em;
font-weight: normal;
display: none;
margin-left: 4px;
}
.important-hint {
@@ -2,7 +2,7 @@
<div class="umo-display" :class="{ 'umo-display--compact': compact }">
<div class="umo-display__main">
<div class="umo-display__line">
<span class="umo-display__name" :class="{ 'umo-display__name--umo': !hasReadableName }" :title="displayNameTitle">
<span class="umo-display__name" :class="{ 'umo-display__name--umo': !hasReadableName }" :title="showRawTitle ? displayNameTitle : displayName">
{{ displayName }}
</span>
</div>
@@ -83,6 +83,10 @@ export default {
type: Boolean,
default: true,
},
showRawTitle: {
type: Boolean,
default: true,
},
editable: {
type: Boolean,
default: false,
@@ -67,6 +67,7 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
const editableProviderSource = ref<any | null>(null)
const availableModels = ref<any[]>([])
const modelMetadata = ref<Record<string, any>>({})
const loadingSources = ref(true)
const loadingModels = ref(false)
const savingSource = ref(false)
const savingProviderToggles = ref<string[]>([])
@@ -723,6 +724,7 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
}
async function loadProviderTemplate() {
loadingSources.value = true
try {
const response = await providerApi.schema()
if (response.data.status === 'ok') {
@@ -736,6 +738,8 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
}
} catch (error) {
console.error('Failed to load provider template:', error)
} finally {
loadingSources.value = false
}
}
@@ -759,6 +763,7 @@ export function useProviderSources(options: UseProviderSourcesOptions) {
editableProviderSource,
availableModels,
modelMetadata,
loadingSources,
loadingModels,
savingSource,
savingProviderToggles,
@@ -415,32 +415,73 @@
"name": "Platform",
"platform": {
"description": "Message Platform Adapters",
"app_id": {
"description": "Application ID",
"hint": "The application ID from the messaging platform's developer console."
},
"app_secret": {
"description": "Application Secret"
"description": "Application secret",
"hint": "The application secret from the messaging platform's developer console. Keep it secure."
},
"domain": {
"description": "Open platform API URL",
"hint": "The base URL of the open platform API. The default normally does not need to be changed."
},
"corpid": {
"description": "Enterprise ID",
"hint": "The enterprise ID (CorpID) from the WeCom administration console."
},
"token": {
"description": "Callback Token"
"description": "Callback token",
"hint": "The token used to verify requests in the messaging platform's callback settings."
},
"encoding_aes_key": {
"description": "Message Encryption Key"
"description": "Message encryption key",
"hint": "The EncodingAESKey from the callback settings, used to encrypt and decrypt messages."
},
"api_base_url": {
"description": "API base URL",
"hint": "The messaging platform API base URL. The default normally does not need to be changed."
},
"client_id": {
"description": "Client ID",
"hint": "The client ID from the messaging platform's developer console."
},
"client_secret": {
"description": "Client Secret"
"description": "Client secret",
"hint": "The client secret from the messaging platform's developer console. Keep it secure."
},
"start_message": {
"description": "Start command reply",
"hint": "The message sent when a user sends the /start command to the Telegram bot."
},
"telegram_api_base_url": {
"description": "API URL",
"hint": "The Telegram Bot API base URL. The official default normally does not need to be changed."
},
"telegram_file_base_url": {
"description": "File API URL",
"hint": "The base URL used to download files from the Telegram Bot API. The official default normally does not need to be changed."
},
"bot_token": {
"description": "Slack Bot Token"
"description": "Slack Bot Token",
"hint": "The Slack application's Bot User OAuth Token, usually beginning with xoxb-."
},
"app_token": {
"description": "Slack App Token"
"description": "Slack App Token",
"hint": "The App-Level Token used by Slack Socket Mode, usually beginning with xapp-."
},
"signing_secret": {
"description": "Slack Signing Secret"
"description": "Slack Signing Secret",
"hint": "The Slack application's Signing Secret, used to verify webhook requests."
},
"channel_access_token": {
"description": "LINE Channel Access Token"
"description": "LINE Channel Access Token",
"hint": "The Channel Access Token for the LINE Messaging API channel."
},
"channel_secret": {
"description": "LINE Channel Secret"
"description": "LINE Channel Secret",
"hint": "The Channel Secret for the LINE Messaging API channel."
},
"active_send_mode": {
"description": "Use Proactive Send API"
@@ -612,19 +653,19 @@
"hint": "Only valid when Slack connection mode is `webhook`."
},
"telegram_command_auto_refresh": {
"description": "Telegram Command Auto Refresh",
"description": "Command Auto Refresh",
"hint": "When enabled, AstrBot automatically refreshes Telegram commands at runtime. (Setting this alone has no effect)"
},
"telegram_command_register": {
"description": "Telegram Command Registration",
"description": "Command Registration",
"hint": "When enabled, AstrBot automatically registers Telegram commands."
},
"telegram_command_register_interval": {
"description": "Telegram Command Auto Refresh Interval",
"description": "Command Auto Refresh Interval",
"hint": "Telegram command auto-refresh interval in seconds."
},
"telegram_polling_restart_delay": {
"description": "Telegram Polling Restart Delay",
"description": "Polling Restart Delay",
"hint": "Waiting time in seconds when the polling loop needs to restart after unexpected exits. Defaults to 5s."
},
"telegram_token": {
@@ -4,6 +4,49 @@
"adapters": "Platform Adapters",
"addAdapter": "Add Adapter",
"emptyText": "No platform adapters yet, click Add Adapter to create one",
"workspace": {
"listTitle": "Bots",
"selectHint": "Select a bot to configure",
"empty": "No bots yet. Create one to start configuring it.",
"enabled": "Enable bot",
"disabled": "Disabled",
"delete": "Delete bot",
"save": "Save changes",
"configTitle": "Connection settings",
"configDescription": "Configure how this bot connects to its messaging platform.",
"routes": {
"title": "Conversation configuration",
"description": "Use different configuration profiles for different conversations. Unbound conversations use the default below.",
"loadFailed": "Conversation configuration could not be loaded. Connection settings remain editable, but conversation assignments will not be changed this time.",
"defaultTitle": "Default configuration for this bot",
"defaultDescription": "Every conversation without its own binding uses this configuration.",
"systemDefault": "System default configuration (default)",
"bindTitle": "Choose a configuration for a conversation",
"bindDescription": "Select a known conversation, then choose the configuration profile it should use.",
"sessionLabel": "Select conversation",
"configLabel": "Configuration profile",
"bind": "Add binding",
"noSessions": "No conversations yet. Send this bot a message on its messaging platform first.",
"boundTitle": "Bound conversations",
"boundCount": "{count}",
"remove": "Remove binding",
"noBindings": "No conversations are bound separately. All conversations use the default configuration.",
"advanced": "Advanced routing rules",
"advancedDescription": "Use UMO patterns to match multiple conversations. Rules are matched from top to bottom and are intended for users familiar with AstrBot message origins.",
"patternLabel": "UMO pattern",
"patternPlaceholder": "For example, bot-id:GroupMessage:*",
"addPattern": "Add rule",
"patternRequired": "Enter a UMO pattern",
"patternInvalid": "Use the format platform:message type:conversation ID",
"patternPlatformMismatch": "The platform part must match the current bot ID",
"duplicatePattern": "Duplicate configuration routes were found. Review them and try again.",
"sessionTypes": {
"group": "Group",
"friend": "Direct message",
"other": "Conversation"
}
}
},
"viewWebhook": "View Webhook URL",
"webhookCopied": "Webhook URL copied to clipboard",
"webhookCopyFailed": "Copy failed, please copy manually",
@@ -415,32 +415,73 @@
"name": "Платформы",
"platform": {
"description": "Адаптеры сообщений",
"app_id": {
"description": "ID приложения",
"hint": "ID приложения из консоли разработчика платформы сообщений."
},
"app_secret": {
"description": "Секрет приложения"
"description": "Секрет приложения",
"hint": "Секрет приложения из консоли разработчика платформы сообщений. Храните его в безопасности."
},
"domain": {
"description": "Адрес API платформы",
"hint": "Базовый адрес API открытой платформы. Обычно значение по умолчанию менять не нужно."
},
"corpid": {
"description": "ID организации",
"hint": "ID организации (CorpID) из консоли администрирования WeCom."
},
"token": {
"description": "Токен обратного вызова"
"description": "Токен обратного вызова",
"hint": "Токен для проверки запросов из настроек обратного вызова платформы сообщений."
},
"encoding_aes_key": {
"description": "Ключ шифрования сообщений"
"description": "Ключ шифрования сообщений",
"hint": "EncodingAESKey из настроек обратного вызова, используемый для шифрования и расшифровки сообщений."
},
"api_base_url": {
"description": "Базовый адрес API",
"hint": "Базовый адрес API платформы сообщений. Обычно значение по умолчанию менять не нужно."
},
"client_id": {
"description": "ID клиента",
"hint": "ID клиента из консоли разработчика платформы сообщений."
},
"client_secret": {
"description": "Секрет клиента"
"description": "Секрет клиента",
"hint": "Секрет клиента из консоли разработчика платформы сообщений. Храните его в безопасности."
},
"start_message": {
"description": "Ответ на команду /start",
"hint": "Сообщение, отправляемое пользователю в ответ на команду /start для Telegram-бота."
},
"telegram_api_base_url": {
"description": "Адрес API",
"hint": "Базовый адрес Telegram Bot API. Обычно официальный адрес менять не нужно."
},
"telegram_file_base_url": {
"description": "Адрес файлового API",
"hint": "Базовый адрес для загрузки файлов из Telegram Bot API. Обычно официальный адрес менять не нужно."
},
"bot_token": {
"description": "Slack Bot Token"
"description": "Slack Bot Token",
"hint": "Bot User OAuth Token приложения Slack, обычно начинается с xoxb-."
},
"app_token": {
"description": "Slack App Token"
"description": "Slack App Token",
"hint": "App-Level Token для Slack Socket Mode, обычно начинается с xapp-."
},
"signing_secret": {
"description": "Slack Signing Secret"
"description": "Slack Signing Secret",
"hint": "Signing Secret приложения Slack для проверки запросов Webhook."
},
"channel_access_token": {
"description": "LINE Channel Access Token"
"description": "Токен доступа канала LINE",
"hint": "Channel Access Token канала LINE Messaging API."
},
"channel_secret": {
"description": "LINE Channel Secret"
"description": "Секрет канала LINE",
"hint": "Channel Secret канала LINE Messaging API."
},
"active_send_mode": {
"description": "Использовать API активной отправки"
@@ -612,17 +653,21 @@
"hint": "Действительно только если режим подключения Slack установлен как `webhook`."
},
"telegram_command_auto_refresh": {
"description": "Автообновление команд Telegram",
"description": "Автообновление команд",
"hint": "Если включено, AstrBot автоматически обновляет команды Telegram во время выполнения. (Одна эта настройка не имеет эффекта)"
},
"telegram_command_register": {
"description": "Регистрация команд Telegram",
"description": "Регистрация команд",
"hint": "Если включено, AstrBot автоматически регистрирует команды Telegram."
},
"telegram_command_register_interval": {
"description": "Интервал автообновления команд Telegram",
"description": "Интервал автообновления команд",
"hint": "Интервал автоматического обновления команд Telegram в секундах."
},
"telegram_polling_restart_delay": {
"description": "Задержка перезапуска опроса",
"hint": "Задержка перед автоматическим перезапуском после неожиданного завершения опроса, в секундах. По умолчанию 5 секунд."
},
"telegram_token": {
"description": "Токен бота",
"hint": "Если вы находитесь в материковом Китае, установите прокси или измените api_base в разделе «Другие настройки»."
@@ -4,6 +4,49 @@
"adapters": "Адаптеры платформ",
"addAdapter": "Создать бота",
"emptyText": "Боты не настроены. Нажмите «Создать бота», чтобы начать.",
"workspace": {
"listTitle": "Боты",
"selectHint": "Выберите бота для настройки",
"empty": "Ботов пока нет. Создайте бота, чтобы начать настройку.",
"enabled": "Включить бота",
"disabled": "Отключён",
"delete": "Удалить бота",
"save": "Сохранить изменения",
"configTitle": "Настройки подключения",
"configDescription": "Настройте подключение бота к платформе сообщений.",
"routes": {
"title": "Настройки диалогов",
"description": "Назначайте разные профили разным диалогам. Диалоги без отдельной привязки используют профиль по умолчанию.",
"loadFailed": "Не удалось загрузить настройки диалогов. Настройки подключения можно редактировать, но назначения диалогов в этот раз не изменятся.",
"defaultTitle": "Профиль бота по умолчанию",
"defaultDescription": "Он используется во всех диалогах без отдельной привязки.",
"systemDefault": "Системный профиль по умолчанию (default)",
"bindTitle": "Выберите профиль для диалога",
"bindDescription": "Выберите известный диалог и укажите профиль конфигурации для него.",
"sessionLabel": "Выберите диалог",
"configLabel": "Профиль конфигурации",
"bind": "Добавить привязку",
"noSessions": "Диалогов пока нет. Сначала отправьте сообщение этому боту на его платформе.",
"boundTitle": "Привязанные диалоги",
"boundCount": "{count}",
"remove": "Удалить привязку",
"noBindings": "Отдельных привязок нет. Все диалоги используют профиль по умолчанию.",
"advanced": "Расширенные правила маршрутизации",
"advancedDescription": "Используйте шаблоны UMO для нескольких диалогов. Правила проверяются сверху вниз и предназначены для пользователей, знакомых с источниками сообщений AstrBot.",
"patternLabel": "Шаблон UMO",
"patternPlaceholder": "Например, bot-id:GroupMessage:*",
"addPattern": "Добавить правило",
"patternRequired": "Введите шаблон UMO",
"patternInvalid": "Используйте формат платформа:тип сообщения:ID диалога",
"patternPlatformMismatch": "Платформа в правиле должна совпадать с ID текущего бота",
"duplicatePattern": "Обнаружены дублирующиеся маршруты. Проверьте их и повторите попытку.",
"sessionTypes": {
"group": "Группа",
"friend": "Личный диалог",
"other": "Диалог"
}
}
},
"viewWebhook": "Показать Webhook",
"webhookCopied": "URL скопирован в буфер обмена",
"webhookCopyFailed": "Не удалось скопировать, сделайте это вручную",
@@ -417,32 +417,73 @@
"name": "平台配置",
"platform": {
"description": "消息平台适配器",
"app_id": {
"description": "应用 ID",
"hint": "消息平台开放平台中的应用 ID。"
},
"app_secret": {
"description": "应用密钥"
"description": "应用密钥",
"hint": "消息平台开放平台中的应用密钥。请妥善保管,避免泄露。"
},
"domain": {
"description": "开放平台 API 地址",
"hint": "开放平台 API 的基础地址。使用默认官方服务时通常无需修改。"
},
"corpid": {
"description": "企业 ID",
"hint": "企业微信后台中的企业 IDCorpID)。"
},
"token": {
"description": "回调 Token"
"description": "回调 Token",
"hint": "消息平台回调配置中用于验证请求的 Token。"
},
"encoding_aes_key": {
"description": "消息加密密钥"
"description": "消息加密密钥",
"hint": "消息平台回调配置中的 EncodingAESKey,用于加密和解密消息。"
},
"api_base_url": {
"description": "API 基础地址",
"hint": "消息平台 API 的基础地址。使用默认官方服务时通常无需修改。"
},
"client_id": {
"description": "客户端 ID",
"hint": "消息平台开放平台中的客户端 ID。"
},
"client_secret": {
"description": "客户端密钥"
"description": "客户端密钥",
"hint": "消息平台开放平台中的客户端密钥。请妥善保管,避免泄露。"
},
"start_message": {
"description": "Start 命令回复",
"hint": "用户向 Telegram 机器人发送 /start 命令时回复的内容。"
},
"telegram_api_base_url": {
"description": "API 地址",
"hint": "Telegram Bot API 的基础地址。使用官方服务时通常无需修改。"
},
"telegram_file_base_url": {
"description": "文件 API 地址",
"hint": "Telegram Bot API 文件下载接口的基础地址。使用官方服务时通常无需修改。"
},
"bot_token": {
"description": "Slack Bot Token"
"description": "Slack Bot Token",
"hint": "Slack 应用的 Bot User OAuth Token,通常以 xoxb- 开头。"
},
"app_token": {
"description": "Slack App Token"
"description": "Slack App Token",
"hint": "Slack Socket Mode 使用的 App-Level Token,通常以 xapp- 开头。"
},
"signing_secret": {
"description": "Slack Signing Secret"
"description": "Slack Signing Secret",
"hint": "Slack 应用的 Signing Secret,用于验证 Webhook 请求。"
},
"channel_access_token": {
"description": "LINE Channel Access Token"
"description": "LINE 频道访问令牌",
"hint": "LINE Messaging API 频道的 Channel Access Token。"
},
"channel_secret": {
"description": "LINE Channel Secret"
"description": "LINE 频道密钥",
"hint": "LINE Messaging API 频道的 Channel Secret。"
},
"active_send_mode": {
"description": "是否换用主动发送接口"
@@ -614,19 +655,19 @@
"hint": "Only valid when Slack connection mode is `webhook`."
},
"telegram_command_auto_refresh": {
"description": "Telegram 命令自动刷新",
"description": "命令自动刷新",
"hint": "启用后,AstrBot 将会在运行时自动刷新 Telegram 命令。(单独设置此项无效)"
},
"telegram_command_register": {
"description": "Telegram 命令注册",
"description": "命令注册",
"hint": "启用后,AstrBot 将会自动注册 Telegram 命令。"
},
"telegram_command_register_interval": {
"description": "Telegram 命令自动刷新间隔",
"description": "命令自动刷新间隔",
"hint": "Telegram 命令自动刷新间隔,单位为秒。"
},
"telegram_polling_restart_delay": {
"description": "Telegram 轮询重启延迟",
"description": "轮询重启延迟",
"hint": "当轮询意外结束尝试自动重启时的延迟时间,单位为秒。默认为 5s。"
},
"telegram_token": {
@@ -4,6 +4,49 @@
"adapters": "平台适配器",
"addAdapter": "创建机器人",
"emptyText": "暂无平台适配器,点击 创建机器人 添加",
"workspace": {
"listTitle": "机器人",
"selectHint": "选择一个机器人进行配置",
"empty": "还没有机器人,创建后即可开始配置。",
"enabled": "启用机器人",
"disabled": "已停用",
"delete": "删除机器人",
"save": "保存更改",
"configTitle": "接入设置",
"configDescription": "配置机器人与消息平台的连接方式。",
"routes": {
"title": "会话配置",
"description": "让不同会话使用不同的配置文件。没有单独绑定的会话会使用下方的默认配置。",
"loadFailed": "会话配置加载失败。接入设置仍可编辑,但本次不会修改会话配置。",
"defaultTitle": "此机器人的默认配置",
"defaultDescription": "所有没有单独设置的会话都会使用它。",
"systemDefault": "系统默认配置(default",
"bindTitle": "为特定会话选择配置",
"bindDescription": "先选择一个已有会话,再指定它要使用的配置文件。",
"sessionLabel": "选择会话",
"configLabel": "配置文件",
"bind": "添加绑定",
"noSessions": "暂无会话。请先在对应的消息平台与这个机器人产生一次对话。",
"boundTitle": "已绑定的会话",
"boundCount": "{count} 个",
"remove": "移除绑定",
"noBindings": "暂未单独绑定会话,所有会话将使用默认配置。",
"advanced": "高级路由规则",
"advancedDescription": "使用 UMO pattern 批量匹配会话。规则按从上到下的顺序匹配,适合熟悉 AstrBot 会话来源格式的用户。",
"patternLabel": "UMO pattern",
"patternPlaceholder": "例如 bot-id:GroupMessage:*",
"addPattern": "添加规则",
"patternRequired": "请输入 UMO pattern",
"patternInvalid": "格式应为 平台:消息类型:会话 ID",
"patternPlatformMismatch": "规则的平台部分必须是当前机器人的 ID",
"duplicatePattern": "存在重复的配置路由,请检查后重试。",
"sessionTypes": {
"group": "群聊",
"friend": "私聊",
"other": "会话"
}
}
},
"viewWebhook": "查看 Webhook 链接",
"webhookCopied": "Webhook URL 已复制到剪贴板",
"webhookCopyFailed": "复制失败,请手动复制",
+11 -4
View File
@@ -25,8 +25,12 @@ const isPluginPageRoute = computed(
() => route.path.startsWith("/plugin-page/"),
);
const isProviderPageRoute = computed(() => route.path === "/providers");
const isPlatformPageRoute = computed(() => route.path === "/platforms");
const isViewportLockedRoute = computed(
() => isCurrentChatRoute.value || isProviderPageRoute.value,
() =>
isCurrentChatRoute.value ||
isProviderPageRoute.value ||
isPlatformPageRoute.value,
);
const isFullScreenRoute = computed(
() => isCurrentChatRoute.value || isPluginPageRoute.value,
@@ -124,16 +128,19 @@ onMounted(() => {
class="page-wrapper"
:class="{
'chat-mode-container': isCurrentChatRoute,
'viewport-locked-container': isProviderPageRoute,
'viewport-locked-container':
isProviderPageRoute || isPlatformPageRoute,
}"
:style="{
height:
isFullScreenRoute || isProviderPageRoute
isFullScreenRoute || isProviderPageRoute || isPlatformPageRoute
? '100%'
: 'calc(100% - 8px)',
padding: isFullScreenRoute ? '0' : undefined,
minHeight:
isFullScreenRoute || isProviderPageRoute ? 'unset' : undefined,
isFullScreenRoute || isProviderPageRoute || isPlatformPageRoute
? 'unset'
: undefined,
}"
>
<div
File diff suppressed because it is too large Load Diff
+2
View File
@@ -42,6 +42,7 @@
:delete-label="selectedProviderType === 'chat_completion'
? ''
: tm('providers.deleteProvider')"
:loading="loadingSources"
:tm="tm"
:resolve-source-icon="resolveSourceIcon"
:is-monochrome-source-icon="isMonochromeSourceIcon"
@@ -353,6 +354,7 @@ const {
selectedProviderType,
selectedProviderSource,
availableModels,
loadingSources,
loadingModels,
savingSource,
testingProviders,