5.0 KiB
5.0 KiB
TaskId 丢失问题修复说明
问题描述
在 Tauri 两个独立窗口之间通信时,容易出现 taskId 丢失的情况,导致编辑窗口中的 taskId 为空,影响后续操作。
根本原因
- 缺少数据持久化:窗口之间传递数据时,如果事件丢失或延迟,taskId 会丢失
- 缺少数据准备状态控制:组件在数据未到达时就开始渲染,导致 taskId 为空
- 缺少兜底机制:没有处理不同字段名(taskId/taskid/id)的情况
- 缺少超时机制:如果事件一直没收到,窗口会一直处于等待状态
修复方案
1. 引入 taskStorage 模块
使用 localStorage 持久化存储 taskId,确保数据不会因窗口通信失败而丢失:
import {
setTaskId,
bindBeforeUnloadClear,
clearTaskId,
unbindBeforeUnloadClear,
getTaskId
} from '../../../taskStorage'
2. 添加数据准备状态控制
添加 isDataReady 状态,在数据未准备好之前显示加载界面:
const isDataReady = ref(false)
<div v-if="!isDataReady" class="loading-overlay">
<el-empty description="正在加载数据..." />
</div>
3. 添加超时机制
如果 5 秒内没有收到数据,也显示界面(避免永久等待):
const timeout = setTimeout(() => {
console.warn(`5秒内未收到数据,显示空界面`)
isDataReady.value = true
}, 5000)
4. 规范化和兜底 taskId
支持多种字段名,并使用 localStorage 作为兜底:
// 规范化并兜底 taskId(支持 taskid/id),最后再持久化
const incomingId = data?.taskId ?? data?.taskid ?? data?.id
const resolvedId = (incomingId ?? getTaskId() ?? '').toString()
if (!form.taskId && resolvedId) {
form.taskId = resolvedId
}
if (form.taskId) setTaskId(form.taskId)
5. 清理机制
在窗口关闭或组件卸载时清理 taskId:
const handleCancel = async () => {
clearTaskId() // 主动关闭时清空 taskId
await emit('task-edit-closed')
await getCurrentWindow().close()
}
onUnmounted(() => {
clearTaskId()
unbindBeforeUnloadClear()
})
修复文件列表
- ✅
src/views/task/selftrans/ai/components/task-edit-window.vue - ✅
src/views/task/selftrans/random/components/task-edit-window.vue - ✅
src/views/task/selftrans/module/components/task-edit-window.vue - ✅
src/views/task/selftrans/collegeexam/components/task-edit-window.vue
已存在的正确实现参考
src/views/task/exam/components/task-edit-window.vue- 已经包含完整的 taskId 持久化机制
关键改进点
前置
// ❌ 旧代码
let unlistenFunc: (() => void) | null = null
// ✅ 新代码
const isDataReady = ref(false)
let unlistenFunc: any = null
事件监听
// ❌ 旧代码
unlistenFunc = await listen(eventName, (event: any) => {
const { data } = event.payload || {}
if (data) {
assignFields(data)
activeStep.value = 0
}
})
// ✅ 新代码
const timeout = setTimeout(() => {
isDataReady.value = true
}, 5000)
unlistenFunc = await listen(eventName, (event: any) => {
clearTimeout(timeout)
const { data } = event.payload || {}
if (data) {
isDataReady.value = false
assignFields(data)
// 规范化和兜底
const incomingId = data?.taskId ?? data?.taskid ?? data?.id
const resolvedId = (incomingId ?? getTaskId() ?? '').toString()
if (!form.taskId && resolvedId) {
form.taskId = resolvedId
}
if (form.taskId) setTaskId(form.taskId)
isDataReady.value = true
activeStep.value = 0
}
})
清理
// ❌ 旧代码
onUnmounted(() => {
if (unlistenFunc) {
unlistenFunc()
}
})
// ✅ 新代码
onUnmounted(() => {
if (unlistenFunc) {
unlistenFunc()
unlistenFunc = null
}
clearTaskId()
unbindBeforeUnloadClear()
})
测试建议
- 正常流程测试:从列表页打开编辑窗口,检查 taskId 是否正确传递
- 延迟测试:模拟网络延迟,检查超时机制是否正常工作
- 重复打开测试:多次打开和关闭编辑窗口,检查是否有 taskId 残留
- 跨步骤测试:在编辑窗口的不同步骤间切换,检查 taskId 是否始终存在
- 刷新测试:在编辑窗口中刷新页面,检查 taskId 是否能从 localStorage 恢复
注意事项
- TypeScript 编译错误是正常的:在文件保存后,TypeScript 会重新编译,导入的函数会被识别为已使用
- bindBeforeUnloadClear 暂未使用:这个函数在某些场景下可能需要,暂时保留导入
- 不同模块的路径:注意
taskStorage的导入路径根据文件位置可能不同(../../../taskStorage)
预期效果
修复后,taskId 将更加稳定:
- ✅ 窗口通信失败时有 localStorage 兜底
- ✅ 数据加载时显示友好的加载界面
- ✅ 支持多种字段名格式
- ✅ 超时后不会永久卡住
- ✅ 窗口关闭后正确清理数据