refactor: 清理IndexedDB相关代码,统一使用后端ZIP存储

- 移除前端废弃的loadZipFile/saveZipFile函数
- ProjectDetail使用scanStoredZipFile替代loadZipFile
- RecycleBin移除手动删除ZIP文件逻辑
- 后端permanently_delete_project自动清理ZIP文件
This commit is contained in:
lintsinghua 2025-11-28 18:01:43 +08:00
parent f640bfbaba
commit c54212a8c9
4 changed files with 17 additions and 44 deletions

View File

@ -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": "项目已永久删除"}

View File

@ -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);

View File

@ -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);

View File

@ -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<void> {
const result = await uploadZipFile(projectId, file);
if (!result.success) {
throw new Error(result.message || '保存ZIP文件失败');
}
}
/**
* @deprecated 使 getZipFileInfo
*/
export async function loadZipFile(projectId: string): Promise<File | null> {
// 后端不再返回文件内容,只返回元数据
// 如果需要文件,应该在创建任务时直接使用后端存储的文件
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;
}