From 1fff5713f36d1035a32944360b23725f45654b8d Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Tue, 23 Sep 2025 15:31:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E8=A7=A3=E8=80=A6=20PlatformPage?= =?UTF-8?q?=20=E5=92=8C=20ProviderPage=20=E7=9A=84=E9=83=A8=E5=88=86?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/platform/AddNewPlatform.vue | 169 +++++++++++++ .../components/provider/AddNewProvider.vue | 239 ++++++++++++++++++ dashboard/src/utils/platformUtils.js | 78 ++++++ dashboard/src/utils/providerUtils.js | 51 ++++ dashboard/src/views/PlatformPage.vue | 227 ++--------------- dashboard/src/views/ProviderPage.vue | 228 +---------------- 6 files changed, 573 insertions(+), 419 deletions(-) create mode 100644 dashboard/src/components/platform/AddNewPlatform.vue create mode 100644 dashboard/src/components/provider/AddNewProvider.vue create mode 100644 dashboard/src/utils/platformUtils.js create mode 100644 dashboard/src/utils/providerUtils.js diff --git a/dashboard/src/components/platform/AddNewPlatform.vue b/dashboard/src/components/platform/AddNewPlatform.vue new file mode 100644 index 000000000..f125bbe8d --- /dev/null +++ b/dashboard/src/components/platform/AddNewPlatform.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/dashboard/src/components/provider/AddNewProvider.vue b/dashboard/src/components/provider/AddNewProvider.vue new file mode 100644 index 000000000..164e31300 --- /dev/null +++ b/dashboard/src/components/provider/AddNewProvider.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/dashboard/src/utils/platformUtils.js b/dashboard/src/utils/platformUtils.js new file mode 100644 index 000000000..2656c56c7 --- /dev/null +++ b/dashboard/src/utils/platformUtils.js @@ -0,0 +1,78 @@ +/** + * 平台相关工具函数 + */ + +/** + * 获取平台图标 + * @param {string} name - 平台名称或类型 + * @returns {string|undefined} 图标URL + */ +export function getPlatformIcon(name) { + if (name === 'aiocqhttp' || name === 'qq_official' || name === 'qq_official_webhook') { + return new URL('@/assets/images/platform_logos/qq.png', import.meta.url).href + } else if (name === 'wecom') { + return new URL('@/assets/images/platform_logos/wecom.png', import.meta.url).href + } else if (name === 'wechatpadpro' || name === 'weixin_official_account' || name === 'wechat') { + return new URL('@/assets/images/platform_logos/wechat.png', import.meta.url).href + } else if (name === 'lark') { + return new URL('@/assets/images/platform_logos/lark.png', import.meta.url).href + } else if (name === 'dingtalk') { + return new URL('@/assets/images/platform_logos/dingtalk.svg', import.meta.url).href + } else if (name === 'telegram') { + return new URL('@/assets/images/platform_logos/telegram.svg', import.meta.url).href + } else if (name === 'discord') { + return new URL('@/assets/images/platform_logos/discord.svg', import.meta.url).href + } else if (name === 'slack') { + return new URL('@/assets/images/platform_logos/slack.svg', import.meta.url).href + } else if (name === 'kook') { + return new URL('@/assets/images/platform_logos/kook.png', import.meta.url).href + } else if (name === 'vocechat') { + return new URL('@/assets/images/platform_logos/vocechat.png', import.meta.url).href + } else if (name === 'satori' || name === 'Satori') { + return new URL('@/assets/images/platform_logos/satori.png', import.meta.url).href + } else if (name === 'misskey') { + return new URL('@/assets/images/platform_logos/misskey.png', import.meta.url).href + } +} + +/** + * 获取平台教程链接 + * @param {string} platformType - 平台类型 + * @returns {string} 教程链接 + */ +export function getTutorialLink(platformType) { + const tutorialMap = { + "qq_official_webhook": "https://docs.astrbot.app/deploy/platform/qqofficial/webhook.html", + "qq_official": "https://docs.astrbot.app/deploy/platform/qqofficial/websockets.html", + "aiocqhttp": "https://docs.astrbot.app/deploy/platform/aiocqhttp/napcat.html", + "wecom": "https://docs.astrbot.app/deploy/platform/wecom.html", + "lark": "https://docs.astrbot.app/deploy/platform/lark.html", + "telegram": "https://docs.astrbot.app/deploy/platform/telegram.html", + "dingtalk": "https://docs.astrbot.app/deploy/platform/dingtalk.html", + "wechatpadpro": "https://docs.astrbot.app/deploy/platform/wechat/wechatpadpro.html", + "weixin_official_account": "https://docs.astrbot.app/deploy/platform/weixin-official-account.html", + "discord": "https://docs.astrbot.app/deploy/platform/discord.html", + "slack": "https://docs.astrbot.app/deploy/platform/slack.html", + "kook": "https://docs.astrbot.app/deploy/platform/kook.html", + "vocechat": "https://docs.astrbot.app/deploy/platform/vocechat.html", + "satori": "https://docs.astrbot.app/deploy/platform/satori/llonebot.html", + "misskey": "https://docs.astrbot.app/deploy/platform/misskey.html", + } + return tutorialMap[platformType] || "https://docs.astrbot.app"; +} + +/** + * 获取平台描述 + * @param {Object} template - 平台模板 + * @param {string} name - 平台名称 + * @returns {string} 平台描述 + */ +export function getPlatformDescription(template, name) { + // special judge for community platforms + if (name.includes('vocechat')) { + return "由 @HikariFroya 提供。"; + } else if (name.includes('kook')) { + return "由 @wuyan1003 提供。" + } + return ''; +} diff --git a/dashboard/src/utils/providerUtils.js b/dashboard/src/utils/providerUtils.js new file mode 100644 index 000000000..1dbc66874 --- /dev/null +++ b/dashboard/src/utils/providerUtils.js @@ -0,0 +1,51 @@ +/** + * 提供商相关的工具函数 + */ + +/** + * 获取提供商类型对应的图标 + * @param {string} type - 提供商类型 + * @returns {string} 图标 URL + */ +export function getProviderIcon(type) { + const icons = { + 'openai': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/openai.svg', + 'azure': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/azure.svg', + 'xai': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/xai.svg', + 'anthropic': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/anthropic.svg', + 'ollama': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/ollama.svg', + 'google': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/gemini-color.svg', + 'deepseek': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/deepseek.svg', + 'modelscope': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/modelscope.svg', + 'zhipu': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/zhipu.svg', + 'siliconflow': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/siliconcloud.svg', + 'moonshot': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/kimi.svg', + 'ppio': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/ppio.svg', + 'dify': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/dify-color.svg', + 'dashscope': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/alibabacloud-color.svg', + 'fastgpt': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/fastgpt-color.svg', + 'lm_studio': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/lmstudio.svg', + 'fishaudio': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/fishaudio.svg', + 'minimax': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/minimax.svg', + '302ai': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/1.53.0/files/icons/ai302-color.svg', + 'microsoft': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/microsoft.svg', + 'vllm': 'https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/vllm.svg', + }; + return icons[type] || ''; +} + +/** + * 获取提供商简介 + * @param {Object} template - 模板对象 + * @param {string} name - 提供商名称 + * @param {Function} tm - 翻译函数 + * @returns {string} 提供商描述 + */ +export function getProviderDescription(template, name, tm) { + if (name == 'OpenAI') { + return tm('providers.description.openai', { type: template.type }); + } else if (name == 'vLLM Rerank') { + return tm('providers.description.vllm_rerank', { type: template.type }); + } + return tm('providers.description.default', { type: template.type }); +} diff --git a/dashboard/src/views/PlatformPage.vue b/dashboard/src/views/PlatformPage.vue index 54e0ff57d..e135908e3 100644 --- a/dashboard/src/views/PlatformPage.vue +++ b/dashboard/src/views/PlatformPage.vue @@ -10,7 +10,8 @@ {{ tm('subtitle') }}

- + {{ tm('addAdapter') }} @@ -25,14 +26,9 @@ - + @@ -61,59 +57,13 @@ - - - - mdi-plus-circle - {{ tm('dialog.addPlatform') }} - - - mdi-close - - - - - - - -
-
- {{ tm('dialog.connectTitle', { name }) }} - - {{ getPlatformDescription(template, name) }} - -
- -
-
-
- - - {{ tm('dialog.noTemplates') }} - - -
-
-
-
+ - - - {{ updatingMode ? 'mdi-pencil' : 'mdi-plus' }} - {{ updatingMode ? tm('dialog.edit') : tm('dialog.add') }} {{ newSelectedPlatformName }} {{ - tm('dialog.adapter') }} - - + @@ -164,7 +114,7 @@ {{ tm('dialog.idConflict.confirm') - }} + }}
@@ -177,7 +127,9 @@

