162 lines
4.7 KiB
TypeScript
162 lines
4.7 KiB
TypeScript
/**
|
||
* 统一的素材文件清理逻辑
|
||
* 根据不同的素材类型,收集所有需要删除的文件
|
||
*/
|
||
|
||
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;
|
||
}
|