清理 scripts 中无引用的一次性补洞脚本

This commit is contained in:
chenpei 2026-03-06 15:57:44 +08:00
parent 2b522aa5a5
commit 7fdc6bb91d
7 changed files with 0 additions and 654 deletions

View File

@ -1,20 +0,0 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
prisma.materialAsset.findFirst({
where: {
materialId: 'f8148b30-d83f-4e6a-800e-fa047efd9b16',
assetType: 'sku',
fileUrl: { startsWith: 'uploads/' }
}
}).then(asset => {
if (asset) {
console.log('SKU zip 资产记录:');
console.log(' fileName:', asset.fileName);
console.log(' fileUrl:', asset.fileUrl);
console.log(' fileSize:', asset.fileSize);
} else {
console.log('未找到 SKU zip 资产记录');
}
prisma.$disconnect();
});

View File

@ -1,31 +0,0 @@
/**
* 清理重复的预览图记录
*/
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
console.log('='.repeat(60));
console.log('清理 XG0176 的重复预览图记录');
console.log('='.repeat(60));
const materialId = 'f8148b30-d83f-4e6a-800e-fa047efd9b16';
// 删除所有 *-preview 类型的资产记录
const result = await prisma.materialAsset.deleteMany({
where: {
materialId,
assetType: {
in: ['main-preview', 'sku-preview', 'detail-preview'],
},
},
});
console.log(`✅ 已删除 ${result.count} 条预览图记录`);
await prisma.$disconnect();
}
main();

View File

