diff --git a/scripts/check-sku-asset.ts b/scripts/check-sku-asset.ts deleted file mode 100644 index f55bc68..0000000 --- a/scripts/check-sku-asset.ts +++ /dev/null @@ -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(); -}); diff --git a/scripts/cleanup-duplicate-previews.ts b/scripts/cleanup-duplicate-previews.ts deleted file mode 100644 index 58cc34c..0000000 --- a/scripts/cleanup-duplicate-previews.ts +++ /dev/null @@ -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(); diff --git a/scripts/cleanup-orphaned-product-package.ts b/scripts/cleanup-orphaned-product-package.ts deleted file mode 100644 index 2f96b0d..0000000 --- a/scripts/cleanup-orphaned-product-package.ts +++ /dev/null @@ -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 { - 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); - }); diff --git a/scripts/cleanup-server-orphaned.ts b/scripts/cleanup-server-orphaned.ts deleted file mode 100644 index 1cf0d56..0000000 --- a/scripts/cleanup-server-orphaned.ts +++ /dev/null @@ -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); diff --git a/scripts/count-sku-assets.ts b/scripts/count-sku-assets.ts deleted file mode 100644 index 0f6decb..0000000 --- a/scripts/count-sku-assets.ts +++ /dev/null @@ -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(); -})(); diff --git a/scripts/diagnose-pdf.js b/scripts/diagnose-pdf.js deleted file mode 100644 index fa84a49..0000000 --- a/scripts/diagnose-pdf.js +++ /dev/null @@ -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() diff --git a/scripts/regenerate-brand-previews.ts b/scripts/regenerate-brand-previews.ts deleted file mode 100644 index af70835..0000000 --- a/scripts/regenerate-brand-previews.ts +++ /dev/null @@ -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)