import { NextRequest } from 'next/server'; import { db } from '@/db'; import { content } from '@/db/schema'; import { checkIsAdmin, getAdminUserId } from '@/lib/auth/check-permission'; import { createAuditLog } from '@/lib/audit'; import { forbidden, badRequest, success, handleApiError, validationError } from '@/lib/api-response'; import { eq, desc, and, like, sql } from 'drizzle-orm'; import { nanoid } from 'nanoid'; export async function GET(request: NextRequest) { try { const { isAdmin } = await checkIsAdmin(); if (!isAdmin) { return forbidden(); } const { searchParams } = new URL(request.url); const type = searchParams.get('type'); const status = searchParams.get('status'); const search = searchParams.get('search'); const page = parseInt(searchParams.get('page') || '1'); const limit = parseInt(searchParams.get('limit') || '20'); const offset = (page - 1) * limit; const conditions = []; if (type) { conditions.push(eq(content.type, type as 'news' | 'product' | 'service' | 'case')); } if (status) { conditions.push(eq(content.status, status as 'draft' | 'published' | 'archived')); } if (search) { conditions.push(like(content.title, `%${search}%`)); } const whereClause = conditions.length > 0 ? and(...conditions) : undefined; const [items, countResult] = await Promise.all([ db .select() .from(content) .where(whereClause) .orderBy(desc(content.createdAt)) .limit(limit) .offset(offset), db .select({ count: sql`count(*)` }) .from(content) .where(whereClause), ]); const total = countResult[0]?.count || 0; return success({ items, pagination: { page, limit, total, totalPages: Math.ceil(total / limit), }, }); } catch (error) { return handleApiError(error); } } export async function POST(request: NextRequest) { try { const { isAdmin } = await checkIsAdmin(); const userId = await getAdminUserId(); if (!isAdmin || !userId) { return forbidden(); } const body = await request.json(); const { type, title, slug, excerpt, contentBody, coverImage, category, tags, status: contentStatus, metadata } = body; if (!type || !title || !slug) { return validationError('缺少必要字段', { required: ['type', 'title', 'slug'] }); } const existingContent = await db .select() .from(content) .where(eq(content.slug, slug)) .limit(1); if (existingContent.length > 0) { return badRequest('Slug 已存在'); } const now = new Date(); const newContent = await db .insert(content) .values({ id: nanoid(), type, title, slug, excerpt: excerpt || null, content: contentBody || '', coverImage: coverImage || null, category: category || null, tags: tags || [], status: contentStatus || 'draft', publishedAt: contentStatus === 'published' ? now : null, authorId: userId, metadata: metadata || null, createdAt: now, updatedAt: now, }) .returning(); await createAuditLog({ userId, action: 'create', resourceType: 'content', resourceId: newContent[0]!.id, details: { type, title, status: contentStatus || 'draft', }, }); return success(newContent[0], 201); } catch (error) { return handleApiError(error); } }