150 lines
4.8 KiB
TypeScript
150 lines
4.8 KiB
TypeScript
/**
|
|
* 在服务器上清理孤立的任务-详情素材残留文件
|
|
*/
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
|
import { deleteFromS3, isS3Url } from '../lib/s3';
|
|
import { promises as fs } from 'fs';
|
|
import path from 'path';
|
|
|
|
const MATERIAL_ID = 'cc7e5cdd-d408-4bcd-a73f-4ddcaa8054b9';
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
console.log('开始检查服务器上的残留文件...\n');
|
|
|
|
try {
|
|
// 1. 检查数据库中的素材记录
|
|
console.log('1. 检查数据库中的素材记录...');
|
|
const material = await prisma.material.findUnique({
|
|
where: { id: MATERIAL_ID },
|
|
select: { id: true, materialType: true },
|
|
});
|
|
|
|
if (material) {
|
|
console.log(` ❌ 发现素材记录: id=${material.id}, type=${material.materialType}`);
|
|
} else {
|
|
console.log(` ✅ 素材记录已删除`);
|
|
}
|
|
|
|
// 2. 检查数据库中的资产记录
|
|
console.log('\n2. 检查数据库中的资产记录...');
|
|
const assets = await prisma.materialAsset.findMany({
|
|
where: { materialId: MATERIAL_ID },
|
|
select: {
|
|
id: true,
|
|
assetType: true,
|
|
fileUrl: true,
|
|
fileName: true,
|
|
},
|
|
});
|
|
|
|
if (assets.length > 0) {
|
|
console.log(` ❌ 发现 ${assets.length} 条资产记录:`);
|
|
assets.forEach((asset, index) => {
|
|
console.log(` [${index + 1}] type=${asset.assetType}, url=${asset.fileUrl}`);
|
|
});
|
|
} else {
|
|
console.log(` ✅ 资产记录已删除`);
|
|
}
|
|
|
|
// 3. 检查本地文件系统
|
|
console.log('\n3. 检查本地文件系统...');
|
|
const uploadsDir = path.join(process.cwd(), 'uploads', 'product-package', MATERIAL_ID);
|
|
let localFiles: string[] = [];
|
|
try {
|
|
const files = await fs.readdir(uploadsDir, { recursive: true });
|
|
localFiles = files.map(f => path.join(uploadsDir, f));
|
|
console.log(` ❌ 发现本地目录: ${uploadsDir}`);
|
|
console.log(` 包含 ${files.length} 个文件/目录`);
|
|
files.forEach((file, index) => {
|
|
console.log(` [${index + 1}] ${file}`);
|
|
});
|
|
} catch (err: any) {
|
|
if (err.code === 'ENOENT') {
|
|
console.log(` ✅ 本地目录已删除`);
|
|
} else {
|
|
console.log(` ⚠️ 检查本地目录时出错: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// 4. 总结
|
|
console.log('\n' + '='.repeat(60));
|
|
console.log('检查总结:');
|
|
console.log(` - 素材记录: ${material ? '存在' : '已删除'}`);
|
|
console.log(` - 资产记录: ${assets.length} 条`);
|
|
console.log(` - 本地文件: ${localFiles.length} 个`);
|
|
console.log('='.repeat(60));
|
|
|
|
// 5. 自动清理
|
|
if (material || assets.length > 0 || localFiles.length > 0) {
|
|
console.log('\n开始自动清理...\n');
|
|
|
|
// 删除资产记录
|
|
if (assets.length > 0) {
|
|
console.log('删除资产记录...');
|
|
const result = await prisma.materialAsset.deleteMany({
|
|
where: { materialId: MATERIAL_ID },
|
|
});
|
|
console.log(` ✅ 已删除 ${result.count} 条资产记录`);
|
|
}
|
|
|
|
// 删除素材记录
|
|
if (material) {
|
|
console.log('删除素材记录...');
|
|
try {
|
|
await prisma.material.delete({
|
|
where: { id: MATERIAL_ID },
|
|
});
|
|
console.log(` ✅ 已删除素材记录`);
|
|
} catch (err: any) {
|
|
console.log(` ⚠️ 删除素材记录失败: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// 删除本地文件
|
|
if (localFiles.length > 0) {
|
|
console.log('删除本地文件...');
|
|
try {
|
|
await fs.rm(uploadsDir, { recursive: true, force: true });
|
|
console.log(` ✅ 已删除本地目录: ${uploadsDir}`);
|
|
} catch (err: any) {
|
|
console.log(` ⚠️ 删除本地文件失败: ${err.message}`);
|
|
}
|
|
}
|
|
|
|
// 删除 S3 文件
|
|
const s3Files = assets.filter(a => isS3Url(a.fileUrl));
|
|
if (s3Files.length > 0) {
|
|
console.log(`删除 S3 文件 (${s3Files.length} 个)...`);
|
|
let deletedCount = 0;
|
|
let failedCount = 0;
|
|
|
|
for (const asset of s3Files) {
|
|
try {
|
|
await deleteFromS3(asset.fileUrl);
|
|
deletedCount++;
|
|
console.log(` ✅ 已删除: ${asset.fileUrl}`);
|
|
} catch (err: any) {
|
|
failedCount++;
|
|
console.log(` ❌ 删除失败: ${asset.fileUrl} - ${err.message}`);
|
|
}
|
|
}
|
|
|
|
console.log(` S3 文件清理完成: ${deletedCount} 成功, ${failedCount} 失败`);
|
|
}
|
|
|
|
console.log('\n✅ 清理完成!');
|
|
} else {
|
|
console.log('\n✅ 没有发现残留文件,无需清理。');
|
|
}
|
|
} catch (error: any) {
|
|
console.error('检查失败:', error.message);
|
|
throw error;
|
|
} finally {
|
|
await prisma.$disconnect();
|
|
}
|
|
}
|
|
|
|
main().catch(console.error);
|