docs/archives/132-architecture-migration-and-session-persistence-plans/PLAN-session-persistence-fix.md
用户在无痕模式打开应用,切换下拉框(优化模型、测试模型、模板)的值后,刷新页面,选择的值会丢失,恢复到默认值。
切换下拉框后,刷新页面,选择应该保留。
切换下拉框时,数据没有立即保存到持久化存储,只更新了内存。
用户切换下拉框
↓
下拉框组件触发更新事件
↓
session store 的 updateOptimizeModel(modelKey) 被调用
↓
更新内存中的 ref: selectedOptimizeModelKey.value = modelKey ✅
↓
【问题点】没有调用 saveSession() ❌
↓
用户刷新页面
↓
pagehide 事件触发,但异步保存未完成
↓
页面刷新,内存清空
↓
restoreSession() 从 IndexedDB 恢复数据
↓
【问题点】恢复的是旧数据或默认值 ❌
↓
下拉框显示错误的值
用户切换下拉框
↓
updateOptimizeModel(modelKey) 被调用
↓
更新内存: selectedOptimizeModelKey.value = modelKey ✅
↓
【修复点】立即调用 saveSession() ✅
↓
saveSession() 异步保存到 IndexedDB
↓
用户刷新页面
↓
restoreSession() 从 IndexedDB 恢复数据
↓
下拉框显示正确的值 ✅
实施内容:
createDebounceSave 函数updateOptimizeModel 等方法中调用 debouncedSave()问题:
实施内容:
PromptOptimizerApp.vue 的 handlePagehide 中添加同步 localStorage 写入问题:
if (existingData) 检查导致首次切换时无法保存实施内容:
updateOptimizeModel 等方法中直接调用 saveSession()问题:
saveSession() 是异步的,但没有 awaitsaveSession() 调用失败实施内容:
updateOptimizeModel 中先同步写入 localStoragesaveSession() 保存到 IndexedDB问题:
if (existingData) 检查导致首次切换时无法保存packages/ui/src/stores/session/
├── useBasicSystemSession.ts
├── useBasicUserSession.ts
├── useProVariableSession.ts
├── useProMultiMessageSession.ts
├── useImageText2ImageSession.ts
└── useImageImage2ImageSession.ts
packages/ui/src/stores/session/useSessionManager.ts
packages/ui/src/components/app-layout/PromptOptimizerApp.vue
packages/ui/src/composables/system/useAppInitializer.ts
tests/e2e/session-persistence/basic-user-persistence.spec.ts
useBasicUserSession.ts 的问题const updateOptimizeModel = (modelKey: string) => {
if (selectedOptimizeModelKey.value === modelKey) return
selectedOptimizeModelKey.value = modelKey
lastActiveAt.value = Date.now()
// 【问题】同步保存到 localStorage
try {
const key = 'session/v1/basic-user'
const existing = localStorage.getItem(key)
if (existing) { // ⚠️ 关键问题:首次切换时 existing 为 null
const data = JSON.parse(existing)
data.selectedOptimizeModelKey = modelKey
data.lastActiveAt = lastActiveAt.value
localStorage.setItem(key, JSON.stringify(data))
}
} catch (err) {
console.warn('[BasicUserSession] 同步保存失败:', err)
}
// 【问题】异步保存,但没有 await
saveSession() // ⚠️ 异步调用,但没有等待完成
}
问题分析:
if (existing) 检查导致首次切换时无法保存saveSession() 是异步的,但没有 await,调用者不知道何时完成const saveSession = async () => {
console.log('[BasicUserSession] saveSession 被调用')
const $services = getPiniaServices()
if (!$services?.preferenceService) {
console.warn('[BasicUserSession] PreferenceService 不可用,无法保存会话')
return
}
try {
const sessionState = {
prompt: prompt.value,
optimizedPrompt: optimizedPrompt.value,
reasoning: reasoning.value,
chainId: chainId.value,
versionId: versionId.value,
testContent: testContent.value,
testResults: testResults.value,
selectedOptimizeModelKey: selectedOptimizeModelKey.value,
selectedTestModelKey: selectedTestModelKey.value,
selectedTemplateId: selectedTemplateId.value,
selectedIterateTemplateId: selectedIterateTemplateId.value,
isCompareMode: isCompareMode.value,
lastActiveAt: lastActiveAt.value,
}
console.log('[BasicUserSession] 保存会话, selectedOptimizeModelKey:', sessionState.selectedOptimizeModelKey)
await $services.preferenceService.set(
'session/v1/basic-user',
JSON.stringify(sessionState)
)
console.log('[BasicUserSession] 保存会话成功')
} catch (error) {
console.error('[BasicUserSession] 保存会话失败:', error)
}
}
问题分析:
tests/e2e/session-persistence/basic-user-persistence.spec.ts
初始优化模型: DeepSeekDeepSeek
切换到模型: SiliconFlowSiliconFlow
切换后: SiliconFlowSiliconFlow ✅ UI 更新成功
刷新后: DeepSeekDeepSeek ❌ 恢复到初始值
期望: "SiliconFlowSiliconFlow"
实际: "DeepSeekDeepSeek"
结论:数据没有被保存到 IndexedDB,或者没有被正确恢复。
原理:
saveSession() 是异步的,而用户刷新很快,异步操作可能来不及完成实施步骤:
saveSession() 调用updateOptimizeModel 等方法中直接同步写入 localStoragerestoreSession 从 localStorage 读取优点:
缺点:
原理:
实施步骤:
saveSession() 是否真的被调用(添加日志验证)preferenceService.set() 是否成功restoreSession() 是否正确从 IndexedDB 读取数据restoreSession() 是否在页面加载时被调用调试方法:
updateOptimizeModel 开头添加 console.logsaveSession 开头添加 console.logpreferenceService.set() 前后添加 console.logrestoreSession 开头和结尾添加 console.log原理:
watch 监听 ref 的变化saveSession()实施步骤:
// 在 store 中添加
watch(selectedOptimizeModelKey, (newValue) => {
saveSession()
})
优点:
saveSession()缺点:
restoreAllSessions()useAppInitializer.ts:初始化 PreferenceServiceuseSessionManager.ts:管理所有 session 的保存和恢复PromptOptimizerApp.vue:应用初始化时调用 restoreAllSessions()preferenceService.set() 会添加 pref: 前缀pref:session/v1/basic-user,不是 session/v1/basic-user修复后的代码应该满足: