153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
/**
|
|
* 任务-详情上传完成接口(改造版)
|
|
* POST - 打包文件、生成预览图、保存资产信息
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
import { getServerSession } from 'next-auth'
|
|
import { authOptions } from '@/lib/auth'
|
|
import { prisma } from '@/lib/prisma'
|
|
import {
|
|
completeProductPackageUpload,
|
|
parsePublicProductPackageAssets,
|
|
} from '@/lib/product-package-completion'
|
|
|
|
export const runtime = 'nodejs'
|
|
export const dynamic = 'force-dynamic'
|
|
export const maxDuration = 10800
|
|
|
|
interface CompleteRequestBody {
|
|
materialId: string
|
|
taskNo?: string
|
|
dingtalkApprovalNo?: string
|
|
noBarcodes?: boolean
|
|
assets: unknown
|
|
}
|
|
|
|
function getProductPackageCompleteError(error: unknown) {
|
|
const code =
|
|
error && typeof error === 'object' && 'code' in error
|
|
? String((error as { code?: unknown }).code || '')
|
|
: ''
|
|
const message = error instanceof Error ? error.message : ''
|
|
const isDatabaseBusy =
|
|
code === 'P2024' ||
|
|
code === 'P2028' ||
|
|
message.includes('Unable to start a transaction in the given time') ||
|
|
message.includes('Timed out fetching a new connection from the connection pool')
|
|
|
|
if (isDatabaseBusy) {
|
|
return {
|
|
code: 'DATABASE_BUSY',
|
|
message: '系统繁忙,本次上传未完成,请稍后重新上传',
|
|
status: 503,
|
|
}
|
|
}
|
|
|
|
return {
|
|
code: 'UPLOAD_COMPLETE_FAILED',
|
|
message: message || '服务器错误',
|
|
status: 500,
|
|
}
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const session = await getServerSession(authOptions)
|
|
if (!session?.user || !(session.user as any).id) {
|
|
return NextResponse.json(
|
|
{ success: false, error: '未登录' },
|
|
{ status: 401 },
|
|
)
|
|
}
|
|
|
|
const body: CompleteRequestBody = await request.json()
|
|
let assets
|
|
try {
|
|
assets = parsePublicProductPackageAssets(body.assets)
|
|
} catch (error) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '资产参数无效',
|
|
},
|
|
{ status: 400 },
|
|
)
|
|
}
|
|
|
|
const material = await prisma.material.findUnique({
|
|
where: { id: body.materialId },
|
|
select: {
|
|
id: true,
|
|
userId: true,
|
|
materialType: true,
|
|
taskDetailRequesterUserId: true,
|
|
},
|
|
})
|
|
|
|
if (!material) {
|
|
return NextResponse.json(
|
|
{ success: false, error: '素材不存在' },
|
|
{ status: 404 },
|
|
)
|
|
}
|
|
|
|
if (material.userId !== (session.user as any).id) {
|
|
return NextResponse.json(
|
|
{ success: false, error: '无权限操作此素材' },
|
|
{ status: 403 },
|
|
)
|
|
}
|
|
|
|
if (material.materialType !== '任务-详情') {
|
|
return NextResponse.json(
|
|
{ success: false, error: '当前素材不是任务-详情,不能使用此完成接口' },
|
|
{ status: 400 },
|
|
)
|
|
}
|
|
|
|
if (!material.taskDetailRequesterUserId) {
|
|
return NextResponse.json(
|
|
{ success: false, error: '当前素材缺少需求运营人员,不能完成上传' },
|
|
{ status: 400 },
|
|
)
|
|
}
|
|
|
|
const result = await completeProductPackageUpload({
|
|
materialId: body.materialId,
|
|
taskNo: body.taskNo,
|
|
dingtalkApprovalNo: body.dingtalkApprovalNo,
|
|
assets,
|
|
operatorUserId: (session.user as any).id,
|
|
options: {
|
|
allowSkuWithoutBarcodes: body.noBarcodes === true,
|
|
},
|
|
})
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: {
|
|
materialId: result.materialId,
|
|
taskNo: result.taskNo,
|
|
dingtalkApprovalNo: result.dingtalkApprovalNo,
|
|
isFullSet: result.isFullSet,
|
|
message: '上传完成',
|
|
},
|
|
})
|
|
} catch (error) {
|
|
console.error('[Product Package Complete] Error:', error)
|
|
const publicError = getProductPackageCompleteError(error)
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
code: publicError.code,
|
|
error: publicError.message,
|
|
},
|
|
{
|
|
status: publicError.status,
|
|
headers: publicError.status === 503 ? { 'Retry-After': '5' } : undefined,
|
|
},
|
|
)
|
|
}
|
|
}
|