diff --git a/dashboard/src/i18n/locales/en-US/features/config.json b/dashboard/src/i18n/locales/en-US/features/config.json index ef595bd71..4a766ad3d 100644 --- a/dashboard/src/i18n/locales/en-US/features/config.json +++ b/dashboard/src/i18n/locales/en-US/features/config.json @@ -28,6 +28,7 @@ "messages": { "configApplied": "Configuration successfully applied. To save, you need to click the save button in the bottom right corner.", "configApplyError": "Configuration not applied, JSON format error.", + "unsavedChangesNotice": "You have unsaved configuration changes. Click the save button in the bottom-right corner to apply them.", "saveSuccess": "Configuration saved successfully", "saveError": "Failed to save configuration", "loadError": "Failed to load configuration", diff --git a/dashboard/src/i18n/locales/zh-CN/features/config.json b/dashboard/src/i18n/locales/zh-CN/features/config.json index bf0c709b0..6ab2292f5 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/config.json +++ b/dashboard/src/i18n/locales/zh-CN/features/config.json @@ -28,6 +28,7 @@ "messages": { "configApplied": "配置成功应用。如要保存,需再点击右下角保存按钮。", "configApplyError": "配置未应用,Json 格式错误。", + "unsavedChangesNotice": "当前配置有未保存修改。请点击右下角保存按钮以生效。", "saveSuccess": "配置保存成功", "saveError": "配置保存失败", "loadError": "配置加载失败", diff --git a/dashboard/src/views/ConfigPage.vue b/dashboard/src/views/ConfigPage.vue index 617c6716c..88ba3d5f1 100644 --- a/dashboard/src/views/ConfigPage.vue +++ b/dashboard/src/views/ConfigPage.vue @@ -15,6 +15,17 @@ + + + + {{ tm('messages.unsavedChangesNotice') }} + + + @@ -235,6 +246,12 @@ export default { }); return items; }, + hasUnsavedChanges() { + if (!this.fetched) { + return false; + } + return this.getConfigSnapshot(this.config_data) !== this.lastSavedConfigSnapshot; + } }, watch: { config_data_str(val) { @@ -269,6 +286,7 @@ export default { save_message: "", save_message_success: "", configContentKey: 0, + lastSavedConfigSnapshot: '', // 配置类型切换 configType: 'normal', // 'normal' 或 'system' @@ -383,6 +401,7 @@ export default { params: params }).then((res) => { this.config_data = res.data.data.config; + this.lastSavedConfigSnapshot = this.getConfigSnapshot(this.config_data); this.fetched = true this.metadata = res.data.data.metadata; this.configContentKey += 1; @@ -407,6 +426,7 @@ export default { axios.post('/api/config/astrbot/update', postData).then((res) => { if (res.data.status === "ok") { + this.lastSavedConfigSnapshot = this.getConfigSnapshot(this.config_data); this.save_message = res.data.message || this.messages.saveSuccess; this.save_message_snack = true; this.save_message_success = "success"; @@ -601,6 +621,9 @@ export default { closeTestChat() { this.testChatDrawer = false; this.testConfigId = null; + }, + getConfigSnapshot(config) { + return JSON.stringify(config ?? {}); } }, } @@ -612,6 +635,26 @@ export default { text-transform: none !important; } +.unsaved-changes-banner { + border-radius: 8px; +} + +.v-theme--light .unsaved-changes-banner { + background-color: #f1f4f9 !important; +} + +.v-theme--dark .unsaved-changes-banner { + background-color: #2d2d2d !important; +} + +.unsaved-changes-banner-wrap { + position: sticky; + top: calc(var(--v-layout-top, 64px)); + z-index: 20; + width: 100%; + margin-bottom: 6px; +} + /* 按钮切换样式优化 */ .v-btn-toggle .v-btn { transition: all 0.3s ease !important;