diff --git a/static/src/components/personalization/PersonalizationDrawer.vue b/static/src/components/personalization/PersonalizationDrawer.vue index 98416a5..15e7242 100644 --- a/static/src/components/personalization/PersonalizationDrawer.vue +++ b/static/src/components/personalization/PersonalizationDrawer.vue @@ -27,7 +27,6 @@
-
@@ -2501,7 +2497,6 @@ const handleStackedHideBordersChange = (event: Event) => { key: 'stacked_hide_borders', value: target.checked }); - personalization.save(); }; const compactMessageDisplayOptions = [ diff --git a/static/src/stores/personalization.ts b/static/src/stores/personalization.ts index 8eaf857..41196cf 100644 --- a/static/src/stores/personalization.ts +++ b/static/src/stores/personalization.ts @@ -207,6 +207,9 @@ const loadExperimentState = (): ExperimentState => { } }; +// 防抖自动保存计时器(非响应式,避免触发不必要的重渲染) +let autoSaveTimer: ReturnType | null = null; + export const usePersonalizationStore = defineStore('personalization', { state: (): PersonalizationState => ({ visible: false, @@ -591,6 +594,40 @@ export const usePersonalizationStore = defineStore('personalization', { [payload.key]: payload.value }; this.clearFeedback(); + this.scheduleAutoSave(); + }, + /** 防抖自动保存:500ms 内多次调用只执行最后一次 */ + scheduleAutoSave() { + if (autoSaveTimer) { + clearTimeout(autoSaveTimer); + } + autoSaveTimer = setTimeout(() => { + autoSaveTimer = null; + this.autoSave(); + }, 500); + }, + /** 静默自动保存,成功不显示提示,失败显示错误 */ + async autoSave() { + if (this.saving) { + return; + } + this.saving = true; + try { + const resp = await fetch('/api/personalization', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(this.form) + }); + const result = await resp.json(); + if (!resp.ok || !result.success) { + throw new Error(result.error || '自动保存失败'); + } + // 静默成功,不刷新表单(避免打断用户编辑) + } catch (error: any) { + this.error = error?.message || '自动保存失败'; + } finally { + this.saving = false; + } }, setThinkingInterval(value: number | null) { let target: number | null = value; @@ -612,6 +649,7 @@ export const usePersonalizationStore = defineStore('personalization', { thinking_interval: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, setRecentConversationsPromptLimit(value: number | null) { const target = @@ -623,6 +661,7 @@ export const usePersonalizationStore = defineStore('personalization', { recent_conversations_prompt_limit: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, toggleDefaultToolCategory(categoryId: string) { if (!categoryId) { @@ -639,6 +678,7 @@ export const usePersonalizationStore = defineStore('personalization', { disabled_tool_categories: Array.from(current) }; this.clearFeedback(); + this.scheduleAutoSave(); }, toggleSkill(skillId: string) { if (!skillId) { @@ -655,6 +695,7 @@ export const usePersonalizationStore = defineStore('personalization', { enabled_skills: Array.from(current) }; this.clearFeedback(); + this.scheduleAutoSave(); }, setDefaultRunMode(mode: RunMode | null) { let target: RunMode | null = null; @@ -666,6 +707,7 @@ export const usePersonalizationStore = defineStore('personalization', { default_run_mode: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, setDefaultPermissionMode(mode: PermissionMode) { const allowed: PermissionMode[] = ['readonly', 'approval', 'auto_approval', 'unrestricted']; @@ -675,6 +717,7 @@ export const usePersonalizationStore = defineStore('personalization', { default_permission_mode: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, setVersioningRestoreMode(_mode: 'overwrite') { const target: 'overwrite' = 'overwrite'; @@ -683,6 +726,7 @@ export const usePersonalizationStore = defineStore('personalization', { versioning_restore_mode: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, setDefaultModel(model: string | null) { const modelStore = useModelStore(); @@ -693,6 +737,7 @@ export const usePersonalizationStore = defineStore('personalization', { default_model: target }; this.clearFeedback(); + this.scheduleAutoSave(); }, setImageCompression(mode: string) { const allowed = ['original', '1080p', '720p', '540p']; @@ -702,6 +747,7 @@ export const usePersonalizationStore = defineStore('personalization', { image_compression: mode }; this.clearFeedback(); + this.scheduleAutoSave(); }, applyTonePreset(preset: string) { if (!preset) { @@ -712,6 +758,7 @@ export const usePersonalizationStore = defineStore('personalization', { tone: preset }; this.clearFeedback(); + this.scheduleAutoSave(); }, updateNewConsideration(value: string) { this.newConsideration = value; @@ -730,6 +777,7 @@ export const usePersonalizationStore = defineStore('personalization', { }; this.newConsideration = ''; this.clearFeedback(); + this.scheduleAutoSave(); }, removeConsideration(index: number) { const items = [...this.form.considerations]; @@ -739,6 +787,7 @@ export const usePersonalizationStore = defineStore('personalization', { considerations: items }; this.clearFeedback(); + this.scheduleAutoSave(); }, considerationDragStart(index: number, event: DragEvent) { this.draggedConsiderationIndex = index; @@ -769,6 +818,7 @@ export const usePersonalizationStore = defineStore('personalization', { } this.considerationDragEnd(); this.considerationDragOver(index, event); + this.scheduleAutoSave(); }, considerationDragEnd() { this.draggedConsiderationIndex = null; @@ -818,6 +868,7 @@ export const usePersonalizationStore = defineStore('personalization', { blockDisplayMode: mode }; this.persistExperiments(); + this.scheduleAutoSave(); }, setCompactMessageDisplay(mode: CompactMessageDisplay) { const target: CompactMessageDisplay = mode === 'brief' ? 'brief' : 'full'; @@ -856,6 +907,7 @@ export const usePersonalizationStore = defineStore('personalization', { communication_style: style }; this.clearFeedback(); + this.scheduleAutoSave(); }, setConversationContinuity(value: ConversationContinuity) { this.form = { @@ -863,6 +915,7 @@ export const usePersonalizationStore = defineStore('personalization', { conversation_continuity: value }; this.clearFeedback(); + this.scheduleAutoSave(); } } });