import { useMemo, useState } from "react"; import { listRechargeBills } from "@/features/payment/api"; import { AdminListBody, AdminListPage, } from "@/shared/ui/AdminListLayout.jsx"; import { DataState } from "@/shared/ui/DataState.jsx"; import { DataTable } from "@/shared/ui/DataTable.jsx"; import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js"; import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js"; import { formatMillis } from "@/shared/utils/time.js"; const pageSize = 20; const statusOptions = [ ["", "全部状态"], ["succeeded", "成功"], ]; const rechargeTypeOptions = [ ["", "全部途径"], ["coin_seller_transfer", "币商充值"], ]; const columns = [ { key: "bill", label: "账单", width: "minmax(240px, 1.4fr)", render: (bill) => , }, { key: "userId", label: "用户 ID", width: "minmax(120px, 0.65fr)", render: (bill) => bill.userId || "-", }, { key: "sellerUserId", label: "币商 ID", width: "minmax(120px, 0.65fr)", render: (bill) => bill.sellerUserId || "-", }, { key: "amount", label: "金币 / 金额", width: "minmax(150px, 0.75fr)", render: (bill) => ( ), }, { key: "policy", label: "兑换口径", width: "minmax(170px, 0.9fr)", render: (bill) => ( ), }, { key: "region", label: "区域", width: "minmax(110px, 0.55fr)", render: (bill) => ( ), }, { key: "rechargeType", label: "充值途径", width: "minmax(130px, 0.7fr)", render: (bill) => rechargeTypeLabel(bill.rechargeType), }, { key: "status", label: "状态", width: "minmax(100px, 0.55fr)", render: (bill) => , }, { key: "time", label: "创建时间", width: "minmax(160px, 0.8fr)", render: (bill) => formatMillis(bill.createdAtMs), }, ]; export function PaymentBillListPage() { const [page, setPage] = useState(1); const [keyword, setKeyword] = useState(""); const [status, setStatus] = useState(""); const [rechargeType, setRechargeType] = useState(""); const [userId, setUserId] = useState(""); const [sellerUserId, setSellerUserId] = useState(""); const filters = useMemo( () => ({ keyword, recharge_type: rechargeType, seller_user_id: sellerUserId, status, user_id: userId, }), [keyword, rechargeType, sellerUserId, status, userId], ); const query = usePaginatedQuery({ errorMessage: "获取账单列表失败", fetcher: listRechargeBills, filters, page, pageSize, queryKey: ["payment-bills", filters, page], }); const data = query.data || { items: [], total: 0, page, pageSize }; const items = data.items || []; const total = data.total || 0; const resetPage = (setter) => (value) => { setter(value); setPage(1); }; const tableColumns = columns.map((column) => { if (column.key === "bill") { return { ...column, filter: createTextColumnFilter({ placeholder: "搜索账单号、命令号、外部单号", value: keyword, onChange: resetPage(setKeyword), }), }; } if (column.key === "userId") { return { ...column, filter: createTextColumnFilter({ placeholder: "搜索用户 ID", value: userId, onChange: (value) => resetPage(setUserId)(digitsOnly(value)), }), }; } if (column.key === "sellerUserId") { return { ...column, filter: createTextColumnFilter({ placeholder: "搜索币商 ID", value: sellerUserId, onChange: (value) => resetPage(setSellerUserId)(digitsOnly(value)), }), }; } if (column.key === "rechargeType") { return { ...column, filter: createOptionsColumnFilter({ options: rechargeTypeOptions, placeholder: "搜索充值途径", value: rechargeType, onChange: resetPage(setRechargeType), }), }; } if (column.key === "status") { return { ...column, filter: createOptionsColumnFilter({ options: statusOptions, placeholder: "搜索状态", value: status, onChange: resetPage(setStatus), }), }; } return column; }); return ( 0 ? { page, pageSize: data.pageSize || pageSize, total, onPageChange: setPage, } : undefined } rowKey={(bill) => bill.transactionId} /> ); } function Stack({ primary, secondary }) { return (
{primary || "-"} {secondary || "-"}
); } function StatusBadge({ status }) { const tone = status === "succeeded" ? "succeeded" : status === "failed" ? "danger" : "stopped"; return ( {statusLabel(status)} ); } function rechargeTypeLabel(value) { return rechargeTypeOptions.find(([optionValue]) => optionValue === value)?.[1] || value || "-"; } function statusLabel(value) { if (value === "succeeded") { return "成功"; } if (value === "failed") { return "失败"; } return value || "-"; } function formatNumber(value) { if (value === 0 || value) { return Number(value).toLocaleString("zh-CN"); } return "-"; } function formatMoney(value, currency = "USD") { if (!(value === 0 || value)) { return "-"; } return `${currency || "USD"} ${(Number(value) / 100).toLocaleString("zh-CN", { maximumFractionDigits: 2, minimumFractionDigits: 2, })}`; } function digitsOnly(value) { return value.replace(/\D/g, ""); }