136 lines
3.5 KiB
TypeScript
136 lines
3.5 KiB
TypeScript
/**
|
||
* 视频转码统计 API(管理员)
|
||
*
|
||
* 提供转码任务的统计信息
|
||
*/
|
||
|
||
import { NextRequest, NextResponse } from 'next/server'
|
||
import { getServerSession } from 'next-auth'
|
||
import { authOptions } from '@/lib/auth'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { transcodeQueue } from '@/lib/video-transcode-queue'
|
||
import { isCurrentAdmin } from '@/lib/admin-permissions'
|
||
|
||
export const dynamic = 'force-dynamic'
|
||
|
||
/**
|
||
* GET /api/admin/video-transcode-stats
|
||
* 获取转码统计信息
|
||
*/
|
||
export async function GET(req: NextRequest) {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
if (!session) {
|
||
return NextResponse.json(
|
||
{ error: '未登录' },
|
||
{ status: 401 }
|
||
)
|
||
}
|
||
|
||
if (!(await isCurrentAdmin(session))) {
|
||
return NextResponse.json(
|
||
{ error: '需要管理员权限' },
|
||
{ status: 403 }
|
||
)
|
||
}
|
||
|
||
// 获取转码队列状态
|
||
const queueStatus = transcodeQueue.getStatus()
|
||
|
||
// 统计数据库中的转码状态
|
||
const [pendingCount, processingCount, doneCount, failedCount] = await Promise.all([
|
||
prisma.material.count({
|
||
where: {
|
||
materialKind: 'VIDEO',
|
||
videoProcessingStatus: 'pending',
|
||
},
|
||
}),
|
||
prisma.material.count({
|
||
where: {
|
||
materialKind: 'VIDEO',
|
||
videoProcessingStatus: 'processing',
|
||
},
|
||
}),
|
||
prisma.material.count({
|
||
where: {
|
||
materialKind: 'VIDEO',
|
||
videoProcessingStatus: 'done',
|
||
},
|
||
}),
|
||
prisma.material.count({
|
||
where: {
|
||
materialKind: 'VIDEO',
|
||
videoProcessingStatus: 'failed',
|
||
},
|
||
}),
|
||
])
|
||
|
||
const [queuedJobCount, processingJobCount, failedJobCount] = await Promise.all([
|
||
(prisma as any).videoTranscodeJob.count({
|
||
where: { status: 'queued' },
|
||
}),
|
||
(prisma as any).videoTranscodeJob.count({
|
||
where: { status: 'processing' },
|
||
}),
|
||
(prisma as any).videoTranscodeJob.count({
|
||
where: { status: 'failed' },
|
||
}),
|
||
])
|
||
|
||
// 获取最近失败的转码任务(最多10个)
|
||
const recentFailed = await prisma.material.findMany({
|
||
where: {
|
||
materialKind: 'VIDEO',
|
||
videoProcessingStatus: 'failed',
|
||
},
|
||
select: {
|
||
id: true,
|
||
productModel: true,
|
||
categoryName: true,
|
||
sceneName: true,
|
||
createdAt: true,
|
||
updatedAt: true,
|
||
},
|
||
orderBy: {
|
||
updatedAt: 'desc',
|
||
},
|
||
take: 10,
|
||
})
|
||
|
||
return NextResponse.json({
|
||
queue: {
|
||
queueLength: queueStatus.queueLength,
|
||
processingCount: queueStatus.processingCount,
|
||
maxConcurrent: queueStatus.maxConcurrent,
|
||
processingIds: queueStatus.processingIds,
|
||
queuedIds: queueStatus.queuedIds,
|
||
},
|
||
statistics: {
|
||
pending: pendingCount,
|
||
processing: processingCount,
|
||
done: doneCount,
|
||
failed: failedCount,
|
||
total: pendingCount + processingCount + doneCount + failedCount,
|
||
},
|
||
jobs: {
|
||
queued: queuedJobCount,
|
||
processing: processingJobCount,
|
||
failed: failedJobCount,
|
||
},
|
||
recentFailed: recentFailed.map((m) => ({
|
||
id: m.id,
|
||
name: `${m.productModel}_${m.categoryName}_${m.sceneName}`,
|
||
createdAt: m.createdAt,
|
||
failedAt: m.updatedAt,
|
||
})),
|
||
})
|
||
} catch (error) {
|
||
console.error('[TranscodeStats] Error:', error)
|
||
return NextResponse.json(
|
||
{ error: '获取统计信息失败' },
|
||
{ status: 500 }
|
||
)
|
||
}
|
||
}
|
||
|