gongxiangp2/lib/material-cleanup.ts

162 lines
4.7 KiB
TypeScript
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.

/**
* 统一的素材文件清理逻辑
* 根据不同的素材类型,收集所有需要删除的文件
*/
import { prisma } from './prisma';
import path from 'path';
export interface MaterialFileInfo {
fileUrls: string[];
directories: string[];
relatedRecords?: {
assets?: number; // MaterialAsset 记录数
skus?: number; // MaterialSku 记录数
};
}
/**
* 收集素材的所有文件路径(根据素材类型)
* @param materialId 素材ID
* @param material 素材对象(可选,如果不提供则从数据库查询)
* @returns 文件信息
*/
export async function collectMaterialFiles(
materialId: string,
material?: any
): Promise<MaterialFileInfo> {
const fileUrls: string[] = [];
const directories: string[] = [];
const relatedRecords: { assets?: number; skus?: number } = {};
// 如果未提供素材对象,从数据库查询
if (!material) {
material = await prisma.material.findUnique({
where: { id: materialId },
});
}
if (!material) {
return { fileUrls: [], directories: [], relatedRecords };
}
const materialType = (material as any).materialType || '';
// 1. 通用字段(所有素材类型都可能有)
if ((material as any).zipFilePath) {
fileUrls.push((material as any).zipFilePath);
}
if ((material as any).videoSourceUrl && (material as any).videoSourceUrl !== (material as any).zipFilePath) {
fileUrls.push((material as any).videoSourceUrl);
}
if ((material as any).previewUrl) {
fileUrls.push((material as any).previewUrl);
}
if ((material as any).videoPreview540Url) {
fileUrls.push((material as any).videoPreview540Url);
}
if ((material as any).videoPreviewClipUrl) {
fileUrls.push((material as any).videoPreviewClipUrl);
}
if ((material as any).videoCoverUrl) {
fileUrls.push((material as any).videoCoverUrl);
}
if (Array.isArray((material as any).displayImages) && (material as any).displayImages.length > 0) {
fileUrls.push(...(material as any).displayImages.filter((img: string) => img && img.trim()));
}
// 2. 任务类型素材特殊处理(任务-详情、任务-3D原图、任务-AI原图、任务-实拍原图)
const taskMaterialTypes = ['任务-详情', '任务-3D原图', '任务-AI原图', '任务-实拍原图'];
if (taskMaterialTypes.includes(materialType)) {
// 查询资产文件
const assets = await prisma.materialAsset.findMany({
where: { materialId },
select: { fileUrl: true },
});
relatedRecords.assets = assets.length;
for (const asset of assets) {
if (asset.fileUrl) {
fileUrls.push(asset.fileUrl);
}
}
// 任务-详情:PSD 文件目录
if (materialType === '任务-详情') {
const psdDir = path.join(process.cwd(), 'uploads', 'product-package', materialId);
directories.push(psdDir);
}
}
// 3. 标准模型特殊处理(SKU 文件)
if (materialType === '标准模型') {
const skus = await prisma.materialSku.findMany({
where: {
materialId,
deletedAt: null, // 只查询未删除的 SKU
} as any,
select: {
filePath: true,
previewUrl: true,
},
});
relatedRecords.skus = skus.length;
for (const sku of skus) {
if (sku.filePath) {
fileUrls.push(sku.filePath);
}
if (sku.previewUrl) {
fileUrls.push(sku.previewUrl);
}
}
}
// 去重
const uniqueFileUrls = Array.from(new Set(fileUrls.filter(f => f && f.trim())));
const uniqueDirectories = Array.from(new Set(directories.filter(d => d && d.trim())));
return {
fileUrls: uniqueFileUrls,
directories: uniqueDirectories,
relatedRecords,
};
}
/**
* 删除素材的关联记录(MaterialAsset, MaterialSku 等)
* @param materialId 素材ID
* @param materialType 素材类型
*/
export async function deleteMaterialRelatedRecords(
materialId: string,
materialType: string
): Promise<{ deletedAssets?: number; deletedSkus?: number }> {
const result: { deletedAssets?: number; deletedSkus?: number } = {};
// 任务类型素材:删除资产记录
const taskMaterialTypes = ['任务-详情', '任务-3D原图', '任务-AI原图', '任务-实拍原图'];
if (taskMaterialTypes.includes(materialType)) {
const deleteResult = await prisma.materialAsset.deleteMany({
where: { materialId },
});
result.deletedAssets = deleteResult.count;
}
// 标准模型:删除 SKU 记录(外键约束会自动处理,但显式删除更清晰)
if (materialType === '标准模型') {
const deleteResult = await prisma.materialSku.deleteMany({
where: { materialId },
});
result.deletedSkus = deleteResult.count;
}
return result;
}