@ -1,185 +0,0 @@
/**
* 清理孤立的任务-详情素材残留文件
* 用于清理已删除素材的数据库记录和文件系统中的残留文件
*/
import { prisma } from '../lib/prisma';
import { deleteFromS3, isS3Url } from '../lib/s3';
import { promises as fs } from 'fs';
import path from 'path';
const MATERIAL_ID = 'cc7e5cdd-d408-4bcd-a73f-4ddcaa8054b9';
async function cleanupOrphanedFiles() {
console.log('开始清理残留文件...\n');
// 1. 检查数据库中的素材记录
console.log('1. 检查数据库中的素材记录...');
const material = await prisma.material.findUnique({
where: { id: MATERIAL_ID },
select: {
id: true,
materialType: true,
previewUrl: 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}] id=${asset.id}, type=${asset.assetType}, url=${asset.fileUrl}, fileName=${asset.fileName}`);
});
} else {
console.log(` ✅ 资产记录已删除`);
}
// 3. 检查本地文件系统
console.log('\n3. 检查本地文件系统...');
const uploadsDir = path.join(process.cwd(), 'uploads', 'product-package', MATERIAL_ID);
try {
const stats = await fs.stat(uploadsDir);
if (stats.isDirectory()) {
const files = await fs.readdir(uploadsDir, { recursive: true });
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. 检查 S3 文件(如果有资产记录)
if (assets.length > 0) {
console.log('\n4. 检查 S3 文件...');
const s3Files = assets.filter(a => isS3Url(a.fileUrl));
const localFiles = assets.filter(a => !isS3Url(a.fileUrl));
console.log(` S3 文件: ${s3Files.length} 个`);
console.log(` 本地文件: ${localFiles.length} 个`);
if (s3Files.length > 0) {
console.log(` S3 文件列表:`);
s3Files.forEach((asset, index) => {
console.log(` [${index + 1}] ${asset.fileUrl}`);
});
}
}
// 5. 询问是否清理
console.log('\n' + '='.repeat(60));
console.log('清理总结:');
console.log(` - 素材记录: ${material ? '存在' : '已删除'}`);
console.log(` - 资产记录: ${assets.length} 条`);
console.log(` - 本地文件: ${await checkLocalFiles(uploadsDir) ? '存在' : '已删除'}`);
console.log('='.repeat(60));
// 自动清理(如果发现残留)
if (material || assets.length > 0 || await checkLocalFiles(uploadsDir)) {
console.log('\n开始自动清理...\n');
// 删除资产记录
if (assets.length > 0) {
console.log('删除资产记录...');
const deletedAssets = await prisma.materialAsset.deleteMany({
where: { materialId: MATERIAL_ID },
});
console.log(` ✅ 已删除 ${deletedAssets.count} 条资产记录`);
}
// 删除素材记录
if (material) {
console.log('删除素材记录...');
try {
await prisma.material.delete({
where: { id: MATERIAL_ID },
});
console.log(` ✅ 已删除素材记录`);
} catch (err: any) {
console.log(` ⚠️ 删除素材记录失败: ${err.message}`);
}
}
// 删除本地文件
try {
const exists = await checkLocalFiles(uploadsDir);
if (exists) {
console.log('删除本地文件...');
await fs.rm(uploadsDir, { recursive: true, force: true });
console.log(` ✅ 已删除本地目录: ${uploadsDir}`);
}
} catch (err: any) {
console.log(` ⚠️ 删除本地文件失败: ${err.message}`);
}
// 删除 S3 文件
if (assets.length > 0) {
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✅ 没有发现残留文件,无需清理。');
}
}
async function checkLocalFiles(dir: string): Promise<boolean> {
try {
await fs.access(dir);
return true;
} catch {
return false;
}
}
// 运行清理
cleanupOrphanedFiles()
.then(() => {
console.log('\n脚本执行完成');
process.exit(0);
})
.catch((error) => {
console.error('脚本执行失败:', error);
process.exit(1);
});

View File

@ -1,149 +0,0 @@
/**
* 在服务器上清理孤立的任务-详情素材残留文件
*/
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);

View File

@ -1,34 +0,0 @@
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
(async () => {
const skuPreviewCount = await prisma.materialAsset.count({
where: {
materialId: 'f8148b30-d83f-4e6a-800e-fa047efd9b16',
assetType: 'sku-preview'
}
});
const skuS3Count = await prisma.materialAsset.count({
where: {
materialId: 'f8148b30-d83f-4e6a-800e-fa047efd9b16',
assetType: 'sku',
fileUrl: { startsWith: 'https://' }
}
});
const skuZipCount = await prisma.materialAsset.count({
where: {
materialId: 'f8148b30-d83f-4e6a-800e-fa047efd9b16',
assetType: 'sku',
fileUrl: { startsWith: 'uploads/' }
}
});
console.log('sku-preview (预览图):', skuPreviewCount);
console.log('sku (S3 原图):', skuS3Count);
console.log('sku (本地 zip):', skuZipCount);
console.log('总计:', skuPreviewCount + skuS3Count + skuZipCount);
await prisma.$disconnect();
})();

View File

@ -1,181 +0,0 @@
#!/usr/bin/env node
/**
* 品牌VI灵感素材预览图诊断脚本
*
* 用途:检查生产环境中品牌VI灵感素材的预览图问题
* 运行:node scripts/diagnose-pdf.js
*/
const { PrismaClient } = require('@prisma/client')
const fs = require('fs/promises')
const path = require('path')
const { exec } = require('child_process')
const { promisify } = require('util')
const execAsync = promisify(exec)
const prisma = new PrismaClient()
// 问题素材ID列表
const PROBLEM_MATERIAL_IDS = [
'3ce99933-4df8-427f-aa30-454148025e1c',
'390fe674-a2a6-47f1-9b5d-6e377e5cac2c',
'fc8ab566-fd0b-4760-b68d-35a46c94d1bc',
'905b709d-74ab-4def-930b-ac5b86dfd381',
'64137416-3f37-4243-a72b-75f11f3a0114'
]
async function checkSystem() {
console.log('\n=== 系统环境检查 ===\n')
// 检查 pdftoppm 是否安装
try {
const { stdout } = await execAsync('which pdftoppm')
console.log('✅ pdftoppm 路径:', stdout.trim())
// 检查版本
try {
const { stdout: version } = await execAsync('pdftoppm -v')
console.log('✅ pdftoppm 版本信息:', version.split('\n')[0])
} catch (e) {
console.log('⚠️ 无法获取 pdftoppm 版本')
}
} catch (e) {
console.log('❌ pdftoppm 未安装或不在 PATH 中')
}
// 检查上传目录
const uploadDir = process.env.UPLOAD_DIR || './uploads'
console.log('\n上传目录配置:', uploadDir)
try {
const stats = await fs.stat(uploadDir)
console.log('✅ 上传目录存在,权限:', stats.mode.toString(8))
} catch (e) {
console.log('❌ 上传目录不存在或无权限访问')
}
// 检查临时目录
const tmpDir = require('os').tmpdir()
console.log('临时目录:', tmp_dir)
try {
await fs.access(tmpDir, fs.constants.W_OK)
console.log('✅ 临时目录可写')
} catch (e) {
console.log('❌ 临时目录不可写')
}
}
async function diagnoseMaterial(materialId) {
console.log(`\n${'='.repeat(60)}`)
console.log(`诊断素材: ${materialId}`)
console.log('='.repeat(60))
// 1. 查询数据库
const material = await prisma.material.findUnique({
where: { id: materialId },
include: {
assets: true,
skus: true
}
})
if (!material) {
console.log('❌ 素材不存在')
return
}
console.log('\n📊 数据库信息:')
console.log(' - 产品型号:', material.productModel)
console.log(' - 素材类型:', material.materialType)
console.log(' - 预览URL:', material.previewUrl || '(空)')
console.log(' - ZIP文件路径:', material.zipFilePath || '(空)')
console.log(' - ZIP文件名:', material.zipFileName || '(空)')
console.log(' - 资源数量:', material.assets.length)
console.log(' - SKU数量:', material.skus.length)
// 2. 检查 PDF 文件是否存在
const pdfPath = material.zipFilePath
if (!pdfPath) {
console.log('\n❌ 没有保存 PDF 文件路径')
return
}
console.log('\n📁 文件系统检查:')
console.log(' - PDF 路径:', pdfPath)
try {
const stats = await fs.stat(pdfPath)
console.log(' ✅ PDF 文件存在')
console.log(' - 文件大小:', (stats.size / 1024 / 1024).toFixed(2), 'MB')
console.log(' - 修改时间:', stats.mtime)
// 检查文件是否为有效 PDF
const handle = await fs.open(pdfPath, 'r')
const buffer = Buffer.alloc(4)
await handle.read(buffer, 0, 4, 0)
await handle.close()
const header = buffer.toString('ascii', 0, 4)
if (header === '%PDF') {
console.log(' ✅ 文件格式正确 (PDF)')
} else {
console.log(' ❌ 文件格式错误,期望 %PDF,实际:', header)
return
}
// 3. 尝试提取预览图
console.log('\n🖼️ 尝试提取 PDF 预览图...')
const { generatePdfPreview } = require('../lib/pdf-processor')
const result = await generatePdfPreview(pdfPath)
if (result.success) {
console.log(' ✅ PDF 预览图提取成功!')
console.log(' - 预览图路径:', result.previewPath)
console.log(' - 尺寸:', result.width, 'x', result.height)
// 读取预览图大小
const previewStats = await fs.stat(result.previewPath)
console.log(' - 文件大小:', (previewStats.size / 1024).toFixed(2), 'KB')
// 清理测试生成的预览图
await fs.unlink(result.previewPath).catch(() => {})
console.log(' ✅ 测试预览图已清理')
} else {
console.log(' ❌ PDF 预览图提取失败')
console.log(' - 错误信息:', result.error)
}
} catch (e) {
console.log(' ❌ 文件访问错误:', e.message)
}
}
async function main() {
console.log('🔍 品牌VI灵感素材预览图诊断工具')
console.log('时间:', new Date().toLocaleString('zh-CN'))
try {
// 检查系统环境
await checkSystem()
// 诊断每个问题素材
for (const id of PROBLEM_MATERIAL_IDS) {
await diagnoseMaterial(id)
}
console.log('\n' + '='.repeat(60))
console.log('✅ 诊断完成')
console.log('='.repeat(60) + '\n')
} catch (error) {
console.error('\n❌ 诊断过程出错:', error)
} finally {
await prisma.$disconnect()
}
}
main()

View File

@ -1,54 +0,0 @@
const { PrismaClient } = require('@prisma/client')
const { processPdfUpload } = require('../lib/pdf-upload-handler')
const prisma = new PrismaClient()
async function main() {
const ids = [
'3ce99933-4df8-427f-aa30-454148025e1c',
'390fe674-a2a6-47f1-9b5d-6e377e5cac2c',
'fc8ab566-fd0b-4760-b68d-35a46c94d1bc',
'905b709d-74ab-4def-930b-ac5b86dfd381',
'64137416-3f37-4243-a72b-75f11f3a0114'
]
console.log('开始处理', ids.length, '个品牌灵感素材的PDF预览重新生成...')
for (const id of ids) {
const m = await prisma.material.findUnique({
where: { id },
select: { id: true, productModel: true, zipFilePath: true, previewUrl: true }
})
if (!m) {
console.log('SKIP:', id, '- not found')
continue
}
console.log('PROCESSING:', m.productModel, '|', m.id)
console.log(' Current previewUrl:', m.previewUrl || '(empty)')
if (m.zipFilePath) {
try {
const result = await processPdfUpload(m.zipFilePath, '')
if (result.success && result.previewUrl) {
await prisma.material.update({
where: { id },
data: { previewUrl: result.previewUrl }
})
console.log(' ✓ Success:', result.previewUrl)
} else {
console.log(' ✗ Failed:', result.error)
}
} catch (e) {
console.log(' ✗ Error:', e.message)
}
} else {
console.log(' SKIP: no zipFilePath')
}
}
await prisma.$disconnect()
console.log('处理完成!')
}
main().catch(console.error)