feat: enhance AddNewPlatform and ConfigPage components with improved configuration management and UI interactions

This commit is contained in:
Soulter
2025-10-26 16:57:01 +08:00
parent c1626613ce
commit 5e2eb91ac0
2 changed files with 152 additions and 35 deletions
@@ -89,10 +89,16 @@
<span>使用现有配置文件</span>
</template>
</v-radio>
<v-select v-if="aBConfigRadioVal === '0'" v-model="selectedAbConfId" :items="configInfoList"
item-title="name" item-value="id" label="选择配置文件" variant="outlined" rounded="md" dense hide-details
style="max-width: 30%; min-width: 200px;" class="ml-10 my-2">
</v-select>
<div class="d-flex align-center ml-10 my-2" v-if="aBConfigRadioVal === '0'">
<v-select v-model="selectedAbConfId" :items="configInfoList" item-title="name"
item-value="id" label="选择配置文件" variant="outlined" rounded="md" dense hide-details
style="max-width: 30%; min-width: 200px;">
</v-select>
<v-btn icon variant="text" density="comfortable" class="ml-2"
:disabled="!selectedAbConfId" @click="openConfigDrawer(selectedAbConfId)">
<v-icon>mdi-arrow-top-right-thick</v-icon>
</v-btn>
</div>
<v-radio value="1" label="创建新配置文件">
</v-radio>
<div class="d-flex align-center" v-if="aBConfigRadioVal === '1'">
@@ -160,23 +166,33 @@
<div class="d-flex align-center" style="min-width: 250px;">
<v-select v-if="isEditingRoutes" v-model="item.messageType" :items="messageTypeOptions"
item-title="label" item-value="value" variant="outlined" density="compact" hide-details
style="max-width: 120px;" class="mr-2">
style="max-width: 140px;">
</v-select>
<span v-else class="mr-2">{{ getMessageTypeLabel(item.messageType) }}</span>
<span class="mx-1">:</span>
<small v-else>{{ getMessageTypeLabel(item.messageType) }}</small>
<small class="mx-1">:</small>
<v-text-field v-if="isEditingRoutes" v-model="item.sessionId" variant="outlined" density="compact"
hide-details placeholder="会话ID或*" style="max-width: 120px;">
hide-details placeholder="会话ID或*">
</v-text-field>
<span v-else>{{ item.sessionId === '*' ? '全部会话' : item.sessionId }}</span>
<small v-else>{{ item.sessionId === '*' ? '全部会话' : item.sessionId }}</small>
</div>
</template>
<template v-slot:item.configId="{ item }">
<v-select v-if="isEditingRoutes" v-model="item.configId" :items="configInfoList" item-title="name"
item-value="id" variant="outlined" density="compact" style="min-width: 200px;" hide-details>
</v-select>
<span v-else>{{ getConfigName(item.configId) }}</span>
<small v-if="configInfoList.findIndex(c => c.id === item.configId) === -1" style="color: red;" class="ml-2">配置文件不存在</small>
<div class="d-flex align-center">
<v-select v-if="isEditingRoutes" v-model="item.configId" :items="configInfoList"
item-title="name" item-value="id" variant="outlined" density="compact"
style="min-width: 200px;" hide-details>
</v-select>
<div v-else>
<small>{{ getConfigName(item.configId) }}</small>
</div>
<v-btn icon variant="text" density="compact" class="ml-2"
:disabled="!item.configId" @click="openConfigDrawer(item.configId)">
<v-icon size="18">mdi-arrow-top-right-thick</v-icon>
</v-btn>
</div>
<small v-if="configInfoList.findIndex(c => c.id === item.configId) === -1" style="color: red;"
class="ml-2">配置文件不存在</small>
</template>
<template v-slot:item.actions="{ item, index }">
@@ -259,6 +275,33 @@
</v-card-actions>
</v-card>
</v-dialog>
<v-overlay
v-model="showConfigDrawer"
class="config-drawer-overlay"
location="right"
transition="slide-x-reverse-transition"
:scrim="true"
@click:outside="closeConfigDrawer"
>
<v-card class="config-drawer-card" elevation="12">
<div class="config-drawer-header">
<div>
<span class="text-h6">配置文件管理</span>
<div v-if="configDrawerTargetId" class="text-caption text-grey">
ID: {{ configDrawerTargetId }}
</div>
</div>
<v-btn icon variant="text" @click="closeConfigDrawer">
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
<v-divider></v-divider>
<div class="config-drawer-content">
<ConfigPage v-if="showConfigDrawer" :initial-config-id="configDrawerTargetId" />
</div>
</v-card>
</v-overlay>
</template>
@@ -268,10 +311,11 @@ import { useModuleI18n } from '@/i18n/composables';
import { getPlatformIcon, getPlatformDescription, getTutorialLink } from '@/utils/platformUtils';
import AstrBotConfig from '@/components/shared/AstrBotConfig.vue';
import AstrBotCoreConfigWrapper from '@/components/config/AstrBotCoreConfigWrapper.vue';
import ConfigPage from '@/views/ConfigPage.vue';
export default {
name: 'AddNewPlatform',
components: { AstrBotConfig, AstrBotCoreConfigWrapper },
components: { AstrBotConfig, AstrBotCoreConfigWrapper, ConfigPage },
emits: ['update:show', 'show-toast', 'refresh-config'],
props: {
show: {
@@ -324,8 +368,8 @@ export default {
// 平台路由表
platformRoutes: [],
routeTableHeaders: [
{ title: '消息会话来源(消息类型:会话 ID)', key: 'source', sortable: false, width: '40%' },
{ title: '使用配置文件', key: 'configId', sortable: false, width: '40%' },
{ title: '消息会话来源(消息类型:会话 ID)', key: 'source', sortable: false, width: '60%' },
{ title: '使用配置文件', key: 'configId', sortable: false, width: '20%' },
{ title: '操作', key: 'actions', sortable: false, align: 'center', width: '20%' },
],
messageTypeOptions: [
@@ -347,6 +391,10 @@ export default {
loading: false,
showConfigSection: false,
// 配置抽屉
showConfigDrawer: false,
configDrawerTargetId: null,
};
},
setup() {
@@ -478,6 +526,9 @@ export default {
this.showConfigSection = false;
this.isEditingRoutes = false; // 重置编辑模式
this.showConfigDrawer = false;
this.configDrawerTargetId = null;
},
closeDialog() {
this.resetForm();
@@ -534,6 +585,19 @@ export default {
const tutorialUrl = getTutorialLink(this.selectedPlatformConfig.type);
window.open(tutorialUrl, '_blank');
},
openConfigDrawer(configId) {
const targetId = configId || 'default';
if (configId && this.configInfoList.findIndex(c => c.id === configId) === -1) {
this.showError('目标配置文件不存在,已打开配置页面以便检查。');
}
this.configDrawerTargetId = targetId;
this.showConfigDrawer = true;
},
closeConfigDrawer() {
this.showConfigDrawer = false;
},
newPlatform() {
this.loading = true;
if (this.updatingMode) {
@@ -906,4 +970,30 @@ export default {
.v-select__selection-text {
font-size: 12px;
}
.config-drawer-overlay {
align-items: stretch;
justify-content: flex-end;
}
.config-drawer-card {
width: clamp(320px, 60vw, 820px);
height: calc(100vh - 32px);
display: flex;
flex-direction: column;
margin: 16px;
}
.config-drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px 12px 20px;
}
.config-drawer-content {
flex: 1;
overflow-y: auto;
padding: 16px 16px 24px 16px;
}
</style>
+45 -18
View File
@@ -8,7 +8,7 @@
<div class="d-flex flex-row pr-4"
style="margin-bottom: 16px; align-items: center; gap: 12px; justify-content: space-between; width: 100%;">
<div class="d-flex flex-row align-center" style="gap: 12px;">
<v-select style="min-width: 130px;" v-model="selectedConfigID" :items="configSelectItems" item-title="name"
<v-select style="min-width: 130px;" v-model="selectedConfigID" :items="configSelectItems" item-title="name" :disabled="initialConfigId !== null"
v-if="!isSystemConfig" item-value="id" label="选择配置文件" hide-details density="compact" rounded="md"
variant="outlined" @update:model-value="onConfigSelect">
</v-select>
@@ -27,24 +27,26 @@
</v-btn-toggle>
</div>
<v-progress-linear v-if="!fetched" indeterminate color="primary"></v-progress-linear>
<!-- <v-progress-linear v-if="!fetched" indeterminate color="primary"></v-progress-linear> -->
<div v-if="(selectedConfigID || isSystemConfig) && fetched" style="width: 100%;">
<!-- 可视化编辑 -->
<AstrBotCoreConfigWrapper
:metadata="metadata"
:config_data="config_data"
/>
<v-slide-y-transition mode="out-in">
<div v-if="(selectedConfigID || isSystemConfig) && fetched" :key="configContentKey" class="config-content" style="width: 100%;">
<!-- 可视化编辑 -->
<AstrBotCoreConfigWrapper
:metadata="metadata"
:config_data="config_data"
/>
<v-btn icon="mdi-content-save" size="x-large" style="position: fixed; right: 52px; bottom: 52px;"
color="darkprimary" @click="updateConfig">
</v-btn>
<v-btn icon="mdi-content-save" size="x-large" style="position: fixed; right: 52px; bottom: 52px;"
color="darkprimary" @click="updateConfig">
</v-btn>
<v-btn icon="mdi-code-json" size="x-large" style="position: fixed; right: 52px; bottom: 124px;" color="primary"
@click="configToString(); codeEditorDialog = true">
</v-btn>
<v-btn icon="mdi-code-json" size="x-large" style="position: fixed; right: 52px; bottom: 124px;" color="primary"
@click="configToString(); codeEditorDialog = true">
</v-btn>
</div>
</div>
</v-slide-y-transition>
</div>
</div>
@@ -150,6 +152,12 @@ export default {
VueMonacoEditor,
WaitingForRestart
},
props: {
initialConfigId: {
type: String,
default: null
}
},
setup() {
const { t } = useI18n();
const { tm } = useModuleI18n('features/config');
@@ -187,8 +195,16 @@ export default {
},
},
watch: {
config_data_str: function (val) {
config_data_str(val) {
this.config_data_has_changed = true;
},
initialConfigId(newVal) {
if (!newVal) {
return;
}
if (this.selectedConfigID !== newVal) {
this.getConfigInfoList(newVal);
}
}
},
data() {
@@ -207,6 +223,7 @@ export default {
save_message_snack: false,
save_message: "",
save_message_success: "",
configContentKey: 0,
// 配置类型切换
configType: 'normal', // 'normal' 或 'system'
@@ -224,7 +241,8 @@ export default {
}
},
mounted() {
this.getConfigInfoList("default");
const targetConfigId = this.initialConfigId || 'default';
this.getConfigInfoList(targetConfigId);
// 初始化配置类型状态
this.configType = this.isSystemConfig ? 'system' : 'normal';
},
@@ -235,13 +253,21 @@ export default {
this.configInfoList = res.data.data.info_list;
if (abconf_id) {
let matched = false;
for (let i = 0; i < this.configInfoList.length; i++) {
if (this.configInfoList[i].id === abconf_id) {
this.selectedConfigID = this.configInfoList[i].id
this.selectedConfigID = this.configInfoList[i].id;
this.getConfig(abconf_id);
matched = true;
break;
}
}
if (!matched && this.configInfoList.length) {
// 当找不到目标配置时,默认展示列表中的第一个配置
this.selectedConfigID = this.configInfoList[0].id;
this.getConfig(this.selectedConfigID);
}
}
}).catch((err) => {
this.save_message = this.messages.loadError;
@@ -265,6 +291,7 @@ export default {
this.config_data = res.data.data.config;
this.fetched = true
this.metadata = res.data.data.metadata;
this.configContentKey += 1;
}).catch((err) => {
this.save_message = this.messages.loadError;
this.save_message_snack = true;