"use client"; import { useTable } from "@refinedev/antd"; import { useGetIdentity, useInvalidate } from "@refinedev/core"; import { List } from "@refinedev/antd"; import { App, Button, Form, InputNumber, Modal, Space, Table, Tag, Typography, type TableColumnsType, } from "antd"; import { useState } from "react"; import { adminRequestJson, type AdminIdentity } from "@/lib/admin/providers"; import { formatAdminDate, ResourceTable } from "./resource-table"; const { Text } = Typography; type Subscription = { id: string; userId: string; email: string | null; productCode: string; productVersion: number; status: string; startsAt: string; endsAt: string; createdAt: string; }; type AdjustmentForm = { days: number }; export function SubscriptionsResource() { const { message } = App.useApp(); const { data: identity } = useGetIdentity(); const table = useTable({ resource: "subscriptions", syncWithLocation: true, }); const [form] = Form.useForm(); const [selected, setSelected] = useState(null); const [saving, setSaving] = useState(false); const [revokingId, setRevokingId] = useState(null); const canAdjust = Boolean( identity?.permissions.includes("billing.adjustments.write"), ); async function adjust( item: Subscription, action: "extend" | "revoke", days: number | undefined, ) { await adminRequestJson("/api/admin/subscriptions", { method: "POST", body: JSON.stringify({ id: item.id, action, days, expectedEndsAt: item.endsAt, }), }); await table.tableQuery.refetch(); } async function extend(values: AdjustmentForm) { if (!selected) return; setSaving(true); try { await adjust(selected, "extend", values.days); message.success("订阅已延长"); setSelected(null); form.resetFields(); } catch (error) { message.error(error instanceof Error ? error.message : "延长订阅失败"); } finally { setSaving(false); } } async function revoke(item: Subscription) { setRevokingId(item.id); try { await adjust(item, "revoke", undefined); message.success("订阅已撤销"); } catch (error) { message.error(error instanceof Error ? error.message : "撤销订阅失败"); } finally { setRevokingId(null); } } const columns: TableColumnsType = [ { title: "用户", render: (_, item) => ( {item.email ?? "未记录邮箱"} {item.userId} ), }, { title: "商品", render: (_, item) => `${item.productCode} · v${item.productVersion}`, }, { title: "状态", dataIndex: "status", render: (value) => ( {value} ), }, { title: "开始", dataIndex: "startsAt", render: formatAdminDate }, { title: "到期", dataIndex: "endsAt", render: formatAdminDate }, { title: "操作", fixed: "right", render: (_, item) => ( {canAdjust && ( )} {canAdjust && ( )} ), }, ]; return ( form.submit()} onCancel={() => setSelected(null)} destroyOnHidden > form={form} layout="vertical" onFinish={extend} > ); } type Order = { id: string; orderNo: string; userId: string; email: string | null; productCode: string | null; productVersion: number | null; moneyCents: number; currency: string; status: string; grantType: string | null; grantStatus: string; grantError: string | null; adjustmentVersion: number; refundStatus: string; refundAmountCents: number | null; refundedAt: string | null; paidAt: string | null; createdAt: string; }; export function OrdersResource() { const { message } = App.useApp(); const { data: identity } = useGetIdentity(); const invalidate = useInvalidate(); const [target, setTarget] = useState<{ orderId: string; action: "retry_grant" | "compensate" | "record_refund"; } | null>(null); const canAdjust = Boolean( identity?.permissions.includes("billing.adjustments.write"), ); async function adjust( order: Order, action: "retry_grant" | "compensate" | "record_refund", ) { setTarget({ orderId: order.id, action }); try { const result = await adminRequestJson<{ data: { actionSuccess: boolean }; }>("/api/admin/orders", { method: "POST", headers: { "x-request-id": crypto.randomUUID() }, body: JSON.stringify({ id: order.id, action, expectedVersion: order.adjustmentVersion, }), }); await invalidate({ resource: "orders", invalidates: ["list"] }); if (action === "retry_grant" && !result.data.actionSuccess) { message.warning("已执行重试,但权益发放仍失败,请查看最新错误"); } else { message.success( action === "record_refund" ? "已记录账务全额退款状态" : "订单权益操作已完成", ); } } catch (error) { message.error(error instanceof Error ? error.message : "订单操作失败"); } finally { setTarget(null); } } const columns: TableColumnsType = [ { title: "订单", render: (_, item) => ( {item.orderNo} {formatAdminDate(item.createdAt)} ), }, { title: "用户", render: (_, item) => item.email ?? item.userId }, { title: "商品", render: (_, item) => item.productCode ? `${item.productCode} · v${item.productVersion}` : "旧积分订单", }, { title: "金额", render: (_, item) => `${item.currency} ${(item.moneyCents / 100).toFixed(2)}`, }, { title: "支付", dataIndex: "status", render: (value) => ( {value} ), }, { title: "权益发放", render: (_, item) => ( {item.grantStatus} {item.grantError && {item.grantError}} ), }, { title: "退款账务", render: (_, item) => item.refundStatus === "recorded" ? ( 已记录 {formatAdminDate(item.refundedAt)} ) : ( "—" ), }, { title: "支付时间", dataIndex: "paidAt", render: formatAdminDate }, { title: "领域动作", fixed: "right", render: (_, item) => canAdjust ? ( ) : null, }, ]; return ( <> “记录全额退款”仅记录账务状态,不调用支付网关。 resource="orders" title="支付订单与权益发放" columns={columns} statusOptions={[ "pending", "paid", "failed", "granted", "refunded", "recorded", ].map((value) => ({ value, label: value }))} /> ); } type Usage = { id: string; userId: string; email: string | null; requestId: string; featureKey: string; source: string; requestedModelId: string | null; actualModelId: string | null; modelConfigVersion: number | null; inputTokens: number; outputTokens: number; costMicrousd: number; durationMs: number | null; cacheReadTokens: number | null; createdAt: string; }; export function UsageResource() { const columns: TableColumnsType = [ { title: "请求", render: (_, item) => ( {item.requestId} {item.email ?? item.userId} ), }, { title: "功能", dataIndex: "featureKey" }, { title: "资金来源", dataIndex: "source", render: (value) => value, }, { title: "模型", render: (_, item) => ( {item.actualModelId ?? "—"} 请求 {item.requestedModelId ?? "—"} · v {item.modelConfigVersion ?? "—"} ), }, { title: "Token", render: (_, item) => `${item.inputTokens.toLocaleString()} / ${item.outputTokens.toLocaleString()}`, }, { title: "缓存读 tokens", dataIndex: "cacheReadTokens", render: (value: number | null) => value == null ? "—" : value.toLocaleString(), }, { title: "成本", dataIndex: "costMicrousd", render: (value: number) => `$${(value / 1_000_000).toFixed(6)}`, }, { title: "耗时", dataIndex: "durationMs", render: (value) => (value == null ? "—" : `${value} ms`), }, { title: "时间", dataIndex: "createdAt", render: formatAdminDate }, ]; return ( resource="usage" title="用量、Token 与成本" columns={columns} statusOptions={[ "subscription", "credits", "complimentary", "chat.standard", "rectification", ].map((value) => ({ value, label: value }))} /> ); } type ModelRelease = { id: string; modelId: string; fromVersion: number | null; toVersion: number; action: string; actorEmail: string | null; reason: string; requestId: string; createdAt: string; }; export function ModelReleasesResource() { const columns: TableColumnsType = [ { title: "模型", dataIndex: "modelId" }, { title: "版本", render: (_, item) => `${item.fromVersion ?? "—"} → ${item.toVersion}`, }, { title: "动作", dataIndex: "action", render: (value) => value, }, { title: "管理员", dataIndex: "actorEmail", render: (value) => value ?? "—", }, { title: "原因", dataIndex: "reason" }, { title: "请求 ID", dataIndex: "requestId", render: (value) => {value}, }, { title: "时间", dataIndex: "createdAt", render: formatAdminDate }, ]; return ( resource="model-releases" title="模型发布与回滚历史" columns={columns} statusOptions={["publish", "rollback"].map((value) => ({ value, label: value, }))} /> ); }