120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
/**
|
|
* 管理员材质详情 API
|
|
* GET /api/admin/materials/[id] - 获取材质详情
|
|
* PUT /api/admin/materials/[id] - 更新材质
|
|
* DELETE /api/admin/materials/[id] - 删除材质
|
|
*/
|
|
|
|
import { NextRequest } from 'next/server'
|
|
import { z } from 'zod'
|
|
import { handleRequest, jsonSuccess, jsonError } from '@/server/core/response'
|
|
import { ErrorCode, AppError } from '@/server/core/errors'
|
|
import { materialService } from '@/server/services'
|
|
|
|
// 更新材质的验证 schema
|
|
const updateMaterialSchema = z.object({
|
|
name: z.string().min(1).max(50).optional(),
|
|
categoryId: z.string().optional(),
|
|
thumbnailUrl: z.string().optional(),
|
|
textureUrl: z.string().optional().nullable(),
|
|
normalMapUrl: z.string().optional().nullable(),
|
|
color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional(),
|
|
metalness: z.number().min(0).max(1).optional(),
|
|
roughness: z.number().min(0).max(1).optional(),
|
|
opacity: z.number().min(0).max(1).optional(),
|
|
textureRepeat: z.number().min(0.1).max(10).optional(),
|
|
textureRotation: z.number().min(0).max(Math.PI * 2).optional(),
|
|
textureSizeMm: z.number().min(10).max(5000).optional(),
|
|
isPreset: z.boolean().optional(),
|
|
isActive: z.boolean().optional(),
|
|
})
|
|
|
|
// 允许的管理角色
|
|
const ADMIN_ROLES = ['SUPER_ADMIN', 'ADMIN', 'SUPERVISOR'] as const
|
|
|
|
/**
|
|
* GET - 获取材质详情
|
|
*/
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
return handleRequest(request, async ({ requestId }) => {
|
|
const { id } = await params
|
|
|
|
try {
|
|
const material = await materialService.findByIdWithUsage(id)
|
|
return jsonSuccess(material, 200, requestId)
|
|
} catch (error) {
|
|
if (error instanceof AppError) {
|
|
return jsonError(error.code, error.message, 404, requestId)
|
|
}
|
|
throw error
|
|
}
|
|
}, { allowedRoles: [...ADMIN_ROLES] })
|
|
}
|
|
|
|
/**
|
|
* PUT - 更新材质
|
|
*/
|
|
export async function PUT(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
return handleRequest(request, async ({ requestId }) => {
|
|
const { id } = await params
|
|
const body = await request.json()
|
|
|
|
// 验证请求数据
|
|
const validationResult = updateMaterialSchema.safeParse(body)
|
|
if (!validationResult.success) {
|
|
return jsonError(
|
|
ErrorCode.VALIDATION_FAILED,
|
|
'数据验证失败: ' + validationResult.error.issues.map(e => e.message).join(', '),
|
|
400,
|
|
requestId
|
|
)
|
|
}
|
|
|
|
const data = validationResult.data
|
|
|
|
try {
|
|
const material = await materialService.update(id, data)
|
|
return jsonSuccess({ material, message: '材质更新成功' }, 200, requestId)
|
|
} catch (error) {
|
|
if (error instanceof AppError) {
|
|
const statusCode = error.code === ErrorCode.FILE_NOT_FOUND ? 404 : 400
|
|
return jsonError(error.code, error.message, statusCode, requestId)
|
|
}
|
|
throw error
|
|
}
|
|
}, { allowedRoles: [...ADMIN_ROLES] })
|
|
}
|
|
|
|
/**
|
|
* DELETE - 删除材质(软删除)
|
|
*/
|
|
export async function DELETE(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
return handleRequest(request, async ({ requestId }) => {
|
|
const { id } = await params
|
|
const { searchParams } = new URL(request.url)
|
|
const hardDelete = searchParams.get('hard') === 'true'
|
|
|
|
try {
|
|
await materialService.delete(id, hardDelete)
|
|
return jsonSuccess({
|
|
message: hardDelete ? '材质已永久删除' : '材质已禁用',
|
|
}, 200, requestId)
|
|
} catch (error) {
|
|
if (error instanceof AppError) {
|
|
const statusCode = error.code === ErrorCode.FILE_NOT_FOUND ? 404 : 400
|
|
return jsonError(error.code, error.message, statusCode, requestId)
|
|
}
|
|
throw error
|
|
}
|
|
}, { allowedRoles: [...ADMIN_ROLES] })
|
|
}
|