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