164 lines
5.0 KiB
TypeScript
164 lines
5.0 KiB
TypeScript
/**
|
||
* 公共上传模板 API
|
||
*
|
||
* 获取启用的上传模板列表(不需要管理员权限)
|
||
* 包括预制模板和自定义模板,并做区分
|
||
* 用于上传页面选择模板
|
||
*/
|
||
|
||
import { NextResponse } from 'next/server'
|
||
import { getServerSession } from 'next-auth'
|
||
import { authOptions } from '@/lib/auth'
|
||
import { prisma } from '@/lib/prisma'
|
||
import { canUseCustomTemplates, projectPublicTemplateOptionsWithPaidCore } from '@/lib/license'
|
||
import {
|
||
BUILTIN_TEMPLATE_KEYS,
|
||
BUILTIN_TEMPLATE_TYPES,
|
||
BUILTIN_TEMPLATE_NAMES,
|
||
BUILTIN_TEMPLATE_DESCRIPTIONS,
|
||
STANDARD_FIELDS,
|
||
BUILTIN_TEMPLATE_FIELDS,
|
||
createBuiltinTemplate,
|
||
} from '@/lib/upload-template-presets'
|
||
|
||
const publicSelect = {
|
||
id: true,
|
||
name: true,
|
||
description: true,
|
||
status: true,
|
||
materialType: true,
|
||
materialKind: true,
|
||
fields: {
|
||
orderBy: { orderIndex: 'asc' },
|
||
select: {
|
||
id: true,
|
||
key: true,
|
||
label: true,
|
||
type: true,
|
||
required: true,
|
||
orderIndex: true,
|
||
layoutWidth: true,
|
||
validations: true,
|
||
optionsSource: true,
|
||
optionsStatic: true,
|
||
allowedExtensions: true,
|
||
visibleOnHomeFilter: true,
|
||
isSearchable: true,
|
||
addToCategory: true,
|
||
conditions: true,
|
||
},
|
||
},
|
||
} as const
|
||
|
||
export async function GET() {
|
||
try {
|
||
const session = await getServerSession(authOptions)
|
||
if (!session?.user) {
|
||
return NextResponse.json(
|
||
{ error: '请先登录' },
|
||
{ status: 401 }
|
||
)
|
||
}
|
||
|
||
// 获取启用的预制模板列表
|
||
let enabledBuiltinTemplates: string[] = []
|
||
try {
|
||
// 使用原始 SQL 查询,避免字段不存在时的错误
|
||
const settings = await prisma.$queryRaw<Array<{ enabledBuiltinTemplates?: string | null }>>`
|
||
SELECT "enabledBuiltinTemplates" FROM "system_settings" LIMIT 1
|
||
`
|
||
if (settings[0]?.enabledBuiltinTemplates) {
|
||
const parsed = JSON.parse(settings[0].enabledBuiltinTemplates)
|
||
if (Array.isArray(parsed) && parsed.length > 0) {
|
||
enabledBuiltinTemplates = parsed
|
||
}
|
||
// 如果为空数组或null,表示全部启用,enabledBuiltinTemplates保持为空数组
|
||
}
|
||
// 如果字段不存在或为null,表示全部启用,enabledBuiltinTemplates保持为空数组
|
||
} catch (error) {
|
||
// 字段不存在或解析失败,表示全部启用
|
||
console.error('Failed to parse enabledBuiltinTemplates:', error)
|
||
}
|
||
|
||
const customTemplatesAllowed = await canUseCustomTemplates()
|
||
const customTemplates = customTemplatesAllowed
|
||
? await prisma.uploadTemplate.findMany({
|
||
orderBy: { updatedAt: 'desc' },
|
||
select: publicSelect,
|
||
})
|
||
: []
|
||
|
||
// 生成所有预制模板,只包含启用的
|
||
// 如果 enabledBuiltinTemplates 为空数组,表示全部启用
|
||
const builtinTemplates = BUILTIN_TEMPLATE_KEYS
|
||
.filter(key => enabledBuiltinTemplates.length === 0 || enabledBuiltinTemplates.includes(key))
|
||
.map(key => createBuiltinTemplate(key))
|
||
|
||
// 统计每个模板的素材数量,用于前端动态排序
|
||
const countTargets = [
|
||
...builtinTemplates.map(t => ({ ...t, isBuiltin: true })),
|
||
...customTemplates.map(t => ({ ...t, isBuiltin: false })),
|
||
]
|
||
const templateCounts = await Promise.all(
|
||
countTargets.map((template) => {
|
||
if (template.isBuiltin) {
|
||
const key = template.id.replace('builtin-', '')
|
||
const materialType = BUILTIN_TEMPLATE_TYPES[key] || template.materialType
|
||
return prisma.material.count({
|
||
where: {
|
||
materialType,
|
||
OR: [
|
||
{ templateId: null },
|
||
{ templateId: template.id },
|
||
],
|
||
},
|
||
})
|
||
}
|
||
return prisma.material.count({
|
||
where: {
|
||
templateId: template.id,
|
||
},
|
||
})
|
||
})
|
||
)
|
||
|
||
const materialCounts = Object.fromEntries(
|
||
countTargets.map((template, index) => [template.id, templateCounts[index] || 0])
|
||
)
|
||
|
||
if (!customTemplatesAllowed) {
|
||
const templatesWithCounts = countTargets.map((template, index) => ({
|
||
...template,
|
||
materialCount: templateCounts[index],
|
||
}))
|
||
|
||
return NextResponse.json(templatesWithCounts)
|
||
}
|
||
|
||
const projected = await projectPublicTemplateOptionsWithPaidCore({
|
||
builtinTemplates,
|
||
customTemplates,
|
||
materialCounts,
|
||
})
|
||
|
||
if (!projected.valid) {
|
||
return NextResponse.json({
|
||
error: projected.error || '付费增强包无法生成上传模板列表',
|
||
errorCode: projected.errorCode || 'TEMPLATE_PUBLIC_OPTIONS_PROJECT_FAILED',
|
||
details: projected.details,
|
||
}, { status: 503 })
|
||
}
|
||
|
||
const templatesWithCounts = projected.uploadTemplates.map((template) => ({
|
||
...template,
|
||
materialCount: Number((template as any).materialCount || 0),
|
||
}))
|
||
|
||
return NextResponse.json(templatesWithCounts)
|
||
} catch (error) {
|
||
console.error('Get active upload templates error:', error)
|
||
return NextResponse.json({ error: '获取上传模板失败' }, { status: 500 })
|
||
}
|
||
}
|
||
|