# 上传垃圾资源清理 - 收尾计划 ## 概述 本计划承接前一会话的工作。前一会话已实现上传垃圾清理的完整三层防御机制(前端即时清理 + 后端保存时清理 + 后端 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 上传成功但解压失败时,文件已落库存储。属于异常流程清理,单独跟踪。 ## 计划改动 ### 改动 1:AdminLayout.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 ``` 4. **IconUpload 传入 uploadSession prop**(约 L157): ```vue ``` 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(个人资料头像取消清理)