From c54212a8c9309e25bf8e15a4732dce20bbf67f65 Mon Sep 17 00:00:00 2001 From: lintsinghua Date: Fri, 28 Nov 2025 18:01:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=B8=85=E7=90=86IndexedDB?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=EF=BC=8C=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=90=8E=E7=AB=AFZIP=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除前端废弃的loadZipFile/saveZipFile函数 - ProjectDetail使用scanStoredZipFile替代loadZipFile - RecycleBin移除手动删除ZIP文件逻辑 - 后端permanently_delete_project自动清理ZIP文件 --- backend/app/api/v1/endpoints/projects.py | 8 ++++++++ frontend/src/pages/ProjectDetail.tsx | 18 ++++++++--------- frontend/src/pages/RecycleBin.tsx | 10 +--------- frontend/src/shared/utils/zipStorage.ts | 25 ------------------------ 4 files changed, 17 insertions(+), 44 deletions(-) diff --git a/backend/app/api/v1/endpoints/projects.py b/backend/app/api/v1/endpoints/projects.py index 3a59217..1c9363f 100644 --- a/backend/app/api/v1/endpoints/projects.py +++ b/backend/app/api/v1/endpoints/projects.py @@ -294,6 +294,14 @@ async def permanently_delete_project( if project.owner_id != current_user.id: raise HTTPException(status_code=403, detail="无权永久删除此项目") + # 如果是ZIP类型项目,删除关联的ZIP文件和元数据 + if project.source_type == "zip": + try: + await delete_project_zip(id) + print(f"[Project] 已删除项目 {id} 的ZIP文件") + except Exception as e: + print(f"[Warning] 删除ZIP文件失败: {e}") + await db.delete(project) await db.commit() return {"message": "项目已永久删除"} diff --git a/frontend/src/pages/ProjectDetail.tsx b/frontend/src/pages/ProjectDetail.tsx index cdb4786..23a158f 100644 --- a/frontend/src/pages/ProjectDetail.tsx +++ b/frontend/src/pages/ProjectDetail.tsx @@ -25,9 +25,9 @@ import { GitBranch } from "lucide-react"; import { api } from "@/shared/config/database"; -import { runRepositoryAudit, scanZipFile } from "@/features/projects/services"; +import { runRepositoryAudit, scanStoredZipFile } from "@/features/projects/services"; import type { Project, AuditTask, CreateProjectForm } from "@/shared/types"; -import { loadZipFile } from "@/shared/utils/zipStorage"; +import { hasZipFile } from "@/shared/utils/zipStorage"; import { isRepositoryProject, getSourceTypeLabel } from "@/shared/utils/projectUtils"; import { toast } from "sonner"; import CreateTaskDialog from "@/components/audit/CreateTaskDialog"; @@ -173,18 +173,17 @@ export default function ProjectDetail() { setScanning(false); } } else { - // 没有仓库地址,尝试从IndexedDB加载保存的ZIP文件 + // 没有仓库地址,尝试使用后端存储的ZIP文件 try { setScanning(true); - const file = await loadZipFile(id); + const hasFile = await hasZipFile(id); - if (file) { - console.log('找到保存的ZIP文件,开始启动审计...'); + if (hasFile) { + console.log('找到后端存储的ZIP文件,开始启动审计...'); try { - // 启动ZIP文件审计 - const taskId = await scanZipFile({ + // 使用后端存储的ZIP文件启动审计 + const taskId = await scanStoredZipFile({ projectId: id, - zipFile: file, excludePatterns: ['node_modules/**', '.git/**', 'dist/**', 'build/**'], createdBy: 'local-user' }); @@ -206,7 +205,6 @@ export default function ProjectDetail() { } else { setScanning(false); toast.warning('此项目未配置仓库地址,也未上传ZIP文件。请先在项目设置中配置仓库地址,或通过"新建任务"上传ZIP文件。'); - // 不自动打开对话框,让用户自己选择 } } catch (error) { console.error('启动审计失败:', error); diff --git a/frontend/src/pages/RecycleBin.tsx b/frontend/src/pages/RecycleBin.tsx index fba03a7..c60842b 100644 --- a/frontend/src/pages/RecycleBin.tsx +++ b/frontend/src/pages/RecycleBin.tsx @@ -18,7 +18,6 @@ import { import { api } from "@/shared/config/database"; import type { Project } from "@/shared/types"; import { toast } from "sonner"; -import { deleteZipFile } from "@/shared/utils/zipStorage"; import { isRepositoryProject, getSourceTypeBadge } from "@/shared/utils/projectUtils"; export default function RecycleBin() { @@ -75,16 +74,9 @@ export default function RecycleBin() { if (!selectedProject) return; try { - // 删除项目数据 + // 删除项目数据(后端会同时删除关联的ZIP文件) await api.permanentlyDeleteProject(selectedProject.id); - // 删除保存的ZIP文件(如果有) - try { - await deleteZipFile(selectedProject.id); - } catch (error) { - console.error('删除ZIP文件失败:', error); - } - toast.success(`项目 "${selectedProject.name}" 已永久删除`); setShowPermanentDeleteDialog(false); setSelectedProject(null); diff --git a/frontend/src/shared/utils/zipStorage.ts b/frontend/src/shared/utils/zipStorage.ts index 2c76969..16c36bd 100644 --- a/frontend/src/shared/utils/zipStorage.ts +++ b/frontend/src/shared/utils/zipStorage.ts @@ -91,29 +91,4 @@ export function formatFileSize(bytes: number): string { return `${bytes} B`; } -// ============ 兼容旧API(已废弃,保留以避免编译错误) ============ -/** - * @deprecated 使用 uploadZipFile 代替 - */ -export async function saveZipFile(projectId: string, file: File): Promise { - const result = await uploadZipFile(projectId, file); - if (!result.success) { - throw new Error(result.message || '保存ZIP文件失败'); - } -} - -/** - * @deprecated 使用 getZipFileInfo 代替 - */ -export async function loadZipFile(projectId: string): Promise { - // 后端不再返回文件内容,只返回元数据 - // 如果需要文件,应该在创建任务时直接使用后端存储的文件 - const info = await getZipFileInfo(projectId); - if (info.has_file && info.original_filename) { - // 返回一个虚拟的File对象,仅包含元数据 - const blob = new Blob([], { type: 'application/zip' }); - return new File([blob], info.original_filename, { type: 'application/zip' }); - } - return null; -}