import { parseAdminAuth } from "@/lib/api/admin-auth-context"; import { fail, ok } from "@/lib/response"; import { AuthError } from "@/modules/auth/errors"; import { requirePermission } from "@/modules/auth/rbac"; import { listQuoteQueryLogs, type QuoteQueryOutcome, } from "@/modules/quote/query-log"; const VALID_OUTCOMES: readonly QuoteQueryOutcome[] = [ "processing", "success", "failed", "stale", ]; function parsePagination(searchParams: URLSearchParams): { page: number; size: number; } | null { const pageRaw = searchParams.get("page"); const sizeRaw = searchParams.get("size"); if (!pageRaw || !sizeRaw) { return null; } const page = Number(pageRaw); const size = Number(sizeRaw); if ( !Number.isInteger(page) || !Number.isInteger(size) || page < 1 || size < 1 || size > 100 ) { return null; } return { page, size }; } /** GET /api/admin/query-logs — 查价记录(最多保留 1000 条) */ export async function GET(request: Request) { let auth; try { auth = parseAdminAuth(request); requirePermission(auth, "alert:read"); } catch (error) { if (error instanceof AuthError) { return fail(error.code, error.message, error.httpStatus); } throw error; } void auth; const searchParams = new URL(request.url).searchParams; const pagination = parsePagination(searchParams); if (!pagination) { return fail("VALIDATION_FAILED", "请提供有效的 page 和 size 参数", 400); } const customerId = searchParams.get("customer_id")?.trim() || undefined; const outcomeRaw = searchParams.get("outcome")?.trim(); if (outcomeRaw && !VALID_OUTCOMES.includes(outcomeRaw as QuoteQueryOutcome)) { return fail("VALIDATION_FAILED", "无效的查询结果筛选", 400); } const data = await listQuoteQueryLogs({ page: pagination.page, size: pagination.size, customerId, outcome: outcomeRaw as QuoteQueryOutcome | undefined, }); return ok(data); }