feat: 添加货币管理功能,更新国际化支持,移除报表相关代码
This commit is contained in:
@@ -36,7 +36,9 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { useAdminCurrencyCatalog } from "@/hooks/use-admin-currency-catalog";
|
||||
import { useAdminDateTimeFormatter } from "@/hooks/use-admin-datetime-formatter";
|
||||
import { formatAdminMinorUnits } from "@/lib/money";
|
||||
import { LotteryApiBizError } from "@/types/api/errors";
|
||||
import type {
|
||||
AdminPlayerWalletsData,
|
||||
@@ -44,11 +46,6 @@ import type {
|
||||
AdminWalletTxnListData,
|
||||
} from "@/types/api/admin-wallet";
|
||||
|
||||
function formatMinorUnits(minor: number, currencyCode: string): string {
|
||||
const major = minor / 100;
|
||||
return `${major.toFixed(2)} ${currencyCode}`;
|
||||
}
|
||||
|
||||
/** 长单号/流水号:单行截断;点击复制全文,悬停可看全文 */
|
||||
function CellMonoId({
|
||||
value,
|
||||
@@ -227,12 +224,13 @@ function canManuallyProcessTransferOrder(row: {
|
||||
|
||||
export function TransferOrdersPanel(): React.ReactElement {
|
||||
const { t } = useTranslation(["wallet", "common"]);
|
||||
useAdminCurrencyCatalog();
|
||||
const formatTs = useAdminDateTimeFormatter();
|
||||
const [data, setData] = useState<AdminTransferOrderListData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(20);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [draft, setDraft] = useState<TransferFilters>(emptyTransferFilters);
|
||||
const [applied, setApplied] = useState<TransferFilters>(emptyTransferFilters);
|
||||
const [actionLoading, setActionLoading] = useState<Set<string>>(new Set());
|
||||
@@ -475,7 +473,7 @@ export function TransferOrdersPanel(): React.ReactElement {
|
||||
</TableCell>
|
||||
<TableCell>{row.direction}</TableCell>
|
||||
<TableCell className="tabular-nums">
|
||||
{formatMinorUnits(row.amount, row.currency_code)}
|
||||
{formatAdminMinorUnits(row.amount, row.currency_code)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant={statusBadgeVariant(row.status)}>{statusLabelT(row.status, t)}</Badge>
|
||||
@@ -552,7 +550,7 @@ export function WalletTxnsPanel(): React.ReactElement {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(20);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [draft, setDraft] = useState<TxnFilters>(emptyTxnFilters);
|
||||
const [applied, setApplied] = useState<TxnFilters>(emptyTxnFilters);
|
||||
|
||||
@@ -836,6 +834,7 @@ export function WalletTxnsPanel(): React.ReactElement {
|
||||
|
||||
export function PlayerWalletPanel(): React.ReactElement {
|
||||
const { t } = useTranslation(["wallet", "common"]);
|
||||
useAdminCurrencyCatalog();
|
||||
const [playerId, setPlayerId] = useState("");
|
||||
const [result, setResult] = useState<AdminPlayerWalletsData | null>(null);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
@@ -918,7 +917,7 @@ export function PlayerWalletPanel(): React.ReactElement {
|
||||
<TableCell>{w.currency_code}</TableCell>
|
||||
<TableCell className="font-mono tabular-nums">{w.balance}</TableCell>
|
||||
<TableCell className="tabular-nums">
|
||||
{formatMinorUnits(w.available_balance, w.currency_code)}
|
||||
{formatAdminMinorUnits(w.available_balance, w.currency_code)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
|
||||
@@ -4,8 +4,8 @@ import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { adminHasAnyPermission } from "@/lib/admin-permissions";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useAdminProfile } from "@/stores/admin-session";
|
||||
|
||||
const RECONCILE_PERMS = [
|
||||
@@ -28,27 +28,38 @@ export function WalletSubnav(): React.ReactElement {
|
||||
return (
|
||||
<nav
|
||||
aria-label={t("subnavLabel")}
|
||||
className="mb-6 flex flex-wrap gap-2 border-b border-border pb-3"
|
||||
className="flex w-full flex-wrap items-end gap-1 border-b border-border/60 px-1"
|
||||
>
|
||||
{tabs.map((tab) => {
|
||||
const allowed = adminHasAnyPermission(perms, [...tab.requiredAny]);
|
||||
const active = pathname === tab.href || pathname.startsWith(`${tab.href}/`);
|
||||
const className = cn(
|
||||
"rounded-lg px-3 py-1.5 text-sm font-medium transition-colors",
|
||||
active
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "bg-muted/60 text-foreground hover:bg-muted",
|
||||
!allowed && "cursor-not-allowed opacity-45",
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return (
|
||||
<span key={tab.href} className={className} title={t("noPermission")}>
|
||||
<span
|
||||
key={tab.href}
|
||||
className={cn(
|
||||
"border-b-2 border-transparent px-4 py-3 text-sm font-medium text-muted-foreground/45",
|
||||
"cursor-not-allowed",
|
||||
)}
|
||||
title={t("noPermission")}
|
||||
>
|
||||
{t(tab.label)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link key={tab.href} href={tab.href} className={className}>
|
||||
<Link
|
||||
key={tab.href}
|
||||
href={tab.href}
|
||||
className={cn(
|
||||
"border-b-2 px-4 py-3 text-sm font-medium transition-colors",
|
||||
active
|
||||
? "border-primary text-primary"
|
||||
: "border-transparent text-muted-foreground hover:border-border/80 hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
{t(tab.label)}
|
||||
</Link>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user