- 迁移57个老素材到新逻辑(本地zip + S3预览图) - 优化文件命名:SPU_作者_店铺_类型.zip - PSD文件单独存储,不打包进all.zip - 修复下载接口,优先使用本地zip文件 - 修复预览图重复问题 - 添加迁移脚本和验证脚本 - 更新文档和迁移计划 迁移统计: - 总素材数:77个 - 成功迁移:57个 - 新逻辑上传:18个 - 空记录:2个
117 lines
3.1 KiB
TypeScript
117 lines
3.1 KiB
TypeScript
/**
|
||
* 回滚已迁移的素材
|
||
*
|
||
* 用于回滚迁移失败或路径错误的素材
|
||
*/
|
||
|
||
import { PrismaClient } from '@prisma/client';
|
||
import { unlink } from 'fs/promises';
|
||
import path from 'path';
|
||
|
||
const prisma = new PrismaClient();
|
||
|
||
// 要回滚的素材型号
|
||
const PRODUCT_MODEL = 'XG0176';
|
||
|
||
async function main() {
|
||
console.log('='.repeat(60));
|
||
console.log('回滚已迁移的素材');
|
||
console.log('='.repeat(60));
|
||
console.log(`素材型号: ${PRODUCT_MODEL}`);
|
||
console.log('');
|
||
|
||
try {
|
||
// 1. 查询素材
|
||
const material = await prisma.material.findFirst({
|
||
where: {
|
||
productModel: PRODUCT_MODEL,
|
||
materialType: '任务-详情',
|
||
deletedAt: null,
|
||
},
|
||
include: {
|
||
assets: true,
|
||
},
|
||
});
|
||
|
||
if (!material) {
|
||
console.log('未找到素材');
|
||
return;
|
||
}
|
||
|
||
console.log(`找到素材: ${material.id}`);
|
||
console.log(`当前 zipFilePath: ${material.zipFilePath}`);
|
||
console.log(`当前 zipFileSize: ${material.zipFileSize}`);
|
||
console.log('');
|
||
|
||
// 2. 删除新增的资产记录(只删除新增的,保留老的 main/sku/detail)
|
||
const assetsToDelete = material.assets.filter(
|
||
(a) =>
|
||
a.assetType === 'main-preview' ||
|
||
a.assetType === 'sku-preview' ||
|
||
a.assetType === 'detail-preview' ||
|
||
(a.assetType === 'main' && a.fileUrl.startsWith('uploads/')) ||
|
||
(a.assetType === 'sku' && a.fileUrl.startsWith('uploads/')) ||
|
||
(a.assetType === 'detail' && a.fileUrl.startsWith('uploads/')) ||
|
||
a.assetType === 'all'
|
||
);
|
||
|
||
console.log(`将删除 ${assetsToDelete.length} 条资产记录:`);
|
||
assetsToDelete.forEach((a) => {
|
||
console.log(` - ${a.assetType}: ${a.fileName}`);
|
||
});
|
||
console.log('');
|
||
|
||
// 3. 删除生成的zip文件(只删除本地zip文件)
|
||
const zipFiles = material.assets.filter(
|
||
(a) =>
|
||
((a.assetType === 'main' || a.assetType === 'sku' || a.assetType === 'detail') &&
|
||
a.fileUrl.startsWith('uploads/')) ||
|
||
a.assetType === 'all'
|
||
);
|
||
|
||
console.log(`将删除 ${zipFiles.length} 个zip文件:`);
|
||
for (const asset of zipFiles) {
|
||
const filePath = path.join(process.cwd(), asset.fileUrl);
|
||
console.log(` - ${filePath}`);
|
||
|
||
try {
|
||
await unlink(filePath);
|
||
console.log(` ✅ 删除成功`);
|
||
} catch (err) {
|
||
console.log(` ⚠️ 删除失败: ${err}`);
|
||
}
|
||
}
|
||
console.log('');
|
||
|
||
// 4. 执行数据库回滚
|
||
await prisma.$transaction(async (tx) => {
|
||
// 删除新增的资产记录(逐个删除,避免误删老记录)
|
||
for (const asset of assetsToDelete) {
|
||
await tx.materialAsset.delete({
|
||
where: { id: asset.id },
|
||
});
|
||
}
|
||
|
||
// 恢复素材记录
|
||
await tx.material.update({
|
||
where: { id: material.id },
|
||
data: {
|
||
zipFilePath: '',
|
||
zipFileName: '',
|
||
zipFileSize: BigInt(0),
|
||
},
|
||
});
|
||
});
|
||
|
||
console.log('✅ 回滚完成');
|
||
|
||
} catch (error) {
|
||
console.error('回滚失败:', error);
|
||
process.exit(1);
|
||
} finally {
|
||
await prisma.$disconnect();
|
||
}
|
||
}
|
||
|
||
main();
|