Merge pull request #1896 from AstrBotDevs/perf-webui-dialog-logo
Improve: improve styles of creating adapter dialog
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="2500" height="2500"><path fill="#4285F4" d="M1024 155.733C1024 70.4 953.6 0 868.267 0H155.733C70.4 0 0 70.4 0 155.733v712.534C0 953.6 70.4 1024 155.733 1024h712.534C953.6 1024 1024 953.6 1024 868.267V155.733z"/><path fill="#FFF" d="M810.667 422.4c-2.134 6.4-4.267 14.933-8.534 23.467C774.4 505.6 701.867 620.8 701.867 620.8l-21.334 36.267h102.4L588.8 915.2l44.8-174.933h-78.933l27.733-115.2c-23.467 6.4-49.067 12.8-81.067 23.466 0 0-42.666 25.6-121.6-46.933 0 0-53.333-46.933-23.466-59.733 12.8-4.267 64-10.667 104.533-17.067 55.467-6.4 87.467-10.667 87.467-10.667s-168.534 2.134-206.934-4.266c-40.533-6.4-89.6-72.534-100.266-132.267 0 0-17.067-32 36.266-17.067s268.8 59.734 268.8 59.734-281.6-87.467-300.8-108.8c-19.2-21.334-55.466-115.2-51.2-172.8 0 0 2.134-14.934 17.067-10.667 0 0 209.067 96 352 147.2 140.8 53.333 264.533 81.067 247.467 147.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 928 B |
@@ -0,0 +1 @@
|
||||
<svg height="1828" viewBox="-10.63 -.07077792 823.87 610.06955549" width="2500" xmlns="http://www.w3.org/2000/svg"><path d="m678.27 51.62c90.35 132.84 134.97 282.68 118.29 455.18-.07.73-.45 1.4-1.05 1.84-68.42 50.24-134.71 80.73-200.07 100.95a2.55 2.55 0 0 1 -2.81-.95c-15.1-21.01-28.82-43.16-40.84-66.42-.69-1.37-.06-3.02 1.36-3.56 21.79-8.21 42.51-18.05 62.44-29.7 1.57-.92 1.67-3.17.22-4.25-4.23-3.14-8.42-6.44-12.43-9.74-.75-.61-1.76-.73-2.61-.32-129.39 59.75-271.13 59.75-402.05 0-.85-.38-1.86-.25-2.59.35-4 3.3-8.2 6.57-12.39 9.71-1.45 1.08-1.33 3.33.25 4.25 19.93 11.43 40.65 21.49 62.41 29.74 1.41.54 2.08 2.15 1.38 3.52-11.76 23.29-25.48 45.44-40.86 66.45-.67.85-1.77 1.24-2.81.92-65.05-20.22-131.34-50.71-199.76-100.95-.57-.44-.98-1.14-1.04-1.87-13.94-149.21 14.47-300.29 118.18-455.18.25-.41.63-.73 1.07-.92 51.03-23.42 105.7-40.65 162.84-50.49 1.04-.16 2.08.32 2.62 1.24 7.06 12.5 15.13 28.53 20.59 41.63 60.23-9.2 121.4-9.2 182.89 0 5.46-12.82 13.25-29.13 20.28-41.63a2.47 2.47 0 0 1 2.62-1.24c57.17 9.87 111.84 27.1 162.83 50.49.45.19.82.51 1.04.95zm-339.04 283.7c.63-44.11-31.53-80.61-71.9-80.61-40.04 0-71.89 36.18-71.89 80.61 0 44.42 32.48 80.6 71.89 80.6 40.05 0 71.9-36.18 71.9-80.6zm265.82 0c.63-44.11-31.53-80.61-71.89-80.61-40.05 0-71.9 36.18-71.9 80.61 0 44.42 32.48 80.6 71.9 80.6 40.36 0 71.89-36.18 71.89-80.6z" fill="#5865f2"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg enable-background="new 0 0 2447.6 2452.5" viewBox="0 0 2447.6 2452.5" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill-rule="evenodd"><path d="m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z" fill="#36c5f0"/><path d="m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z" fill="#2eb67d"/><path d="m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z" fill="#ecb22e"/><path d="m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0" fill="#e01e5a"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="svg2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="2500" height="2500"><style>.st0{fill:url(#path2995-1-0_1_)}.st1{fill:#c8daea}.st2{fill:#a9c9dd}.st3{fill:url(#path2991_1_)}</style><linearGradient id="path2995-1-0_1_" gradientUnits="userSpaceOnUse" x1="-683.305" y1="534.845" x2="-693.305" y2="511.512" gradientTransform="matrix(6 0 0 -6 4255 3247)"><stop offset="0" stop-color="#37aee2"/><stop offset="1" stop-color="#1e96c8"/></linearGradient><path id="path2995-1-0" class="st0" d="M240 120c0 66.3-53.7 120-120 120S0 186.3 0 120 53.7 0 120 0s120 53.7 120 120z"/><path id="path2993" class="st1" d="M98 175c-3.9 0-3.2-1.5-4.6-5.2L82 132.2 152.8 88l8.3 2.2-6.9 18.8L98 175z"/><path id="path2989" class="st2" d="M98 175c3 0 4.3-1.4 6-3 2.6-2.5 36-35 36-35l-20.5-5-19 12-2.5 30v1z"/><linearGradient id="path2991_1_" gradientUnits="userSpaceOnUse" x1="128.991" y1="118.245" x2="153.991" y2="78.245" gradientTransform="matrix(1 0 0 -1 0 242)"><stop offset="0" stop-color="#eff7fc"/><stop offset="1" stop-color="#fff"/></linearGradient><path id="path2991" class="st3" d="M100 144.4l48.4 35.7c5.5 3 9.5 1.5 10.9-5.1L179 82.2c2-8.1-3.1-11.7-8.4-9.3L55 117.5c-7.9 3.2-7.8 7.6-1.4 9.5l29.7 9.3L152 93c3.2-2 6.2-.9 3.8 1.3L100 144.4z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
@@ -20,7 +20,8 @@
|
||||
"adapter": "Platform Adapter",
|
||||
"refresh": "Refresh",
|
||||
"cancel": "Cancel",
|
||||
"save": "Save"
|
||||
"save": "Save",
|
||||
"addPlatform": "Add Platform Adapter"
|
||||
},
|
||||
"messages": {
|
||||
"updateSuccess": "Update successful!",
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"typed": "No {type} type service providers available, click Add Provider to add one"
|
||||
},
|
||||
"description": {
|
||||
"openai": "{type} service provider. Also supports all OpenAI API compatible model providers.",
|
||||
"default": "{type} service provider"
|
||||
"openai": "Supports all OpenAI API compatible providers.",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
"availability": {
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
"adapter": "平台适配器",
|
||||
"refresh": "刷新",
|
||||
"cancel": "取消",
|
||||
"save": "保存"
|
||||
"save": "保存",
|
||||
"addPlatform": "添加平台适配器"
|
||||
},
|
||||
"messages": {
|
||||
"updateSuccess": "更新成功!",
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"typed": "暂无{type}类型的服务提供商,点击 新增服务提供商 添加"
|
||||
},
|
||||
"description": {
|
||||
"openai": "{type} 服务提供商。同时也支持所有兼容 OpenAI API 的模型提供商。",
|
||||
"default": "{type} 服务提供商"
|
||||
"openai": "也支持所有兼容 OpenAI API 的模型提供商。",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
"availability": {
|
||||
|
||||
@@ -12,19 +12,6 @@ export const useCommonStore = defineStore({
|
||||
log_cache_max_len: 1000,
|
||||
startTime: -1,
|
||||
|
||||
tutorial_map: {
|
||||
"qq_official_webhook": "https://astrbot.app/deploy/platform/qqofficial/webhook.html",
|
||||
"qq_official": "https://astrbot.app/deploy/platform/qqofficial/websockets.html",
|
||||
"aiocqhttp": "https://astrbot.app/deploy/platform/aiocqhttp/napcat.html",
|
||||
"wecom": "https://astrbot.app/deploy/platform/wecom.html",
|
||||
"gewechat": "https://astrbot.app/deploy/platform/wechat/gewechat.html",
|
||||
"lark": "https://astrbot.app/deploy/platform/lark.html",
|
||||
"telegram": "https://astrbot.app/deploy/platform/telegram.html",
|
||||
"dingtalk": "https://astrbot.app/deploy/platform/dingtalk.html",
|
||||
"wechatpadpro": "https://astrbot.app/deploy/platform/wechat/wechatpadpro.html",
|
||||
"weixin_official_account": "https://astrbot.app/deploy/platform/weixin-official-account.html",
|
||||
},
|
||||
|
||||
pluginMarketData: [],
|
||||
}),
|
||||
actions: {
|
||||
@@ -124,9 +111,6 @@ export const useCommonStore = defineStore({
|
||||
this.startTime = res.data.data.start_time
|
||||
})
|
||||
},
|
||||
getTutorialLink(platform) {
|
||||
return this.tutorial_map[platform]
|
||||
},
|
||||
async getPluginCollections(force = false) {
|
||||
// 获取插件市场数据
|
||||
if (!force && this.pluginMarketData.length > 0) {
|
||||
|
||||
@@ -20,43 +20,22 @@
|
||||
<span class="text-h6">{{ tm('adapters') }}</span>
|
||||
<v-chip color="info" size="small" class="ml-2">{{ config_data.platform?.length || 0 }}</v-chip>
|
||||
<v-spacer></v-spacer>
|
||||
<v-menu>
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" variant="tonal" v-bind="props">
|
||||
{{ tm('addAdapter') }}
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list @update:selected="addFromDefaultConfigTmpl($event)">
|
||||
<v-list-item
|
||||
v-for="(item, index) in metadata['platform_group']?.metadata?.platform?.config_template || {}"
|
||||
:key="index"
|
||||
rounded="xl"
|
||||
:value="index"
|
||||
>
|
||||
<v-list-item-title>{{ index }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" variant="tonal" @click="showAddPlatformDialog = true">
|
||||
{{ tm('addAdapter') }}
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-card-text class="px-4 py-3">
|
||||
<item-card-grid
|
||||
:items="config_data.platform || []"
|
||||
title-field="id"
|
||||
enabled-field="enable"
|
||||
empty-icon="mdi-connection"
|
||||
:empty-text="tm('emptyText')"
|
||||
@toggle-enabled="platformStatusChange"
|
||||
@delete="deletePlatform"
|
||||
@edit="editPlatform"
|
||||
>
|
||||
<item-card-grid :items="config_data.platform || []" title-field="id" enabled-field="enable"
|
||||
empty-icon="mdi-connection" :empty-text="tm('emptyText')" @toggle-enabled="platformStatusChange"
|
||||
@delete="deletePlatform" @edit="editPlatform">
|
||||
<template v-slot:item-details="{ item }">
|
||||
<div class="d-flex align-center mb-2">
|
||||
<v-icon size="small" color="grey" class="me-2">mdi-tag</v-icon>
|
||||
<span class="text-caption text-medium-emphasis">
|
||||
{{ tm('details.adapterType') }}:
|
||||
{{ tm('details.adapterType') }}:
|
||||
<v-chip size="x-small" color="primary" class="ml-1">{{ item.type }}</v-chip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -95,36 +74,79 @@
|
||||
</v-card>
|
||||
</v-container>
|
||||
|
||||
<!-- 配置对话框 -->
|
||||
<v-dialog v-model="showPlatformCfg" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="bg-primary text-white py-3">
|
||||
<v-icon color="white" class="me-2">{{ updatingMode ? 'mdi-pencil' : 'mdi-plus' }}</v-icon>
|
||||
<span>{{ updatingMode ? tm('dialog.edit') : tm('dialog.add') }} {{ newSelectedPlatformName }} {{ tm('dialog.adapter') }}</span>
|
||||
<!-- 添加平台适配器对话框 -->
|
||||
<v-dialog v-model="showAddPlatformDialog" max-width="900px" min-height="80%">
|
||||
<v-card class="platform-selection-dialog">
|
||||
<v-card-title class="bg-primary text-white py-3 px-4" style="display: flex; align-items: center;">
|
||||
<v-icon color="white" class="me-2">mdi-plus-circle</v-icon>
|
||||
<span>{{ tm('dialog.addPlatform') }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon variant="text" color="white" @click="showAddPlatformDialog = false">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="py-4">
|
||||
<v-row>
|
||||
<v-col cols="12" md="8">
|
||||
<AstrBotConfig :iterable="newSelectedPlatformConfig"
|
||||
:metadata="metadata['platform_group']?.metadata"
|
||||
metadataKey="platform" />
|
||||
|
||||
<v-card-text class="pa-4" style="overflow-y: auto;">
|
||||
<v-row class="mt-1">
|
||||
<v-col v-for="(template, name) in metadata['platform_group']?.metadata?.platform?.config_template || {}"
|
||||
:key="name" cols="12" sm="6" md="6">
|
||||
<v-card variant="outlined" hover class="platform-card" @click="selectPlatformTemplate(name)">
|
||||
<div class="platform-card-content">
|
||||
<div class="platform-card-text">
|
||||
<v-card-title class="platform-card-title">接入 {{ name }}</v-card-title>
|
||||
<v-card-text class="text-caption text-medium-emphasis platform-card-description">
|
||||
{{ getPlatformDescription(template, name) }}
|
||||
</v-card-text>
|
||||
</div>
|
||||
<div class="platform-card-logo">
|
||||
<img :src="getPlatformIcon(name)" v-if="getPlatformIcon(name)" class="platform-logo-img">
|
||||
<div v-else class="platform-logo-fallback">
|
||||
{{ name[0].toUpperCase() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4" class="d-flex flex-column align-end">
|
||||
<v-btn :loading="iframeLoading" @click="refreshIframe" variant="tonal" color="primary">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
{{ tm('dialog.refresh') }}
|
||||
</v-btn>
|
||||
<iframe v-show="!iframeLoading"
|
||||
:src="store.getTutorialLink(newSelectedPlatformConfig.type)"
|
||||
@load="iframeLoading = false" style="width: 100%; border: none; min-height: 400px; margin-top: 10px; flex: 1;">
|
||||
</iframe>
|
||||
<v-col
|
||||
v-if="Object.keys(metadata['platform_group']?.metadata?.platform?.config_template || {}).length === 0"
|
||||
cols="12">
|
||||
<v-alert type="info" variant="tonal">
|
||||
{{ tm('dialog.noTemplates') }}
|
||||
</v-alert>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 配置对话框 -->
|
||||
<v-dialog v-model="showPlatformCfg" persistent width="900px" max-width="90%">
|
||||
<v-card>
|
||||
<v-card-title class="bg-primary text-white py-3">
|
||||
<v-icon color="white" class="me-2">{{ updatingMode ? 'mdi-pencil' : 'mdi-plus' }}</v-icon>
|
||||
<span>{{ updatingMode ? tm('dialog.edit') : tm('dialog.add') }} {{ newSelectedPlatformName }} {{
|
||||
tm('dialog.adapter') }}</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="py-4">
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<AstrBotConfig :iterable="newSelectedPlatformConfig" :metadata="metadata['platform_group']?.metadata"
|
||||
metadataKey="platform" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row class="mt-2">
|
||||
<v-col cols="12" class="text-center">
|
||||
<v-btn color="info" variant="outlined" @click="openTutorial">
|
||||
<v-icon start>mdi-book-open-variant</v-icon>
|
||||
查看接入教程
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn variant="text" @click="showPlatformCfg = false" :disabled="loading">
|
||||
@@ -142,8 +164,25 @@
|
||||
location="top">
|
||||
{{ save_message }}
|
||||
</v-snackbar>
|
||||
|
||||
|
||||
<WaitingForRestart ref="wfr"></WaitingForRestart>
|
||||
|
||||
<!-- ID冲突确认对话框 -->
|
||||
<v-dialog v-model="showIdConflictDialog" max-width="450" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="text-h6 bg-warning d-flex align-center">
|
||||
<v-icon start class="me-2">mdi-alert-circle-outline</v-icon>
|
||||
ID 冲突警告
|
||||
</v-card-title>
|
||||
<v-card-text class="py-4 text-body-1 text-medium-emphasis">
|
||||
检测到 ID "{{ conflictId }}" 重复。请使用一个新的 ID。
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" variant="text" @click="handleIdConflictConfirm(false)">好的</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -167,7 +206,7 @@ export default {
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { tm } = useModuleI18n('features/platform');
|
||||
|
||||
|
||||
return {
|
||||
t,
|
||||
tm
|
||||
@@ -191,6 +230,7 @@ export default {
|
||||
fetched: false,
|
||||
metadata: {},
|
||||
showPlatformCfg: false,
|
||||
showAddPlatformDialog: false,
|
||||
|
||||
newSelectedPlatformName: '',
|
||||
newSelectedPlatformConfig: {},
|
||||
@@ -203,23 +243,89 @@ export default {
|
||||
save_message_success: "success",
|
||||
|
||||
showConsole: false,
|
||||
iframeLoading: true,
|
||||
|
||||
// ID冲突确认对话框
|
||||
showIdConflictDialog: false,
|
||||
conflictId: '',
|
||||
idConflictResolve: null,
|
||||
|
||||
store: useCommonStore()
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
showIdConflictDialog(newValue) {
|
||||
// 当对话框关闭时,如果 Promise 还在等待,则拒绝它以防止内存泄漏
|
||||
if (!newValue && this.idConflictResolve) {
|
||||
this.idConflictResolve(false);
|
||||
this.idConflictResolve = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getConfig();
|
||||
},
|
||||
|
||||
methods: {
|
||||
refreshIframe() {
|
||||
this.iframeLoading = true;
|
||||
const iframe = document.querySelector('iframe');
|
||||
iframe.src = iframe.src + '?t=' + new Date().getTime();
|
||||
openTutorial() {
|
||||
const tutorialUrl = this.getTutorialLink(this.newSelectedPlatformConfig.type);
|
||||
window.open(tutorialUrl, '_blank');
|
||||
},
|
||||
|
||||
|
||||
getPlatformIcon(name) {
|
||||
if (name.includes('QQ')) {
|
||||
return '/src/assets/images/platform_logos/qq.png'
|
||||
} else if (name.includes('企业微信')) {
|
||||
return '/src/assets/images/platform_logos/wecom.png'
|
||||
} else if (name.includes('微信')) {
|
||||
return '/src/assets/images/platform_logos/wechat.png';
|
||||
} else if (name.includes('Lark')) {
|
||||
return '/src/assets/images/platform_logos/lark.png';
|
||||
} else if (name.includes('DingTalk')) {
|
||||
return '/src/assets/images/platform_logos/dingtalk.svg';
|
||||
} else if (name.includes('Telegram')) {
|
||||
return '/src/assets/images/platform_logos/telegram.svg';
|
||||
} else if (name.includes('Discord')) {
|
||||
return '/src/assets/images/platform_logos/discord.svg';
|
||||
} else if (name.includes('Slack')) {
|
||||
return '/src/assets/images/platform_logos/slack.svg';
|
||||
} else if (name.includes('kook')) {
|
||||
return '/src/assets/images/platform_logos/kook.png';
|
||||
} else if (name.includes('vocechat')) {
|
||||
return '/src/assets/images/platform_logos/vocechat.png';
|
||||
}
|
||||
},
|
||||
|
||||
getTutorialLink(platform_type) {
|
||||
let tutorial_map = {
|
||||
"qq_official_webhook": "https://astrbot.app/deploy/platform/qqofficial/webhook.html",
|
||||
"qq_official": "https://astrbot.app/deploy/platform/qqofficial/websockets.html",
|
||||
"aiocqhttp": "https://astrbot.app/deploy/platform/aiocqhttp/napcat.html",
|
||||
"wecom": "https://astrbot.app/deploy/platform/wecom.html",
|
||||
"gewechat": "https://astrbot.app/deploy/platform/wechat/gewechat.html",
|
||||
"lark": "https://astrbot.app/deploy/platform/lark.html",
|
||||
"telegram": "https://astrbot.app/deploy/platform/telegram.html",
|
||||
"dingtalk": "https://astrbot.app/deploy/platform/dingtalk.html",
|
||||
"wechatpadpro": "https://astrbot.app/deploy/platform/wechat/wechatpadpro.html",
|
||||
"weixin_official_account": "https://astrbot.app/deploy/platform/weixin-official-account.html",
|
||||
"discord": "https://astrbot.app/deploy/platform/discord.html",
|
||||
"slack": "https://astrbot.app/deploy/platform/slack.html",
|
||||
"kook": "https://astrbot.app/deploy/platform/kook.html",
|
||||
"vocechat": "https://astrbot.app/deploy/platform/vocechat.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;
|
||||
@@ -230,6 +336,17 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
// 添加一个新方法来选择平台模板
|
||||
selectPlatformTemplate(name) {
|
||||
this.newSelectedPlatformName = name;
|
||||
this.showPlatformCfg = true;
|
||||
this.updatingMode = false;
|
||||
this.newSelectedPlatformConfig = JSON.parse(JSON.stringify(
|
||||
this.metadata['platform_group']?.metadata?.platform?.config_template[name] || {}
|
||||
));
|
||||
this.showAddPlatformDialog = false;
|
||||
},
|
||||
|
||||
addFromDefaultConfigTmpl(index) {
|
||||
this.newSelectedPlatformName = index[0];
|
||||
this.showPlatformCfg = true;
|
||||
@@ -264,18 +381,48 @@ export default {
|
||||
});
|
||||
this.updatingMode = false;
|
||||
} else {
|
||||
axios.post('/api/config/platform/new', this.newSelectedPlatformConfig).then((res) => {
|
||||
this.loading = false;
|
||||
this.showPlatformCfg = false;
|
||||
this.getConfig();
|
||||
this.showSuccess(res.data.message || this.messages.addSuccess);
|
||||
}).catch((err) => {
|
||||
this.loading = false;
|
||||
this.showError(err.response?.data?.message || err.message);
|
||||
});
|
||||
this.savePlatform();
|
||||
}
|
||||
},
|
||||
|
||||
async savePlatform() {
|
||||
// 检查 ID 是否已存在
|
||||
const existingPlatform = this.config_data.platform?.find(p => p.id === this.newSelectedPlatformConfig.id);
|
||||
if (existingPlatform) {
|
||||
const confirmed = await this.confirmIdConflict(this.newSelectedPlatformConfig.id);
|
||||
if (!confirmed) {
|
||||
this.loading = false;
|
||||
return; // 如果用户取消,则中止保存
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await axios.post('/api/config/platform/new', this.newSelectedPlatformConfig);
|
||||
this.loading = false;
|
||||
this.showPlatformCfg = false;
|
||||
this.getConfig();
|
||||
this.showSuccess(res.data.message || this.messages.addSuccess);
|
||||
} catch (err) {
|
||||
this.loading = false;
|
||||
this.showError(err.response?.data?.message || err.message);
|
||||
}
|
||||
},
|
||||
|
||||
confirmIdConflict(id) {
|
||||
this.conflictId = id;
|
||||
this.showIdConflictDialog = true;
|
||||
return new Promise((resolve) => {
|
||||
this.idConflictResolve = resolve;
|
||||
});
|
||||
},
|
||||
|
||||
handleIdConflictConfirm(confirmed) {
|
||||
if (this.idConflictResolve) {
|
||||
this.idConflictResolve(confirmed);
|
||||
}
|
||||
this.showIdConflictDialog = false;
|
||||
},
|
||||
|
||||
deletePlatform(platform) {
|
||||
if (confirm(`${this.messages.deleteConfirm} ${platform.id}?`)) {
|
||||
axios.post('/api/config/platform/delete', { id: platform.id }).then((res) => {
|
||||
@@ -290,7 +437,7 @@ export default {
|
||||
|
||||
platformStatusChange(platform) {
|
||||
platform.enable = !platform.enable; // 切换状态
|
||||
|
||||
|
||||
axios.post('/api/config/platform/update', {
|
||||
id: platform.id,
|
||||
config: platform
|
||||
@@ -303,13 +450,13 @@ export default {
|
||||
this.showError(err.response?.data?.message || err.message);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
showSuccess(message) {
|
||||
this.save_message = message;
|
||||
this.save_message_success = "success";
|
||||
this.save_message_snack = true;
|
||||
},
|
||||
|
||||
|
||||
showError(message) {
|
||||
this.save_message = message;
|
||||
this.save_message_success = "error";
|
||||
@@ -324,4 +471,84 @@ 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;
|
||||
}
|
||||
</style>
|
||||
@@ -198,20 +198,20 @@
|
||||
:key="name"
|
||||
cols="12" sm="6" md="4">
|
||||
<v-card variant="outlined" hover class="provider-card" @click="selectProviderTemplate(name)">
|
||||
<v-card-item>
|
||||
<template v-slot:prepend>
|
||||
<v-avatar color="primary" variant="tonal" class="mr-3">
|
||||
<img :src="getProviderIcon(name)" v-if="getProviderIcon(name)" width="24" height="24">
|
||||
<span v-else style="font-weight: 1000;">
|
||||
{{ name[0].toUpperCase() }}
|
||||
</span>
|
||||
</v-avatar>
|
||||
</template>
|
||||
<v-card-title style="font-size: 15px;">{{ name }}</v-card-title>
|
||||
</v-card-item>
|
||||
<v-card-text class="text-caption text-medium-emphasis">
|
||||
{{ getProviderDescription(template, name) }}
|
||||
</v-card-text>
|
||||
<div class="provider-card-content">
|
||||
<div class="provider-card-text">
|
||||
<v-card-title class="provider-card-title">接入 {{ name }}</v-card-title>
|
||||
<v-card-text class="text-caption text-medium-emphasis provider-card-description">
|
||||
{{ getProviderDescription(template, name) }}
|
||||
</v-card-text>
|
||||
</div>
|
||||
<div class="provider-card-logo">
|
||||
<img :src="getProviderIcon(name)" v-if="getProviderIcon(name)" class="provider-logo-img">
|
||||
<div v-else class="provider-logo-fallback">
|
||||
{{ name[0].toUpperCase() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col v-if="Object.keys(getTemplatesByType(tabType)).length === 0" cols="12">
|
||||
@@ -307,6 +307,23 @@
|
||||
|
||||
<WaitingForRestart ref="wfr"></WaitingForRestart>
|
||||
|
||||
<!-- ID冲突确认对话框 -->
|
||||
<v-dialog v-model="showIdConflictDialog" max-width="450" persistent>
|
||||
<v-card>
|
||||
<v-card-title class="text-h6 bg-warning d-flex align-center">
|
||||
<v-icon start class="me-2">mdi-alert-circle-outline</v-icon>
|
||||
ID 冲突警告
|
||||
</v-card-title>
|
||||
<v-card-text class="py-4 text-body-1 text-medium-emphasis">
|
||||
检测到 ID "{{ conflictId }}" 重复。请使用一个新的 ID。
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" variant="text" @click="handleIdConflictConfirm(false)">好的</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Key为空的确认对话框 -->
|
||||
<v-dialog v-model="showKeyConfirm" max-width="450" persistent>
|
||||
<v-card>
|
||||
@@ -359,6 +376,11 @@ export default {
|
||||
sessionSeparationEnabled: false,
|
||||
sessionSettingLoading: false,
|
||||
|
||||
// ID冲突确认对话框
|
||||
showIdConflictDialog: false,
|
||||
conflictId: '',
|
||||
idConflictResolve: null,
|
||||
|
||||
// Key确认对话框
|
||||
showKeyConfirm: false,
|
||||
keyConfirmResolve: null,
|
||||
@@ -411,6 +433,13 @@ export default {
|
||||
},
|
||||
|
||||
watch: {
|
||||
showIdConflictDialog(newValue) {
|
||||
// 当对话框关闭时,如果 Promise 还在等待,则拒绝它以防止内存泄漏
|
||||
if (!newValue && this.idConflictResolve) {
|
||||
this.idConflictResolve(false);
|
||||
this.idConflictResolve = null;
|
||||
}
|
||||
},
|
||||
showKeyConfirm(newValue) {
|
||||
// 当对话框关闭时,如果 Promise 还在等待,则拒绝它以防止内存泄漏
|
||||
if (!newValue && this.keyConfirmResolve) {
|
||||
@@ -645,6 +674,16 @@ export default {
|
||||
});
|
||||
this.showSuccess(res.data.message || "更新成功!");
|
||||
} else {
|
||||
// 检查 ID 是否已存在
|
||||
const existingProvider = this.config_data.provider?.find(p => p.id === this.newSelectedProviderConfig.id);
|
||||
if (existingProvider) {
|
||||
const confirmed = await this.confirmIdConflict(this.newSelectedProviderConfig.id);
|
||||
if (!confirmed) {
|
||||
this.loading = false;
|
||||
return; // 如果用户取消,则中止保存
|
||||
}
|
||||
}
|
||||
|
||||
const res = await axios.post('/api/config/provider/new', this.newSelectedProviderConfig);
|
||||
this.showSuccess(res.data.message || "添加成功!");
|
||||
}
|
||||
@@ -753,6 +792,21 @@ export default {
|
||||
}
|
||||
this.showKeyConfirm = false;
|
||||
},
|
||||
|
||||
confirmIdConflict(id) {
|
||||
this.conflictId = id;
|
||||
this.showIdConflictDialog = true;
|
||||
return new Promise((resolve) => {
|
||||
this.idConflictResolve = resolve;
|
||||
});
|
||||
},
|
||||
|
||||
handleIdConflictConfirm(confirmed) {
|
||||
if (this.idConflictResolve) {
|
||||
this.idConflictResolve(confirmed);
|
||||
}
|
||||
this.showIdConflictDialog = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -772,6 +826,8 @@ export default {
|
||||
transition: all 0.3s ease;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.provider-card:hover {
|
||||
@@ -780,6 +836,67 @@ export default {
|
||||
border-color: var(--v-primary-base);
|
||||
}
|
||||
|
||||
.provider-card-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.provider-card-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.provider-card-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.provider-card-description {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.provider-card-logo {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.provider-logo-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
opacity: 0.6;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.provider-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;
|
||||
}
|
||||
|
||||
.v-tabs {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||