feat: 更新钱包日志和资金模式相关的国际化文本,增强用户体验
Some checks failed
lotteryfront CI / build (push) Has been cancelled
Some checks failed
lotteryfront CI / build (push) Has been cancelled
This commit is contained in:
@@ -24,7 +24,8 @@ export const WALLET_FLOW_FILTERS: { value: string; labelKey: string }[] = [
|
||||
export const CREDIT_FLOW_FILTERS: { value: string; labelKey: string }[] = [
|
||||
{ value: "", labelKey: "wallet.creditFlow.all" },
|
||||
{ value: "bet", labelKey: "wallet.creditFlow.bet" },
|
||||
{ value: "credit_release", labelKey: "wallet.creditFlow.credit_release" },
|
||||
{ value: "game_settlement", labelKey: "wallet.creditFlow.game_settlement" },
|
||||
{ value: "rebate", labelKey: "wallet.creditFlow.rebate" },
|
||||
{ value: "bill_settlement", labelKey: "wallet.creditFlow.bill_settlement" },
|
||||
];
|
||||
|
||||
@@ -37,7 +38,9 @@ const FLOW_LABEL_FALLBACKS: Record<string, string> = {
|
||||
"wallet.flow.refund": "退款",
|
||||
"wallet.flow.reversal": "冲正",
|
||||
"wallet.creditFlow.all": "全部",
|
||||
"wallet.creditFlow.bet": "占用额度",
|
||||
"wallet.creditFlow.bet": "下注冻结",
|
||||
"wallet.creditFlow.game_settlement": "开奖结算",
|
||||
"wallet.creditFlow.rebate": "账期回水",
|
||||
"wallet.creditFlow.credit_release": "释额",
|
||||
"wallet.creditFlow.bill_settlement": "账期收付",
|
||||
"wallet.creditFlow.win_credit": "中奖释额",
|
||||
@@ -59,7 +62,14 @@ function txnStatusLabel(
|
||||
status: string,
|
||||
t: (key: string, options?: { defaultValue?: string }) => string,
|
||||
): string {
|
||||
return t(`wallet.txnStatus.${status}`, { defaultValue: status });
|
||||
const fallback: Record<string, string> = {
|
||||
accrued: "已计提",
|
||||
in_bill: "已入账单",
|
||||
settled: "已结清",
|
||||
reversed: "已冲正",
|
||||
};
|
||||
|
||||
return t(`wallet.txnStatus.${status}`, { defaultValue: fallback[status] ?? status });
|
||||
}
|
||||
|
||||
type WalletLogsBlockProps = {
|
||||
@@ -125,6 +135,7 @@ export function WalletLogsBlock({
|
||||
? "h-8 rounded-full bg-[#07459f] px-3 text-xs font-bold text-white hover:bg-[#063b88]"
|
||||
: "h-8 rounded-full border-[#dce7f7] bg-white px-3 text-xs font-bold text-[#32518d] hover:bg-[#f8fbff]"
|
||||
}
|
||||
disabled={logsLoading && filter === f.value}
|
||||
onClick={() => onFilterChange(f.value)}
|
||||
>
|
||||
{f.label}
|
||||
@@ -142,7 +153,7 @@ export function WalletLogsBlock({
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("wallet.totalRecords", { total: logs.total })}
|
||||
</p>
|
||||
<ul className="space-y-2">
|
||||
<ul className={logsLoading ? "space-y-2 opacity-60" : "space-y-2"}>
|
||||
{logs.items.length === 0 ? (
|
||||
<li className="rounded-lg border border-dashed py-8 text-center text-sm text-muted-foreground">
|
||||
{t(creditMode ? "wallet.emptyCreditLogs" : "wallet.emptyLogs", {
|
||||
|
||||
@@ -24,14 +24,31 @@ import { formatWalletClientError } from "@/lib/wallet-api-error";
|
||||
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
||||
import type { WalletBalanceData } from "@/types/api/wallet-balance";
|
||||
import { getWalletLogsLastPage, type WalletLogsData } from "@/types/api/wallet-logs";
|
||||
import type { PlayerMeData } from "@/types/api/player-me";
|
||||
|
||||
const WALLET_LOGS_PAGE_SIZE = 10;
|
||||
type FundingModeView = "credit" | "wallet" | "unknown";
|
||||
|
||||
function scrollToWalletSection(id: string): void {
|
||||
if (typeof document === "undefined") return;
|
||||
document.getElementById(id)?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
|
||||
function resolveFundingModeView(
|
||||
balance: WalletBalanceData | null,
|
||||
profile: PlayerMeData | null,
|
||||
): FundingModeView {
|
||||
if (isCreditFundingPlayer(balance) || isCreditFundingPlayer(profile)) {
|
||||
return "credit";
|
||||
}
|
||||
|
||||
if (balance?.funding_mode === "wallet" || profile?.funding_mode === "wallet") {
|
||||
return "wallet";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function WalletScreen() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -54,7 +71,9 @@ export function WalletScreen() {
|
||||
const sectionDeepLinkHandledRef = useRef(false);
|
||||
|
||||
const profile = usePlayerSessionStore((s) => s.profile);
|
||||
const isCreditPlayer = isCreditFundingPlayer(balance) || isCreditFundingPlayer(profile);
|
||||
const fundingModeView = resolveFundingModeView(balance, profile);
|
||||
const fundingModeKnown = fundingModeView !== "unknown";
|
||||
const isCreditPlayer = fundingModeView === "credit";
|
||||
|
||||
useEffect(() => {
|
||||
if (actionDeepLinkHandledRef.current || loading) return;
|
||||
@@ -181,6 +200,16 @@ export function WalletScreen() {
|
||||
};
|
||||
}, [currency, filter, t]);
|
||||
|
||||
const handleFilterChange = useCallback((value: string) => {
|
||||
if (value === filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLogs(null);
|
||||
setLogsLoading(true);
|
||||
setFilter(value);
|
||||
}, [filter]);
|
||||
|
||||
const refreshAll = useCallback(async () => {
|
||||
setError(null);
|
||||
setLogsLoading(true);
|
||||
@@ -210,6 +239,11 @@ export function WalletScreen() {
|
||||
const displayMinor = isCreditPlayer
|
||||
? Number(balance?.available_balance ?? 0)
|
||||
: Number(balance?.balance ?? 0);
|
||||
const panelTitle = !fundingModeKnown
|
||||
? t("wallet.loadingTitle", { defaultValue: "账户资金" })
|
||||
: isCreditPlayer
|
||||
? t("wallet.creditTitle", { defaultValue: "信用" })
|
||||
: t("wallet.title");
|
||||
|
||||
const loadMore = useCallback(() => {
|
||||
if (!logs || !hasMore || loadingMore) return;
|
||||
@@ -243,9 +277,7 @@ export function WalletScreen() {
|
||||
}, [hasMore, loadMore, loading, loadingMore, logsLoading]);
|
||||
|
||||
return (
|
||||
<PlayerPanel
|
||||
title={isCreditPlayer ? t("wallet.creditTitle", { defaultValue: "信用" }) : t("wallet.title")}
|
||||
>
|
||||
<PlayerPanel title={panelTitle}>
|
||||
<div className="space-y-3">
|
||||
{error ? (
|
||||
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700">
|
||||
@@ -274,11 +306,13 @@ export function WalletScreen() {
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm font-semibold text-white/90">
|
||||
{isCreditPlayer
|
||||
{fundingModeKnown && isCreditPlayer
|
||||
? t("wallet.creditAvailable", { defaultValue: "可用信用" })
|
||||
: t("wallet.balance")}
|
||||
: fundingModeKnown
|
||||
? t("wallet.balance")
|
||||
: t("wallet.loadingBalance", { defaultValue: "正在加载" })}
|
||||
</p>
|
||||
{loading ? (
|
||||
{loading || !fundingModeKnown ? (
|
||||
<Skeleton className="mt-2 h-8 w-44 rounded-md bg-white/25" />
|
||||
) : (
|
||||
<PlayerMoneyDisplay
|
||||
@@ -288,21 +322,23 @@ export function WalletScreen() {
|
||||
/>
|
||||
)}
|
||||
<p className="mt-2 text-xs text-white/75">
|
||||
{isCreditPlayer
|
||||
? t("wallet.creditSummary", {
|
||||
defaultValue: "授信 {{limit}} · 已用 {{used}}",
|
||||
limit: formatMinorAsCurrency(balance?.credit_limit ?? 0, currency),
|
||||
used: formatMinorAsCurrency(balance?.used_credit ?? 0, currency),
|
||||
})
|
||||
: t("wallet.available", {
|
||||
amount: formatMinorAsCurrency(balance?.available_balance ?? 0, currency),
|
||||
})}
|
||||
{!fundingModeKnown
|
||||
? t("wallet.loadingAccountMode", { defaultValue: "正在确认资金模式…" })
|
||||
: isCreditPlayer
|
||||
? t("wallet.creditSummary", {
|
||||
defaultValue: "授信 {{limit}} · 已用 {{used}}",
|
||||
limit: formatMinorAsCurrency(balance?.credit_limit ?? 0, currency),
|
||||
used: formatMinorAsCurrency(balance?.used_credit ?? 0, currency),
|
||||
})
|
||||
: t("wallet.available", {
|
||||
amount: formatMinorAsCurrency(balance?.available_balance ?? 0, currency),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{!isCreditPlayer ? (
|
||||
{fundingModeKnown && !isCreditPlayer ? (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<TransferInDialog
|
||||
idPrefix="wallet-"
|
||||
@@ -334,7 +370,7 @@ export function WalletScreen() {
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{!isCreditPlayer && (logs?.pending_reconcile?.length ?? 0) > 0 ? (
|
||||
{fundingModeKnown && !isCreditPlayer && (logs?.pending_reconcile?.length ?? 0) > 0 ? (
|
||||
<section
|
||||
id="wallet-pending"
|
||||
className="scroll-mt-3 rounded-2xl border border-amber-200 bg-amber-50 px-3 py-3 text-sm text-amber-900"
|
||||
@@ -371,18 +407,22 @@ export function WalletScreen() {
|
||||
) : null}
|
||||
|
||||
<div id="wallet-logs" className="scroll-mt-3">
|
||||
<WalletLogsBlock
|
||||
creditMode={isCreditPlayer}
|
||||
logs={logs}
|
||||
logsLoading={loading || logsLoading}
|
||||
loadingMore={loadingMore}
|
||||
hasMore={hasMore}
|
||||
onLoadMore={loadMore}
|
||||
loadMoreRef={loadMoreRef}
|
||||
filter={filter}
|
||||
onFilterChange={setFilter}
|
||||
currency={currency}
|
||||
/>
|
||||
{fundingModeKnown ? (
|
||||
<WalletLogsBlock
|
||||
creditMode={isCreditPlayer}
|
||||
logs={logs}
|
||||
logsLoading={loading || logsLoading}
|
||||
loadingMore={loadingMore}
|
||||
hasMore={hasMore}
|
||||
onLoadMore={loadMore}
|
||||
loadMoreRef={loadMoreRef}
|
||||
filter={filter}
|
||||
onFilterChange={handleFilterChange}
|
||||
currency={currency}
|
||||
/>
|
||||
) : (
|
||||
<Skeleton className="h-40 w-full rounded-lg" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PlayerPanel>
|
||||
|
||||
@@ -428,7 +428,7 @@
|
||||
"flowsTitle": "Wallet logs",
|
||||
"creditFlowsTitle": "Credit activity",
|
||||
"playerChannel": {
|
||||
"credit": "Credit line: credit holds, releases, and billing payments (not wallet payouts)",
|
||||
"credit": "Credit line: bet holds, draw settlement, and period payments (not wallet payouts)",
|
||||
"wallet": "Main-site wallet player (transfers & wallet ledger)"
|
||||
},
|
||||
"creditAvailableAfter": "Available credit after",
|
||||
@@ -458,7 +458,9 @@
|
||||
},
|
||||
"creditFlow": {
|
||||
"all": "All",
|
||||
"bet": "Credit hold",
|
||||
"bet": "Bet hold",
|
||||
"game_settlement": "Draw settlement",
|
||||
"rebate": "Period rebate",
|
||||
"credit_release": "Credit release",
|
||||
"bill_settlement": "Period payment",
|
||||
"win_credit": "Win release",
|
||||
@@ -467,6 +469,9 @@
|
||||
},
|
||||
"txnStatus": {
|
||||
"posted": "Success",
|
||||
"accrued": "Accrued",
|
||||
"in_bill": "In bill",
|
||||
"settled": "Settled",
|
||||
"pending_reconcile": "Pending reconciliation",
|
||||
"reversed": "Reversed",
|
||||
"manually_processed": "Case closed"
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
"creditLogsTitle": "क्रेडिट लेनदेन",
|
||||
"creditLogsSubtitle": "ओगट, मुक्ति र बिलिङ भुक्तानी",
|
||||
"playerChannel": {
|
||||
"credit": "क्रेडिट लाइन: ओगट, मुक्ति र बिलिङ भुक्तानी (वालेट भुक्तानी होइन)",
|
||||
"credit": "क्रेडिट लाइन: बेट होल्ड, ड्र सेटलमेन्ट र अवधि भुक्तानी (वालेट भुक्तानी होइन)",
|
||||
"wallet": "मुख्य साइट वालेट खेलाडी"
|
||||
},
|
||||
"creditAvailableAfter": "पछि उपलब्ध क्रेडिट",
|
||||
@@ -435,7 +435,9 @@
|
||||
"emptyCreditLogs": "क्रेडिट लेनदेन छैन",
|
||||
"creditFlow": {
|
||||
"all": "सबै",
|
||||
"bet": "क्रेडिट ओगट",
|
||||
"bet": "बेट होल्ड",
|
||||
"game_settlement": "ड्र सेटलमेन्ट",
|
||||
"rebate": "अवधि रिबेट",
|
||||
"credit_release": "मुक्ति",
|
||||
"bill_settlement": "अवधि भुक्तानी",
|
||||
"win_credit": "जित मुक्ति",
|
||||
@@ -466,6 +468,9 @@
|
||||
},
|
||||
"txnStatus": {
|
||||
"posted": "सफल",
|
||||
"accrued": "जम्मा भयो",
|
||||
"in_bill": "बिलमा",
|
||||
"settled": "सेटल भयो",
|
||||
"pending_reconcile": "मिलान बाँकी",
|
||||
"reversed": "रिभर्स भयो",
|
||||
"manually_processed": "केस बन्द भयो"
|
||||
|
||||
@@ -427,7 +427,7 @@
|
||||
"flowsTitle": "资金流水",
|
||||
"creditFlowsTitle": "信用流水",
|
||||
"playerChannel": {
|
||||
"credit": "信用盘:展示额度占用、释额与账期收付(非钱包派彩)",
|
||||
"credit": "信用盘:展示下注冻结、开奖结算与账期收付(非钱包派彩)",
|
||||
"wallet": "主站钱包玩家(划转与钱包余额流水)"
|
||||
},
|
||||
"creditAvailableAfter": "变更后可用信用",
|
||||
@@ -457,7 +457,9 @@
|
||||
},
|
||||
"creditFlow": {
|
||||
"all": "全部",
|
||||
"bet": "占用额度",
|
||||
"bet": "下注冻结",
|
||||
"game_settlement": "开奖结算",
|
||||
"rebate": "账期回水",
|
||||
"credit_release": "释额",
|
||||
"bill_settlement": "账期收付",
|
||||
"win_credit": "中奖释额",
|
||||
@@ -466,6 +468,9 @@
|
||||
},
|
||||
"txnStatus": {
|
||||
"posted": "成功",
|
||||
"accrued": "已计提",
|
||||
"in_bill": "已入账单",
|
||||
"settled": "已结清",
|
||||
"pending_reconcile": "待对账",
|
||||
"reversed": "已冲正",
|
||||
"manually_processed": "已结案"
|
||||
|
||||
@@ -3,7 +3,7 @@ export type WalletLogItem = {
|
||||
log_id: string;
|
||||
type: string;
|
||||
biz_type: string;
|
||||
/** wallet_txn | credit_ledger */
|
||||
/** wallet_txn | credit_ledger | rebate_record */
|
||||
ledger_source?: string;
|
||||
funding_mode?: string;
|
||||
auth_source?: string | null;
|
||||
@@ -13,7 +13,7 @@ export type WalletLogItem = {
|
||||
direction: "in" | "out";
|
||||
currency_code: string;
|
||||
balance_after: number | null;
|
||||
/** 信用盘:false 表示账期收付记账,不改变可用信用 */
|
||||
/** 信用盘:false 表示账期收付/账期回水展示记录,不改变可用信用 */
|
||||
affects_available_credit?: boolean;
|
||||
ref_id: string | null;
|
||||
idempotent_key: string | null;
|
||||
@@ -57,7 +57,7 @@ export type GetWalletLogsParams = {
|
||||
page?: number;
|
||||
/** 每页条数(PRD 示例 `size`) */
|
||||
size?: number;
|
||||
/** 逗号分隔:transfer_in,transfer_out,bet,prize,refund,reversal */
|
||||
/** 逗号分隔:transfer_in,transfer_out,bet,prize,refund,reversal,game_settlement,bill_settlement,rebate */
|
||||
type?: string;
|
||||
/** 按钱包币种筛选 */
|
||||
currency?: string;
|
||||
|
||||
Reference in New Issue
Block a user