/** * 检查正式系统中上传失败的素材 * * 用途:排查上传中的素材问题 */ import { PrismaClient } from '@prisma/client' import { existsSync } from 'fs' const prisma = new PrismaClient() async function checkUploadIssues() { try { console.log('=== 检查上传失败的素材 ===\n') // 查询最近24小时内创建的素材 const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000) const recentMaterials = await prisma.material.findMany({ where: { createdAt: { gte: twentyFourHoursAgo, }, deletedAt: null, }, orderBy: { createdAt: 'desc', }, include: { user: { select: { username: true, email: true, }, }, }, }) console.log(`找到 ${recentMaterials.length} 条最近24小时创建的素材记录\n`) // 检查可能有问题的情况 const issues: Array<{ material: any issue: string details: string }> = [] for (const material of recentMaterials) { const issuesForThis: string[] = [] const detailsForThis: string[] = [] // 1. 检查视频处理状态 if (material.videoProcessingStatus) { if (material.videoProcessingStatus === 'failed') { issuesForThis.push('视频转码失败') if (material.transcodeLastError) { detailsForThis.push(`错误: ${material.transcodeLastError}`) } } else if (material.videoProcessingStatus === 'pending') { // 检查是否pending太久(超过1小时) const hoursPending = (Date.now() - material.createdAt.getTime()) / (1000 * 60 * 60) if (hoursPending > 1) { issuesForThis.push('视频转码pending时间过长') detailsForThis.push(`已pending ${hoursPending.toFixed(1)} 小时`) } } else if (material.videoProcessingStatus === 'processing') { // 检查是否processing太久(超过2小时) const hoursProcessing = (Date.now() - material.updatedAt.getTime()) / (1000 * 60 * 60) if (hoursProcessing > 2) { issuesForThis.push('视频转码processing时间过长') detailsForThis.push(`已processing ${hoursProcessing.toFixed(1)} 小时`) } } } // 2. 检查文件是否存在 if (material.zipFilePath) { if (!existsSync(material.zipFilePath)) { issuesForThis.push('源文件不存在') detailsForThis.push(`路径: ${material.zipFilePath}`) } } // 3. 检查预览图URL是否为空 if (!material.previewUrl || material.previewUrl.trim() === '') { issuesForThis.push('预览图URL为空') } // 4. 检查是否有zipFileSize但zipFilePath为空 if (material.zipFileSize > 0 && (!material.zipFilePath || material.zipFilePath.trim() === '')) { issuesForThis.push('有文件大小但文件路径为空') detailsForThis.push(`文件大小: ${material.zipFileSize} 字节`) } if (issuesForThis.length > 0) { issues.push({ material, issue: issuesForThis.join(', '), details: detailsForThis.join(' | '), }) } } // 输出结果 if (issues.length === 0) { console.log('✅ 未发现明显的问题\n') } else { console.log(`⚠️ 发现 ${issues.length} 个可能有问题素材:\n`) for (const { material, issue, details } of issues) { console.log(`素材ID: ${material.id}`) console.log(` SPU: ${material.productModel}`) console.log(` 类型: ${material.materialType}`) console.log(` 作者: ${material.authorName} (${material.user?.username || 'N/A'})`) console.log(` 创建时间: ${material.createdAt.toLocaleString('zh-CN')}`) console.log(` 更新时间: ${material.updatedAt.toLocaleString('zh-CN')}`) console.log(` 问题: ${issue}`) if (details) { console.log(` 详情: ${details}`) } if (material.videoProcessingStatus) { console.log(` 视频状态: ${material.videoProcessingStatus}`) if (material.transcodeAttempts) { console.log(` 转码尝试次数: ${material.transcodeAttempts}`) } } if (material.zipFilePath) { console.log(` 文件路径: ${material.zipFilePath}`) console.log(` 文件大小: ${material.zipFileSize} 字节`) } if (material.previewUrl) { console.log(` 预览图: ${material.previewUrl.substring(0, 80)}...`) } console.log('') } } // 输出所有最近创建的素材(简要信息) console.log('\n=== 最近创建的素材列表(全部) ===\n') for (const material of recentMaterials) { const statusInfo = material.videoProcessingStatus ? ` [视频状态: ${material.videoProcessingStatus}]` : '' console.log( `${material.createdAt.toLocaleString('zh-CN')} | ${material.materialType} | ${material.productModel} | ${material.authorName}${statusInfo}` ) } } catch (error) { console.error('查询失败:', error) throw error } finally { await prisma.$disconnect() } } checkUploadIssues() .then(() => { console.log('\n✅ 检查完成') process.exit(0) }) .catch((error) => { console.error('\n❌ 检查失败:', error) process.exit(1) })