{{ tm('dialog.securityWarning.aiocqhttpTokenMissing') }}

- {{ tm('dialog.securityWarning.learnMore') }} + {{ tm('dialog.securityWarning.learnMore') }}
@@ -199,8 +151,10 @@ import AstrBotConfig from '@/components/shared/AstrBotConfig.vue'; import WaitingForRestart from '@/components/shared/WaitingForRestart.vue'; import ConsoleDisplayer from '@/components/shared/ConsoleDisplayer.vue'; import ItemCard from '@/components/shared/ItemCard.vue'; +import AddNewPlatform from '@/components/platform/AddNewPlatform.vue'; import { useCommonStore } from '@/stores/common'; import { useI18n, useModuleI18n } from '@/i18n/composables'; +import { getPlatformIcon, getTutorialLink } from '@/utils/platformUtils'; export default { name: 'PlatformPage', @@ -208,7 +162,8 @@ export default { AstrBotConfig, WaitingForRestart, ConsoleDisplayer, - ItemCard + ItemCard, + AddNewPlatform }, setup() { const { t } = useI18n(); @@ -285,69 +240,14 @@ export default { }, methods: { + // 从工具函数导入 + getPlatformIcon, + openTutorial() { - const tutorialUrl = this.getTutorialLink(this.newSelectedPlatformConfig.type); + const tutorialUrl = getTutorialLink(this.newSelectedPlatformConfig.type); window.open(tutorialUrl, '_blank'); }, - getPlatformIcon(name) { - if (name === 'aiocqhttp' || name === 'qq_official' || name === 'qq_official_webhook') { - return new URL('@/assets/images/platform_logos/qq.png', import.meta.url).href - } else if (name === 'wecom') { - return new URL('@/assets/images/platform_logos/wecom.png', import.meta.url).href - } else if (name === 'wechatpadpro' || name === 'weixin_official_account' || name === 'wechat') { - return new URL('@/assets/images/platform_logos/wechat.png', import.meta.url).href - } else if (name === 'lark') { - return new URL('@/assets/images/platform_logos/lark.png', import.meta.url).href - } else if (name === 'dingtalk') { - return new URL('@/assets/images/platform_logos/dingtalk.svg', import.meta.url).href - } else if (name === 'telegram') { - return new URL('@/assets/images/platform_logos/telegram.svg', import.meta.url).href - } else if (name === 'discord') { - return new URL('@/assets/images/platform_logos/discord.svg', import.meta.url).href - } else if (name === 'slack') { - return new URL('@/assets/images/platform_logos/slack.svg', import.meta.url).href - } else if (name === 'kook') { - return new URL('@/assets/images/platform_logos/kook.png', import.meta.url).href - } else if (name === 'vocechat') { - return new URL('@/assets/images/platform_logos/vocechat.png', import.meta.url).href - } else if (name === 'satori' || name === 'Satori') { - return new URL('@/assets/images/platform_logos/satori.png', import.meta.url).href - } else if (name === 'misskey') { - return new URL('@/assets/images/platform_logos/misskey.png', import.meta.url).href - } - }, - - getTutorialLink(platform_type) { - let tutorial_map = { - "qq_official_webhook": "https://docs.astrbot.app/deploy/platform/qqofficial/webhook.html", - "qq_official": "https://docs.astrbot.app/deploy/platform/qqofficial/websockets.html", - "aiocqhttp": "https://docs.astrbot.app/deploy/platform/aiocqhttp/napcat.html", - "wecom": "https://docs.astrbot.app/deploy/platform/wecom.html", - "lark": "https://docs.astrbot.app/deploy/platform/lark.html", - "telegram": "https://docs.astrbot.app/deploy/platform/telegram.html", - "dingtalk": "https://docs.astrbot.app/deploy/platform/dingtalk.html", - "wechatpadpro": "https://docs.astrbot.app/deploy/platform/wechat/wechatpadpro.html", - "weixin_official_account": "https://docs.astrbot.app/deploy/platform/weixin-official-account.html", - "discord": "https://docs.astrbot.app/deploy/platform/discord.html", - "slack": "https://docs.astrbot.app/deploy/platform/slack.html", - "kook": "https://docs.astrbot.app/deploy/platform/kook.html", - "vocechat": "https://docs.astrbot.app/deploy/platform/vocechat.html", - "satori": "https://docs.astrbot.app/deploy/platform/satori/llonebot.html", - "misskey": "https://docs.astrbot.app/deploy/platform/misskey.html", - } - return tutorial_map[platform_type] || "https://docs.astrbot.app"; - }, - - getPlatformDescription(template, name) { - // special judge for community platforms - if (name.includes('vocechat')) { - return "由 @HikariFroya 提供。"; - } else if (name.includes('kook')) { - return "由 @wuyan1003 提供。" - } - }, - getConfig() { axios.get('/api/config/get').then((res) => { this.config_data = res.data.data.config; @@ -358,7 +258,7 @@ export default { }); }, - // 添加一个新方法来选择平台模板 + // 选择平台模板 selectPlatformTemplate(name) { this.newSelectedPlatformName = name; this.showPlatformCfg = true; @@ -366,7 +266,6 @@ export default { this.newSelectedPlatformConfig = JSON.parse(JSON.stringify( this.metadata['platform_group']?.metadata?.platform?.config_template[name] || {} )); - this.showAddPlatformDialog = false; }, addFromDefaultConfigTmpl(index) { @@ -483,7 +382,7 @@ export default { this.oneBotEmptyTokenWarningResolve(continueWithWarning); this.oneBotEmptyTokenWarningResolve = null; } - + if (!continueWithWarning) { this.loading = false; } @@ -535,84 +434,4 @@ export default { padding: 20px; padding-top: 8px; } - -.platform-selection-dialog .v-card-title { - border-top-left-radius: 4px; - border-top-right-radius: 4px; -} - -.platform-card { - transition: all 0.3s ease; - height: 100%; - cursor: pointer; - overflow: hidden; - position: relative; -} - -.platform-card:hover { - transform: translateY(-4px); - box-shadow: 0 4px 25px 0 rgba(0, 0, 0, 0.05); - border-color: var(--v-primary-base); -} - -.platform-card-content { - display: flex; - align-items: center; - height: 100px; - padding: 16px; - position: relative; - z-index: 2; -} - -.platform-card-text { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; -} - -.platform-card-title { - font-size: 15px; - font-weight: 600; - margin-bottom: 4px; - padding: 0; -} - -.platform-card-description { - padding: 0; - margin: 0; -} - -.platform-card-logo { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 80px; - display: flex; - align-items: center; - justify-content: center; - z-index: 1; -} - -.platform-logo-img { - max-width: 60px; - max-height: 60px; - opacity: 0.6; - object-fit: contain; -} - -.platform-logo-fallback { - width: 50px; - height: 50px; - border-radius: 50%; - background-color: var(--v-primary-base); - color: white; - display: flex; - align-items: center; - justify-content: center; - font-size: 24px; - font-weight: bold; - opacity: 0.3; -} diff --git a/dashboard/src/views/ProviderPage.vue b/dashboard/src/views/ProviderPage.vue index b36c0db21..5da5bd47b 100644 --- a/dashboard/src/views/ProviderPage.vue +++ b/dashboard/src/views/ProviderPage.vue @@ -155,86 +155,15 @@ - - - - mdi-plus-circle - {{ tm('dialogs.addProvider.title') }} - - - mdi-close - - - - - - - mdi-message-text - {{ tm('dialogs.addProvider.tabs.basic') }} - - - mdi-microphone-message - {{ tm('dialogs.addProvider.tabs.speechToText') }} - - - mdi-volume-high - {{ tm('dialogs.addProvider.tabs.textToSpeech') }} - - - mdi-code-json - {{ tm('dialogs.addProvider.tabs.embedding') }} - - - mdi-compare-vertical - {{ tm('dialogs.addProvider.tabs.rerank') }} - - - - - - - - -
-
- 接入 {{ name }} - - {{ getProviderDescription(template, name) }} - -
- -
-
-
- - - {{ tm('dialogs.addProvider.noTemplates', { type: getTabTypeName(tabType) }) }} - - -
-
-
-
-
-
+ - - - {{ updatingMode ? 'mdi-pencil' : 'mdi-plus' }} - {{ updatingMode ? tm('dialogs.config.editTitle') : tm('dialogs.config.addTitle') }} {{ newSelectedProviderName }} {{ tm('dialogs.config.provider') }} - - +