import { NextResponse } from "next/server"; import { z } from "zod"; import { requireAdminSession } from "@/lib/admin/auth"; import { queryAdminRows } from "@/lib/admin/database"; import { adminErrorResponse } from "@/lib/admin/http"; export const runtime = "nodejs"; const schema = z.object({ name: z.string().trim().min(1).max(80), description: z.string().trim().max(500), priceCents: z.number().int().positive().max(100_000_000), credits: z.number().int().positive().max(10_000_000), sortOrder: z.number().int().min(-100_000).max(100_000), enabled: z.boolean(), }).strict(); const updateSchema = schema.extend({ id: z.string().uuid() }); const idSchema = z.object({ id: z.string().uuid() }).strict(); type PackageRow = { id: string; name: string; description: string; price_cents: number; credits: number; sort_order: number; enabled: boolean; created_at: Date; updated_at: Date; }; function output(row: PackageRow) { return { id: row.id, name: row.name, description: row.description, priceCents: row.price_cents, credits: row.credits, sortOrder: row.sort_order, enabled: row.enabled, createdAt: row.created_at.toISOString(), updatedAt: row.updated_at.toISOString(), }; } export async function GET() { try { await requireAdminSession("read"); const rows = await queryAdminRows(` select id, name, description, price_cents, credits, sort_order, enabled, created_at, updated_at from public.payment_packages order by sort_order, created_at `); return NextResponse.json({ packages: rows.map(output) }); } catch (error) { return adminErrorResponse(error); } } export async function POST(request: Request) { try { const auth = await requireAdminSession("write"); const parsed = schema.safeParse(await request.json().catch(() => null)); if (!parsed.success) return NextResponse.json({ error: "套餐参数不正确" }, { status: 400 }); const p = parsed.data; const rows = await queryAdminRows(` insert into public.payment_packages (name, description, price_cents, credits, sort_order, enabled, created_by) values ($1, $2, $3, $4, $5, $6, $7) returning id, name, description, price_cents, credits, sort_order, enabled, created_at, updated_at `, [p.name, p.description, p.priceCents, p.credits, p.sortOrder, p.enabled, auth.user.id]); return NextResponse.json({ package: output(rows[0]) }, { status: 201 }); } catch (error) { return adminErrorResponse(error); } } export async function PATCH(request: Request) { try { await requireAdminSession("write"); const parsed = updateSchema.safeParse(await request.json().catch(() => null)); if (!parsed.success) return NextResponse.json({ error: "套餐参数不正确" }, { status: 400 }); const p = parsed.data; const rows = await queryAdminRows(` update public.payment_packages set name = $2, description = $3, price_cents = $4, credits = $5, sort_order = $6, enabled = $7, updated_at = clock_timestamp() where id = $1 returning id, name, description, price_cents, credits, sort_order, enabled, created_at, updated_at `, [p.id, p.name, p.description, p.priceCents, p.credits, p.sortOrder, p.enabled]); if (!rows[0]) return NextResponse.json({ error: "套餐不存在" }, { status: 404 }); return NextResponse.json({ package: output(rows[0]) }); } catch (error) { return adminErrorResponse(error); } } export async function DELETE(request: Request) { try { await requireAdminSession("write"); const parsed = idSchema.safeParse(await request.json().catch(() => null)); if (!parsed.success) return NextResponse.json({ error: "套餐参数不正确" }, { status: 400 }); const rows = await queryAdminRows<{ id: string }>(` update public.payment_packages set enabled = false, updated_at = clock_timestamp() where id = $1 returning id `, [parsed.data.id]); if (!rows[0]) return NextResponse.json({ error: "套餐不存在" }, { status: 404 }); return NextResponse.json({ ok: true }); } catch (error) { return adminErrorResponse(error); } }