import { allow, deny } from "@/lib/decision" import { isApiError, toApiError, type ApiDecision } from "@/lib/errors" import type { Order, OrderStatus } from "@/lib/types" import { httpJson } from "./http" type Paginated = { items: T[] | null meta: { total: number offset: number limit: number } } export type ListOrdersOptions = { role?: "consumer" | "player" | "owner" status?: OrderStatus offset?: number limit?: number } type ActionResult = { decision: ApiDecision; order?: Order } function withOffsetLimit(path: string, options?: ListOrdersOptions): string { const offset = options?.offset ?? 0 const limit = options?.limit ?? 100 const searchParams = new URLSearchParams({ offset: String(offset), limit: String(limit), }) if (options?.role) searchParams.set("role", options.role) if (options?.status) searchParams.set("status", options.status) return `${path}?${searchParams.toString()}` } function unwrapOrder(value: unknown): Order | undefined { if (typeof value !== "object" || value === null) return undefined if ("order" in value) { const envelope = value as { order?: Order } return envelope.order } return value as Order } function denyFromError(error: unknown): ApiDecision { if (error instanceof Error && error.message === "UNAUTHORIZED") { return deny(401, "请先登录") } const apiError = toApiError(error) return deny(apiError.code, apiError.msg) } export async function listOrders(options?: ListOrdersOptions): Promise { const res = await httpJson>(withOffsetLimit("/api/v1/orders", options), { cache: "no-store", }) return res.items ?? [] } export async function getOrderById(orderId: string): Promise { try { const res = await httpJson(`/api/v1/orders/${encodeURIComponent(orderId)}`, { cache: "no-store", }) return unwrapOrder(res) } catch (error) { if (error instanceof Error && error.message === "UNAUTHORIZED") { throw error } if (isApiError(error) && error.code === 404) { return undefined } throw error } } export async function listOrdersByConsumer(consumerId: string): Promise { const items = await listOrders({ role: "consumer" }) return items.filter((order) => order.consumerId === consumerId) } interface CreatePaidOrderInput { playerId: string serviceId: string shopId?: string quantity: number note?: string } export async function createPaidOrder(input: CreatePaidOrderInput): Promise { try { const res = await httpJson("/api/v1/orders/paid", { method: "POST", cache: "no-store", json: input, }) const order = unwrapOrder(res) if (!order) { return { decision: deny(500, "订单创建失败") } } return { decision: allow(), order } } catch (error) { return { decision: denyFromError(error) } } } async function postOrderAction(orderId: string, action: string): Promise { try { const res = await httpJson(`/api/v1/orders/${encodeURIComponent(orderId)}/${action}`, { method: "POST", cache: "no-store", }) const order = unwrapOrder(res) if (order) { return { decision: allow(), order } } const refetched = await getOrderById(orderId).catch(() => undefined) if (refetched) { return { decision: allow(), order: refetched } } return { decision: allow() } } catch (error) { return { decision: denyFromError(error) } } } export async function payOrder(orderId: string): Promise { return postOrderAction(orderId, "pay") } export async function acceptOrder(orderId: string): Promise { return postOrderAction(orderId, "accept") } export async function requestClose(orderId: string): Promise { return postOrderAction(orderId, "request-close") } export async function confirmClose(orderId: string): Promise { return postOrderAction(orderId, "confirm-close") } export async function cancelPreAccept(orderId: string): Promise { return postOrderAction(orderId, "cancel") }