Files
lotteryAdmin/src/modules/settlement/settlement-credit-ledger-table.tsx
kang 65eaeecf8c feat(agents, i18n): enhance agent management and settlement features with new translations and UI updates
Added new translations for agent management and settlement features in English, Nepali, and Chinese, improving multi-language support. Updated the agents console to reflect changes in funding modes and player details, enhancing user experience. Refactored the admin permission gate to include new logic for handling bound line agents, ensuring better permission management. Additionally, streamlined the UI for agent-related pages and improved navigation to the settlement center, consolidating related functionalities for better accessibility.
2026-06-04 18:01:05 +08:00

173 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useTranslation } from "react-i18next";
import type { SettlementLedgerRow } from "@/api/admin-agent-settlement";
import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { AdminLoadingState } from "@/components/admin/admin-loading-state";
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
import { PlayerLedgerSourceBadge } from "@/components/admin/player-funding-badges";
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
import { formatDashboardMoneyMinor } from "@/modules/dashboard/use-dashboard-analytics";
import { SettlementLedgerRowActions } from "@/modules/settlement/settlement-ledger-row-actions";
import {
creditLedgerReasonLabel,
settlementAdjustmentTypeLabel,
settlementBillStatusLabel,
} from "@/modules/settlement/settlement-status-label";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
type SettlementCreditLedgerTableProps = {
rows: SettlementLedgerRow[];
loading: boolean;
currencyCode: string;
canManage: boolean;
onOpenBill: (billId: number) => void;
onRefresh: () => void;
showStatusColumn?: boolean;
};
function ledgerBizLabel(
row: SettlementLedgerRow,
t: ReturnType<typeof useTranslation<["settlementCenter", "agents"]>>["t"],
): string {
if (row.entry_kind === "payment") {
return t("creditLedger.reason.payment_record", { defaultValue: "账单收付" });
}
if (row.entry_kind === "adjustment") {
return settlementAdjustmentTypeLabel(row.biz_type, t);
}
return creditLedgerReasonLabel(row.biz_type, t);
}
function ledgerSourceForBadge(row: SettlementLedgerRow): string | null {
if (row.entry_kind === "credit") {
return "credit_ledger";
}
if (row.entry_kind === "payment") {
return "wallet_txn";
}
return null;
}
export function SettlementCreditLedgerTable({
rows,
loading,
currencyCode,
canManage,
onOpenBill,
onRefresh,
showStatusColumn = false,
}: SettlementCreditLedgerTableProps): React.ReactElement {
const { t } = useTranslation(["settlementCenter", "agents", "common"]);
const formatDt = useAdminDateTimeFormatter();
if (loading) {
return <AdminLoadingState />;
}
if (rows.length === 0) {
return <AdminNoResourceState />;
}
return (
<div className="admin-table-shell overflow-x-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead>{t("creditLedger.columns.txn", { defaultValue: "流水号" })}</TableHead>
<TableHead>{t("creditLedger.columns.player", { defaultValue: "玩家" })}</TableHead>
<TableHead>{t("creditLedger.columns.reason", { defaultValue: "业务类型" })}</TableHead>
<TableHead>{t("creditLedger.columns.ref", { defaultValue: "关联" })}</TableHead>
<TableHead className="text-right">
{t("creditLedger.columns.amount", { defaultValue: "金额" })}
</TableHead>
<TableHead>{t("creditLedger.columns.channel", { defaultValue: "渠道" })}</TableHead>
{showStatusColumn ? (
<TableHead>{t("creditLedger.columns.status", { defaultValue: "状态" })}</TableHead>
) : null}
<TableHead>{t("creditLedger.columns.time", { defaultValue: "时间" })}</TableHead>
<TableHead className="sticky right-0 z-10 w-14 bg-muted text-center shadow-[-1px_0_0_rgba(203,213,225,0.7)]">
{t("common:table.actions", { defaultValue: "操作" })}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rows.map((row) => {
const signed = row.signed_amount ?? (row.direction === 1 ? row.amount : -row.amount);
const playerLabel =
row.username?.trim() ||
row.nickname?.trim() ||
row.site_player_id?.trim() ||
`#${row.player_id}`;
const badgeSource = ledgerSourceForBadge(row);
return (
<TableRow key={row.row_key ?? `${row.entry_kind}-${row.id}`}>
<TableCell className="font-mono text-xs">{row.txn_no}</TableCell>
<TableCell>
<span className="font-medium">{playerLabel}</span>
<span className="ml-1 text-xs text-muted-foreground">#{row.player_id}</span>
</TableCell>
<TableCell>{ledgerBizLabel(row, t)}</TableCell>
<TableCell className="text-xs text-muted-foreground">
{row.biz_no ?? (row.settlement_bill_id ? `bill#${row.settlement_bill_id}` : "—")}
</TableCell>
<TableCell
className={`text-right tabular-nums font-medium ${signed < 0 ? "text-destructive" : "text-emerald-700"}`}
>
{signed < 0 ? "" : "+"}
{formatDashboardMoneyMinor(Math.abs(signed), row.currency_code || currencyCode)}
</TableCell>
<TableCell className="text-xs text-muted-foreground">
{badgeSource ? (
<PlayerLedgerSourceBadge ledgerSource={badgeSource} />
) : (
t("creditLedger.entryKind.adjustment", { defaultValue: "调账流水" })
)}
</TableCell>
{showStatusColumn ? (
<TableCell>
{row.bill_status ? (
<AdminStatusBadge status={row.bill_status}>
{settlementBillStatusLabel(row.bill_status, t)}
</AdminStatusBadge>
) : (
<AdminStatusBadge status="posted">
{t("ledgerPanel.rowPosted", { defaultValue: "已记账" })}
</AdminStatusBadge>
)}
</TableCell>
) : null}
<TableCell className="text-xs text-muted-foreground whitespace-nowrap">
{row.created_at ? formatDt(row.created_at) : "—"}
</TableCell>
<TableCell
className="sticky right-0 z-10 bg-card text-center shadow-[-1px_0_0_rgba(203,213,225,0.7)]"
onClick={(e) => e.stopPropagation()}
>
<SettlementLedgerRowActions
row={row}
canManage={canManage}
onOpenBill={onOpenBill}
onRefresh={onRefresh}
/>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
);
}