MilliSim/.trae/documents/upload-cleanup-completion.md

93 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 上传垃圾资源清理 - 收尾计划
## 概述
本计划承接前一会话的工作。前一会话已实现上传垃圾清理的完整三层防御机制(前端即时清理 + 后端保存时清理 + 后端 GC 兜底),并完成了 8 个页面的接入。经探查验证,发现**一个遗漏场景**后台顶栏的个人资料弹窗AdminLayout.vue使用了 IconUpload 上传头像,但未接入上传会话清理机制。本计划补齐该场景并完成整体验证。
## 当前状态分析
### 已完成(无需改动)
- **前端基础设施**`api/index.ts``deleteUpload` 方法、`useUploadSession.ts` composable
- **上传组件**`IconUpload.vue``VideoUpload.vue` 已支持 `uploadSession` prop + `currentKey` 跟踪
- **8 个页面接入**Categories / Platforms / Banners / Partners / Employees / Customers / Settings / ProjectEdit
- **后端基础设施**SystemController Upload/DELETE 端点、UploadTrackingService、UploadCleanupJob、各业务 Service 的 ConsumeAsync 调用
### 遗漏场景(本次修复)
- **AdminLayout.vue 个人资料弹窗**:使用 IconUpload 上传头像,但未接入上传会话。当用户上传新头像后点击"取消"或关闭弹窗,文件成为垃圾资源(仅靠 24h GC 兜底,不符合即时清理目标)。
### 范围外说明(不在本次修复)
- **ProjectPackage 软删除孤儿**`DeletePackageAsync` 仅设 `IsDeleted = true`,不删除存储文件。这是实体级清理问题,不属于"上传垃圾清理"范畴(上传时立即消费,无 pending 状态),单独跟踪。
- **WebGL 解压失败孤儿**ZIP 上传成功但解压失败时,文件已落库存储。属于异常流程清理,单独跟踪。
## 计划改动
### 改动 1AdminLayout.vue 接入上传会话清理
**文件**`d:\TraeProject\MilliSim4\frontend\src\layouts\AdminLayout.vue`
**改动内容**(参照 Employees.vue 模式):
1. **导入 composable**script 顶部):
```typescript
import { useUploadSession } from '@/composables/useUploadSession'
```
2. **创建实例**setup 区域):
```typescript
const uploadSession = useUploadSession()
```
3. **个人资料 el-dialog 增加 @closed 事件**(约 L142
```vue
<el-dialog v-model="profileVisible" ... @closed="uploadSession.cleanupPending()">
```
4. **IconUpload 传入 uploadSession prop**(约 L157
```vue
<IconUpload
v-model="profileForm.avatar"
folder="avatars"
alt="头像"
:upload-session="uploadSession"
/>
```
5. **saveProfile 成功后重置会话**(约 L259-276 内的成功分支):
```typescript
// 保存成功后清空 pending 列表:头像已被后端 ConsumeAsync 消费
uploadSession.reset()
```
**注意**
- AdminLayout 是常驻布局组件,不会频繁卸载,`onBeforeUnmount` 自动清理在此场景下主要起兜底作用;真正的清理依赖 `@closed` 事件。
- 不需要改"取消"按钮逻辑,因为 `@closed` 事件在点击取消(关闭弹窗)时也会触发。
### 改动 2验证步骤
**前端验证**
1. 后端 dev server 已运行(前一会话已启动,确认端口 5041 监听)
2. 前端 Vite dev server 已运行(确认无 HMR 编译错误)
3. 如有编译错误则修复
**功能场景测试**(建议用户在浏览器手动验证至少 2 个场景):
- 场景 A新增分类 → 上传图标 → 点击取消 → 确认图标被清理(检查后端日志 DELETE 请求)
- 场景 B编辑员工 → 上传新头像 → 点击取消 → 确认头像被清理
- 场景 C后台顶栏 → 点击头像 → 上传新头像 → 点击取消 → 确认头像被清理(本次新增场景)
## 假设与决策
1. **不动后端代码**:前一会话后端已完整实现,本次仅前端补漏。
2. **不动 ProjectPackage 软删除逻辑**:属于实体生命周期管理,不在上传垃圾清理范畴。
3. **保留 onBeforeUnmount 兜底**AdminLayout 虽不常卸载,但 composable 的 onBeforeUnmount 仍是安全网,不删除。
4. **使用 `@closed` 而非 `@close`**`@closed` 在弹窗动画结束后触发,避免与销毁逻辑冲突(与已接入页面保持一致)。
## 验证步骤
1. 修改 AdminLayout.vue 后,查看 Vite HMR 日志确认无编译错误
2. 检查后端进程仍在运行(端口 5041
3. 向用户报告:本次补漏 + 整体验证结果
4. 建议用户手动测试场景 C个人资料头像取消清理