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 }[] = [ export const CREDIT_FLOW_FILTERS: { value: string; labelKey: string }[] = [
{ value: "", labelKey: "wallet.creditFlow.all" }, { value: "", labelKey: "wallet.creditFlow.all" },
{ value: "bet", labelKey: "wallet.creditFlow.bet" }, { 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" }, { value: "bill_settlement", labelKey: "wallet.creditFlow.bill_settlement" },
]; ];
@@ -37,7 +38,9 @@ const FLOW_LABEL_FALLBACKS: Record<string, string> = {
"wallet.flow.refund": "退款", "wallet.flow.refund": "退款",
"wallet.flow.reversal": "冲正", "wallet.flow.reversal": "冲正",
"wallet.creditFlow.all": "全部", "wallet.creditFlow.all": "全部",
"wallet.creditFlow.bet": "占用额度", "wallet.creditFlow.bet": "下注冻结",
"wallet.creditFlow.game_settlement": "开奖结算",
"wallet.creditFlow.rebate": "账期回水",
"wallet.creditFlow.credit_release": "释额", "wallet.creditFlow.credit_release": "释额",
"wallet.creditFlow.bill_settlement": "账期收付", "wallet.creditFlow.bill_settlement": "账期收付",
"wallet.creditFlow.win_credit": "中奖释额", "wallet.creditFlow.win_credit": "中奖释额",
@@ -59,7 +62,14 @@ function txnStatusLabel(
status: string, status: string,
t: (key: string, options?: { defaultValue?: string }) => string, t: (key: string, options?: { defaultValue?: string }) => 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 = { 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 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]" : "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)} onClick={() => onFilterChange(f.value)}
> >
{f.label} {f.label}
@@ -142,7 +153,7 @@ export function WalletLogsBlock({
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{t("wallet.totalRecords", { total: logs.total })} {t("wallet.totalRecords", { total: logs.total })}
</p> </p>
<ul className="space-y-2"> <ul className={logsLoading ? "space-y-2 opacity-60" : "space-y-2"}>
{logs.items.length === 0 ? ( {logs.items.length === 0 ? (
<li className="rounded-lg border border-dashed py-8 text-center text-sm text-muted-foreground"> <li className="rounded-lg border border-dashed py-8 text-center text-sm text-muted-foreground">
{t(creditMode ? "wallet.emptyCreditLogs" : "wallet.emptyLogs", { {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 { usePlayerSessionStore } from "@/stores/player-session-store";
import type { WalletBalanceData } from "@/types/api/wallet-balance"; import type { WalletBalanceData } from "@/types/api/wallet-balance";
import { getWalletLogsLastPage, type WalletLogsData } from "@/types/api/wallet-logs"; import { getWalletLogsLastPage, type WalletLogsData } from "@/types/api/wallet-logs";
import type { PlayerMeData } from "@/types/api/player-me";
const WALLET_LOGS_PAGE_SIZE = 10; const WALLET_LOGS_PAGE_SIZE = 10;
type FundingModeView = "credit" | "wallet" | "unknown";
function scrollToWalletSection(id: string): void { function scrollToWalletSection(id: string): void {
if (typeof document === "undefined") return; if (typeof document === "undefined") return;
document.getElementById(id)?.scrollIntoView({ behavior: "smooth", block: "start" }); 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() { export function WalletScreen() {
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
@@ -54,7 +71,9 @@ export function WalletScreen() {
const sectionDeepLinkHandledRef = useRef(false); const sectionDeepLinkHandledRef = useRef(false);
const profile = usePlayerSessionStore((s) => s.profile); 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(() => { useEffect(() => {
if (actionDeepLinkHandledRef.current || loading) return; if (actionDeepLinkHandledRef.current || loading) return;
@@ -181,6 +200,16 @@ export function WalletScreen() {
}; };
}, [currency, filter, t]); }, [currency, filter, t]);
const handleFilterChange = useCallback((value: string) => {
if (value === filter) {
return;
}
setLogs(null);
setLogsLoading(true);
setFilter(value);
}, [filter]);
const refreshAll = useCallback(async () => { const refreshAll = useCallback(async () => {
setError(null); setError(null);
setLogsLoading(true); setLogsLoading(true);
@@ -210,6 +239,11 @@ export function WalletScreen() {
const displayMinor = isCreditPlayer const displayMinor = isCreditPlayer
? Number(balance?.available_balance ?? 0) ? Number(balance?.available_balance ?? 0)
: Number(balance?.balance ?? 0); : Number(balance?.balance ?? 0);
const panelTitle = !fundingModeKnown
? t("wallet.loadingTitle", { defaultValue: "账户资金" })
: isCreditPlayer
? t("wallet.creditTitle", { defaultValue: "信用" })
: t("wallet.title");
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
if (!logs || !hasMore || loadingMore) return; if (!logs || !hasMore || loadingMore) return;
@@ -243,9 +277,7 @@ export function WalletScreen() {
}, [hasMore, loadMore, loading, loadingMore, logsLoading]); }, [hasMore, loadMore, loading, loadingMore, logsLoading]);
return ( return (
<PlayerPanel <PlayerPanel title={panelTitle}>
title={isCreditPlayer ? t("wallet.creditTitle", { defaultValue: "信用" }) : t("wallet.title")}
>
<div className="space-y-3"> <div className="space-y-3">
{error ? ( {error ? (
<div className="rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700"> <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>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="text-sm font-semibold text-white/90"> <p className="text-sm font-semibold text-white/90">
{isCreditPlayer {fundingModeKnown && isCreditPlayer
? t("wallet.creditAvailable", { defaultValue: "可用信用" }) ? t("wallet.creditAvailable", { defaultValue: "可用信用" })
: t("wallet.balance")} : fundingModeKnown
? t("wallet.balance")
: t("wallet.loadingBalance", { defaultValue: "正在加载" })}
</p> </p>
{loading ? ( {loading || !fundingModeKnown ? (
<Skeleton className="mt-2 h-8 w-44 rounded-md bg-white/25" /> <Skeleton className="mt-2 h-8 w-44 rounded-md bg-white/25" />
) : ( ) : (
<PlayerMoneyDisplay <PlayerMoneyDisplay
@@ -288,21 +322,23 @@ export function WalletScreen() {
/> />
)} )}
<p className="mt-2 text-xs text-white/75"> <p className="mt-2 text-xs text-white/75">
{isCreditPlayer {!fundingModeKnown
? t("wallet.creditSummary", { ? t("wallet.loadingAccountMode", { defaultValue: "正在确认资金模式…" })
defaultValue: "授信 {{limit}} · 已用 {{used}}", : isCreditPlayer
limit: formatMinorAsCurrency(balance?.credit_limit ?? 0, currency), ? t("wallet.creditSummary", {
used: formatMinorAsCurrency(balance?.used_credit ?? 0, currency), defaultValue: "授信 {{limit}} · 已用 {{used}}",
}) limit: formatMinorAsCurrency(balance?.credit_limit ?? 0, currency),
: t("wallet.available", { used: formatMinorAsCurrency(balance?.used_credit ?? 0, currency),
amount: formatMinorAsCurrency(balance?.available_balance ?? 0, currency), })
})} : t("wallet.available", {
amount: formatMinorAsCurrency(balance?.available_balance ?? 0, currency),
})}
</p> </p>
</div> </div>
</div> </div>
</section> </section>
{!isCreditPlayer ? ( {fundingModeKnown && !isCreditPlayer ? (
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<TransferInDialog <TransferInDialog
idPrefix="wallet-" idPrefix="wallet-"
@@ -334,7 +370,7 @@ export function WalletScreen() {
</div> </div>
) : null} ) : null}
{!isCreditPlayer && (logs?.pending_reconcile?.length ?? 0) > 0 ? ( {fundingModeKnown && !isCreditPlayer && (logs?.pending_reconcile?.length ?? 0) > 0 ? (
<section <section
id="wallet-pending" 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" 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} ) : null}
<div id="wallet-logs" className="scroll-mt-3"> <div id="wallet-logs" className="scroll-mt-3">
<WalletLogsBlock {fundingModeKnown ? (
creditMode={isCreditPlayer} <WalletLogsBlock
logs={logs} creditMode={isCreditPlayer}
logsLoading={loading || logsLoading} logs={logs}
loadingMore={loadingMore} logsLoading={loading || logsLoading}
hasMore={hasMore} loadingMore={loadingMore}
onLoadMore={loadMore} hasMore={hasMore}
loadMoreRef={loadMoreRef} onLoadMore={loadMore}
filter={filter} loadMoreRef={loadMoreRef}
onFilterChange={setFilter} filter={filter}
currency={currency} onFilterChange={handleFilterChange}
/> currency={currency}
/>
) : (
<Skeleton className="h-40 w-full rounded-lg" />
)}
</div> </div>
</div> </div>
</PlayerPanel> </PlayerPanel>

View File

@@ -428,7 +428,7 @@
"flowsTitle": "Wallet logs", "flowsTitle": "Wallet logs",
"creditFlowsTitle": "Credit activity", "creditFlowsTitle": "Credit activity",
"playerChannel": { "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)" "wallet": "Main-site wallet player (transfers & wallet ledger)"
}, },
"creditAvailableAfter": "Available credit after", "creditAvailableAfter": "Available credit after",
@@ -458,7 +458,9 @@
}, },
"creditFlow": { "creditFlow": {
"all": "All", "all": "All",
"bet": "Credit hold", "bet": "Bet hold",
"game_settlement": "Draw settlement",
"rebate": "Period rebate",
"credit_release": "Credit release", "credit_release": "Credit release",
"bill_settlement": "Period payment", "bill_settlement": "Period payment",
"win_credit": "Win release", "win_credit": "Win release",
@@ -467,6 +469,9 @@
}, },
"txnStatus": { "txnStatus": {
"posted": "Success", "posted": "Success",
"accrued": "Accrued",
"in_bill": "In bill",
"settled": "Settled",
"pending_reconcile": "Pending reconciliation", "pending_reconcile": "Pending reconciliation",
"reversed": "Reversed", "reversed": "Reversed",
"manually_processed": "Case closed" "manually_processed": "Case closed"

View File

@@ -427,7 +427,7 @@
"creditLogsTitle": "क्रेडिट लेनदेन", "creditLogsTitle": "क्रेडिट लेनदेन",
"creditLogsSubtitle": "ओगट, मुक्ति र बिलिङ भुक्तानी", "creditLogsSubtitle": "ओगट, मुक्ति र बिलिङ भुक्तानी",
"playerChannel": { "playerChannel": {
"credit": "क्रेडिट लाइन: ओगट, मुक्ति र बिलिङ भुक्तानी (वालेट भुक्तानी होइन)", "credit": "क्रेडिट लाइन: बेट होल्ड, ड्र सेटलमेन्ट र अवधि भुक्तानी (वालेट भुक्तानी होइन)",
"wallet": "मुख्य साइट वालेट खेलाडी" "wallet": "मुख्य साइट वालेट खेलाडी"
}, },
"creditAvailableAfter": "पछि उपलब्ध क्रेडिट", "creditAvailableAfter": "पछि उपलब्ध क्रेडिट",
@@ -435,7 +435,9 @@
"emptyCreditLogs": "क्रेडिट लेनदेन छैन", "emptyCreditLogs": "क्रेडिट लेनदेन छैन",
"creditFlow": { "creditFlow": {
"all": "सबै", "all": "सबै",
"bet": "क्रेडिट ओगट", "bet": "बेट होल्ड",
"game_settlement": "ड्र सेटलमेन्ट",
"rebate": "अवधि रिबेट",
"credit_release": "मुक्ति", "credit_release": "मुक्ति",
"bill_settlement": "अवधि भुक्तानी", "bill_settlement": "अवधि भुक्तानी",
"win_credit": "जित मुक्ति", "win_credit": "जित मुक्ति",
@@ -466,6 +468,9 @@
}, },
"txnStatus": { "txnStatus": {
"posted": "सफल", "posted": "सफल",
"accrued": "जम्मा भयो",
"in_bill": "बिलमा",
"settled": "सेटल भयो",
"pending_reconcile": "मिलान बाँकी", "pending_reconcile": "मिलान बाँकी",
"reversed": "रिभर्स भयो", "reversed": "रिभर्स भयो",
"manually_processed": "केस बन्द भयो" "manually_processed": "केस बन्द भयो"

View File

@@ -427,7 +427,7 @@
"flowsTitle": "资金流水", "flowsTitle": "资金流水",
"creditFlowsTitle": "信用流水", "creditFlowsTitle": "信用流水",
"playerChannel": { "playerChannel": {
"credit": "信用盘:展示额度占用、释额与账期收付(非钱包派彩)", "credit": "信用盘:展示下注冻结、开奖结算与账期收付(非钱包派彩)",
"wallet": "主站钱包玩家(划转与钱包余额流水)" "wallet": "主站钱包玩家(划转与钱包余额流水)"
}, },
"creditAvailableAfter": "变更后可用信用", "creditAvailableAfter": "变更后可用信用",
@@ -457,7 +457,9 @@
}, },
"creditFlow": { "creditFlow": {
"all": "全部", "all": "全部",
"bet": "占用额度", "bet": "下注冻结",
"game_settlement": "开奖结算",
"rebate": "账期回水",
"credit_release": "释额", "credit_release": "释额",
"bill_settlement": "账期收付", "bill_settlement": "账期收付",
"win_credit": "中奖释额", "win_credit": "中奖释额",
@@ -466,6 +468,9 @@
}, },
"txnStatus": { "txnStatus": {
"posted": "成功", "posted": "成功",
"accrued": "已计提",
"in_bill": "已入账单",
"settled": "已结清",
"pending_reconcile": "待对账", "pending_reconcile": "待对账",
"reversed": "已冲正", "reversed": "已冲正",
"manually_processed": "已结案" "manually_processed": "已结案"

View File

@@ -3,7 +3,7 @@ export type WalletLogItem = {
log_id: string; log_id: string;
type: string; type: string;
biz_type: string; biz_type: string;
/** wallet_txn | credit_ledger */ /** wallet_txn | credit_ledger | rebate_record */
ledger_source?: string; ledger_source?: string;
funding_mode?: string; funding_mode?: string;
auth_source?: string | null; auth_source?: string | null;
@@ -13,7 +13,7 @@ export type WalletLogItem = {
direction: "in" | "out"; direction: "in" | "out";
currency_code: string; currency_code: string;
balance_after: number | null; balance_after: number | null;
/** 信用盘false 表示账期收付记账,不改变可用信用 */ /** 信用盘false 表示账期收付/账期回水展示记录,不改变可用信用 */
affects_available_credit?: boolean; affects_available_credit?: boolean;
ref_id: string | null; ref_id: string | null;
idempotent_key: string | null; idempotent_key: string | null;
@@ -57,7 +57,7 @@ export type GetWalletLogsParams = {
page?: number; page?: number;
/** 每页条数PRD 示例 `size` */ /** 每页条数PRD 示例 `size` */
size?: number; 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; type?: string;
/** 按钱包币种筛选 */ /** 按钱包币种筛选 */
currency?: string; currency?: string;