gongxiangp2/scripts/check-upload-issues.ts
chenpei ea9076df45 feat: 实现统一的下载错误处理系统并修复产品全案数据库Schema
- 创建统一的下载错误处理模块 (lib/download-errors.ts)
- 实现13种错误类型分类和中文错误消息
- 后端统一使用 createDownloadError 创建标准化错误响应
- 前端统一使用 parseDownloadError 解析错误并显示
- 修复正式系统数据库Schema,添加产品全案相关字段和表
- 执行数据库迁移:添加 task_no, task_status, task_fetched_at 字段
- 创建 material_assets, api_keys, api_call_logs 表
2026-01-05 17:52:42 +08:00

167 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 检查正式系统中上传失败的素材
*
* 用途:排查上传中的素材问题
*/
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)
})