feat: 更新钱包日志和资金模式相关的国际化文本,增强用户体验
Some checks failed
lotteryfront CI / build (push) Has been cancelled

This commit is contained in:
2026-06-30 17:55:06 +08:00
parent ce1aca8905
commit efb1bcdda8
6 changed files with 109 additions and 43 deletions

View File

@@ -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", {

View File

@@ -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>

View File

@@ -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"

View File

@@ -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": "केस बन्द भयो"

View File

@@ -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": "已结案"

View File

@@ -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;