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 @@
+
+
+
+
+
+
+
+
+
+ {{ tm('dialog.connectTitle', { name }) }}
+
+ {{ getPlatformDescription(template, name) }}
+
+
+
+
+
+
+
+
+ {{ tm('dialog.noTemplates') }}
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+ 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) }}
+
+
+
+
![]()
+
+ {{ name[0].toUpperCase() }}
+
+
+
+
+
+
+
+ {{ tm('dialogs.addProvider.noTemplates', { type: getTabTypeName(tabType) }) }}
+
+
+
+
+
+
+
+
+
+ Close
+
+
+
+
+
+
+
+
+
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) }}
-
-
-
-
![]()
-
- {{ name[0].toUpperCase() }}
-
-
-
-
-
-
-
- {{ 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') }}
-
-
+