feat(personalization): 去掉保存按钮,所有选项改为实时自动保存
- personalization store 新增 scheduleAutoSave/autoSave 防抖方法(500ms) - updateField 及所有 mutation 方法修改后自动触发保存 - PersonalizationDrawer 删除保存按钮和 settings-save-bar - handleStackedHideBordersChange 移除显式 save 调用
This commit is contained in:
parent
0ed262c87b
commit
76e4c5144e
@ -27,7 +27,6 @@
|
||||
<div class="personalization-body settings-redesign-body" v-if="!loading">
|
||||
<form
|
||||
class="personal-form settings-redesign-form"
|
||||
@submit.prevent="personalization.save()"
|
||||
>
|
||||
<div class="settings-redesign-layout">
|
||||
<nav class="settings-redesign-tabs" aria-label="个人空间分组切换">
|
||||
@ -1651,9 +1650,6 @@
|
||||
><span class="status error" v-if="error">{{ error }}</span></transition
|
||||
>
|
||||
</div>
|
||||
<button type="submit" class="settings-primary-button" :disabled="saving">
|
||||
{{ saving ? '保存中...' : '保存设置' }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@ -2501,7 +2497,6 @@ const handleStackedHideBordersChange = (event: Event) => {
|
||||
key: 'stacked_hide_borders',
|
||||
value: target.checked
|
||||
});
|
||||
personalization.save();
|
||||
};
|
||||
|
||||
const compactMessageDisplayOptions = [
|
||||
|
||||
@ -207,6 +207,9 @@ const loadExperimentState = (): ExperimentState => {
|
||||
}
|
||||
};
|
||||
|
||||
// 防抖自动保存计时器(非响应式,避免触发不必要的重渲染)
|
||||
let autoSaveTimer: ReturnType<typeof setTimeout> | 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user