feat: 优化多语言文案接入并升级大厅与钱包交互体验
- 补充大厅下注结果、快速填单、查中奖、分页与通用操作多语言文案 - 移除多处界面默认文案回退,统一改用 i18n 配置输出 - 优化大厅快速填单、开奖结果入口与注单筛选区域视觉交互 - 重构钱包转入转出弹窗与流水卡片样式,增强金额与状态信息展示
This commit is contained in:
@@ -82,15 +82,15 @@ function SubmittingPanel() {
|
||||
</div>
|
||||
<DialogHeader className="mt-8 items-center gap-2">
|
||||
<DialogTitle className="text-xl font-black text-slate-950">
|
||||
{t("hall.preview.processingTitle", { defaultValue: "正在提交下注" })}
|
||||
{t("hall.preview.processingTitle")}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="max-w-[220px] text-center text-sm leading-relaxed text-slate-500">
|
||||
{t("hall.preview.processingDescription", { defaultValue: "请勿关闭页面或返回上一页。" })}
|
||||
{t("hall.preview.processingDescription")}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="mt-7 inline-flex items-center gap-2 text-sm font-semibold text-slate-500">
|
||||
<LoaderCircle className="size-4 animate-spin text-[#0755c7]" />
|
||||
{t("hall.preview.processingProgress", { defaultValue: "正在处理注单..." })}
|
||||
{t("hall.preview.processingProgress")}
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -143,7 +143,7 @@ export function HallBetPreviewDialog({
|
||||
onClick={() => onOpenChange(false)}
|
||||
disabled={placing}
|
||||
className="absolute right-3 top-3 inline-flex size-9 items-center justify-center rounded-full text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700 disabled:opacity-50"
|
||||
aria-label={t("actions.close", { defaultValue: "关闭" })}
|
||||
aria-label={t("actions.close")}
|
||||
>
|
||||
<XIcon className="size-5" />
|
||||
</button>
|
||||
@@ -193,10 +193,10 @@ export function HallBetPreviewDialog({
|
||||
<tr>
|
||||
<th className="w-10 border-r border-[#dfe8f6] px-2 py-3 text-center font-black">No.</th>
|
||||
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
||||
{t("hall.result.number", { defaultValue: "号码" })}
|
||||
{t("hall.result.number")}
|
||||
</th>
|
||||
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
||||
{t("orders.play", { defaultValue: "玩法" })}
|
||||
{t("orders.play")}
|
||||
</th>
|
||||
<th className="border-r border-[#dfe8f6] px-2 py-3 text-center font-black">
|
||||
{t("hall.preview.amount")}
|
||||
@@ -283,7 +283,7 @@ export function HallBetPreviewDialog({
|
||||
) : (
|
||||
<div className="flex items-center gap-2 rounded-xl border border-emerald-100 bg-emerald-50 px-3 py-3 text-sm font-semibold text-emerald-700">
|
||||
<CheckCircle2 className="size-5" />
|
||||
{t("hall.preview.noWarnings", { defaultValue: "当前预览未发现明显风险。" })}
|
||||
{t("hall.preview.noWarnings")}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -47,7 +47,7 @@ export function HallBetResultDialog({
|
||||
type="button"
|
||||
onClick={() => onOpenChange(false)}
|
||||
className="absolute right-3 top-3 inline-flex size-9 items-center justify-center rounded-full text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700"
|
||||
aria-label={t("actions.close", { defaultValue: "关闭" })}
|
||||
aria-label={t("actions.close")}
|
||||
>
|
||||
<XIcon className="size-5" />
|
||||
</button>
|
||||
@@ -56,11 +56,11 @@ export function HallBetResultDialog({
|
||||
</div>
|
||||
<DialogHeader className="mt-4 items-center gap-2">
|
||||
<DialogTitle className="text-2xl font-black text-slate-950">
|
||||
{t("hall.result.title", { defaultValue: "下注结果" })}
|
||||
{t("hall.result.title")}
|
||||
</DialogTitle>
|
||||
{data ? (
|
||||
<DialogDescription className="text-sm leading-relaxed text-slate-500">
|
||||
{t("hall.result.draw", { defaultValue: "期号" })}{" "}
|
||||
{t("hall.result.draw")}{" "}
|
||||
<span className="font-mono font-black text-[#e5002c]">{data.draw.draw_id}</span>
|
||||
</DialogDescription>
|
||||
) : null}
|
||||
@@ -73,20 +73,20 @@ export function HallBetResultDialog({
|
||||
<div className="space-y-4 py-4">
|
||||
{!data ? (
|
||||
<p className="text-sm text-slate-500">
|
||||
{t("hall.result.empty", { defaultValue: "暂无结果。" })}
|
||||
{t("hall.result.empty")}
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="rounded-lg border border-emerald-100 bg-emerald-50 px-3 py-4 text-center">
|
||||
<p className="text-sm font-bold text-emerald-700">
|
||||
{t("hall.result.successCount", { defaultValue: "成功注项" })}
|
||||
{t("hall.result.successCount")}
|
||||
</p>
|
||||
<p className="mt-2 text-4xl font-black tabular-nums text-emerald-600">{totalSuccess}</p>
|
||||
</div>
|
||||
<div className="rounded-lg border border-rose-100 bg-rose-50 px-3 py-4 text-center">
|
||||
<p className="text-sm font-bold text-rose-600">
|
||||
{t("hall.result.failureCount", { defaultValue: "失败注项" })}
|
||||
{t("hall.result.failureCount")}
|
||||
</p>
|
||||
<p className="mt-2 text-4xl font-black tabular-nums text-[#e5002c]">{totalFailure}</p>
|
||||
</div>
|
||||
@@ -98,7 +98,7 @@ export function HallBetResultDialog({
|
||||
<ClipboardList className="size-5" />
|
||||
</span>
|
||||
<span className="truncate text-sm font-black text-[#0b3f96]">
|
||||
{t("hall.result.actual", { defaultValue: "实扣金额" })}
|
||||
{t("hall.result.actual")}
|
||||
</span>
|
||||
</div>
|
||||
<span className="shrink-0 font-mono text-base font-black tabular-nums text-[#0b3f96]">
|
||||
@@ -108,11 +108,11 @@ export function HallBetResultDialog({
|
||||
|
||||
<div className="grid gap-2 rounded-lg border border-[#e8eef7] bg-white px-4 py-3 text-xs text-slate-600 sm:grid-cols-2">
|
||||
<p>
|
||||
{t("hall.result.orderNo", { defaultValue: "订单号" })}:{" "}
|
||||
{t("hall.result.orderNo")}:{" "}
|
||||
<span className="font-mono font-black text-[#0b3f96]">{data.order_no}</span>
|
||||
</p>
|
||||
<p>
|
||||
{t("hall.result.balanceAfter", { defaultValue: "剩余余额" })}:{" "}
|
||||
{t("hall.result.balanceAfter")}:{" "}
|
||||
<span className="font-semibold text-slate-950">
|
||||
{formatMinorAsCurrency(data.balance_after, currencyCode)}
|
||||
</span>
|
||||
@@ -121,9 +121,7 @@ export function HallBetResultDialog({
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-black text-[#e5002c]">
|
||||
{t("hall.result.items", {
|
||||
defaultValue: "成功注项明细",
|
||||
})}
|
||||
{t("hall.result.items")}
|
||||
</p>
|
||||
<div className="overflow-x-auto rounded-xl border border-[#dfe8f6]">
|
||||
<table className="min-w-[430px] w-full border-collapse text-xs">
|
||||
@@ -131,13 +129,13 @@ export function HallBetResultDialog({
|
||||
<tr>
|
||||
<th className="w-10 border-r border-[#dfe8f6] px-2 py-2.5 text-center font-black">No.</th>
|
||||
<th className="border-r border-[#dfe8f6] px-2 py-2.5 text-center font-black">
|
||||
{t("hall.result.number", { defaultValue: "号码" })}
|
||||
{t("hall.result.number")}
|
||||
</th>
|
||||
<th className="border-r border-[#dfe8f6] px-2 py-2.5 text-center font-black">
|
||||
{t("orders.play", { defaultValue: "玩法" })}
|
||||
{t("orders.play")}
|
||||
</th>
|
||||
<th className="px-2 py-2.5 text-center font-black">
|
||||
{t("hall.result.actualDeduct", { defaultValue: "实扣" })}
|
||||
{t("hall.result.actualDeduct")}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -171,12 +169,12 @@ export function HallBetResultDialog({
|
||||
</div>
|
||||
{totalFailure === 0 ? (
|
||||
<div className="rounded-lg border border-emerald-100 bg-emerald-50 px-3 py-3 text-sm font-semibold text-emerald-700">
|
||||
{t("hall.result.noFailures", { defaultValue: "本次提交没有失败注项。" })}
|
||||
{t("hall.result.noFailures")}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2 rounded-lg border border-rose-100 bg-rose-50 px-3 py-3">
|
||||
<p className="text-sm font-black text-[#e5002c]">
|
||||
{t("hall.result.failedItems", { defaultValue: "失败注项明细" })}
|
||||
{t("hall.result.failedItems")}
|
||||
</p>
|
||||
{failedItems.map((item, index) => (
|
||||
<div
|
||||
@@ -188,7 +186,7 @@ export function HallBetResultDialog({
|
||||
{playLabel(item.play_code, t)}
|
||||
</span>
|
||||
<span className="shrink-0 font-bold text-[#e5002c]">
|
||||
{item.fail_reason_text ?? item.fail_reason_code ?? t("hall.result.failed", { defaultValue: "失败" })}
|
||||
{item.fail_reason_text ?? item.fail_reason_code ?? t("hall.result.failed")}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -208,7 +206,7 @@ export function HallBetResultDialog({
|
||||
render={<Link href="/orders" />}
|
||||
>
|
||||
<ClipboardList className="size-5" />
|
||||
{t("hall.result.viewBets", { defaultValue: "查看注单" })}
|
||||
{t("hall.result.viewBets")}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -216,7 +214,7 @@ export function HallBetResultDialog({
|
||||
className="h-12 rounded-lg border-0 bg-[#07459f] text-base font-black text-white shadow-[0_10px_24px_rgba(7,69,159,0.24)] hover:bg-[#063b88]"
|
||||
>
|
||||
<Ticket className="size-5" />
|
||||
{t("hall.result.continueBetting", { defaultValue: "继续下注" })}
|
||||
{t("hall.result.continueBetting")}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -625,19 +625,13 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
removed
|
||||
? t("hall.playConfig.playClosedDraftCleared", {
|
||||
playCode: evt.play_code,
|
||||
defaultValue: "{{playCode}} 已关闭,相关草稿金额已清除。",
|
||||
})
|
||||
: t("hall.playConfig.playClosed", {
|
||||
playCode: evt.play_code,
|
||||
defaultValue: "{{playCode}} 已关闭。",
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
toast.message(
|
||||
t("hall.playConfig.updated", {
|
||||
defaultValue: "玩法配置已更新,已刷新下注表格。",
|
||||
}),
|
||||
);
|
||||
toast.message(t("hall.playConfig.updated"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -645,12 +639,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
void loadCatalog();
|
||||
setPreviewOpen(false);
|
||||
setPreviewData(null);
|
||||
toast.message(
|
||||
evt.message ??
|
||||
t("hall.playConfig.oddsUpdated", {
|
||||
defaultValue: "赔率已更新,请重新预览注单。",
|
||||
}),
|
||||
);
|
||||
toast.message(evt.message ?? t("hall.playConfig.oddsUpdated"));
|
||||
};
|
||||
|
||||
channel.listen(".play.toggle", onPlayToggle);
|
||||
@@ -840,7 +829,6 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
t("hall.placePartialFailed", {
|
||||
success: data.summary.success_count ?? 0,
|
||||
failed: data.summary.failure_count ?? 0,
|
||||
defaultValue: "{{success}} 个成功,{{failed}} 个失败",
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -947,7 +935,6 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
<p className="rounded-full bg-amber-100 px-3 py-1 text-xs font-bold text-amber-800">
|
||||
{t("results.jackpotGap", {
|
||||
count: jackpot.draws_since_last_burst,
|
||||
defaultValue: "距上次爆池 {{count}} 期",
|
||||
})}
|
||||
</p>
|
||||
) : null}
|
||||
@@ -970,49 +957,74 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="space-y-3 rounded-xl border border-[#e9eef7] bg-white p-4 shadow-[0_8px_28px_rgba(15,23,42,0.05)]">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-slate-900">
|
||||
{t("hall.quickFill.title", { defaultValue: "快速填单" })}
|
||||
<div className="rounded-xl border border-[#e3ebf7] bg-white px-3 py-3 shadow-[0_8px_24px_rgba(15,23,42,0.045)]">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-bold leading-5 text-slate-950">
|
||||
{t("hall.quickFill.title")}
|
||||
</p>
|
||||
<p className="text-xs text-slate-500">
|
||||
{t("hall.quickFill.description", {
|
||||
defaultValue: "收藏号码、最近号码可一键填入当前行。",
|
||||
})}
|
||||
<p className="mt-0.5 text-xs leading-5 text-slate-500">
|
||||
{t("hall.quickFill.description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button type="button" variant="outline" size="sm" onClick={clearAllRows}>
|
||||
{t("hall.quickFill.clearAll", { defaultValue: "批量清空" })}
|
||||
</Button>
|
||||
<div className="flex shrink-0 items-center gap-1.5">
|
||||
{activeRow?.number ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label={
|
||||
favorites.includes(activeRow.number)
|
||||
? t("hall.quickFill.unfavorite")
|
||||
: t("hall.quickFill.favorite")
|
||||
}
|
||||
aria-pressed={favorites.includes(activeRow.number)}
|
||||
title={
|
||||
favorites.includes(activeRow.number)
|
||||
? t("hall.quickFill.unfavorite")
|
||||
: t("hall.quickFill.favorite")
|
||||
}
|
||||
className={cn(
|
||||
"size-8 rounded-full border border-[#ffd7db] bg-[#fff7f8] text-[#d81435] hover:bg-[#fff1f3] hover:text-[#b80f2b]",
|
||||
favorites.includes(activeRow.number) &&
|
||||
"border-[#d81435] bg-[#d81435] text-white hover:bg-[#c51230] hover:text-white",
|
||||
)}
|
||||
onClick={() => toggleFavoriteNumber(activeRow.number)}
|
||||
>
|
||||
<Star className="mr-1 size-4" />
|
||||
{favorites.includes(activeRow.number)
|
||||
? t("hall.quickFill.unfavorite", { defaultValue: "取消收藏" })
|
||||
: t("hall.quickFill.favorite", { defaultValue: "收藏号码" })}
|
||||
<Star
|
||||
className={cn(
|
||||
"size-4",
|
||||
favorites.includes(activeRow.number) && "fill-current",
|
||||
)}
|
||||
aria-hidden
|
||||
/>
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label={t("hall.quickFill.clearAll")}
|
||||
title={t("hall.quickFill.clearAll")}
|
||||
className="size-8 rounded-full border border-[#dfe6f0] bg-[#f8fafc] text-slate-500 hover:bg-slate-100 hover:text-slate-900"
|
||||
onClick={clearAllRows}
|
||||
>
|
||||
<Trash2 className="size-4" aria-hidden />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-slate-400">
|
||||
{t("hall.quickFill.favorites", { defaultValue: "收藏" })}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{favoriteChips.length > 0 ? (
|
||||
favoriteChips.map((number) => (
|
||||
<div className="mt-3 space-y-2">
|
||||
{favoriteChips.length > 0 ? (
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="mr-0.5 text-[11px] font-semibold text-[#d81435]">
|
||||
{t("hall.quickFill.favorites")}
|
||||
</span>
|
||||
{favoriteChips.map((number) => (
|
||||
<button
|
||||
key={`fav-${number}`}
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-[#ffd7db] bg-[#fff3f5] px-3 py-1 text-xs font-medium text-[#d81435]"
|
||||
className="inline-flex h-7 items-center gap-1 rounded-full border border-[#ffd7db] bg-[#fff3f5] px-2.5 text-xs font-semibold text-[#d81435] transition-colors hover:bg-[#ffe9ed]"
|
||||
onPointerDown={() => {
|
||||
const current = holdFavoriteRef.current;
|
||||
current.number = number;
|
||||
@@ -1044,38 +1056,32 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
}}
|
||||
>
|
||||
{number}
|
||||
<span className="text-[10px] opacity-70">
|
||||
{t("hall.quickFill.tapHold", { defaultValue: "长按取消" })}
|
||||
<span className="text-[10px] font-medium opacity-70">
|
||||
{t("hall.quickFill.tapHold")}
|
||||
</span>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<span className="text-xs text-slate-400">
|
||||
{t("hall.quickFill.emptyFavorites", { defaultValue: "暂无收藏" })}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-slate-400">
|
||||
{t("hall.quickFill.history", { defaultValue: "最近 20 个历史号码" })}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="mr-0.5 text-[11px] font-semibold text-slate-400">
|
||||
{t("hall.quickFill.history")}
|
||||
</span>
|
||||
{historyChips.length > 0 ? (
|
||||
historyChips.map((number) => (
|
||||
<button
|
||||
key={`his-${number}`}
|
||||
type="button"
|
||||
className="inline-flex items-center rounded-full border border-[#dce7f7] bg-[#f8fbff] px-3 py-1 text-xs font-medium text-[#07459f]"
|
||||
className="inline-flex h-7 min-w-10 items-center justify-center rounded-full border border-[#d7e5f8] bg-[#f8fbff] px-3 text-xs font-bold text-[#07459f] transition-colors hover:border-[#b9d0f3] hover:bg-[#eef6ff]"
|
||||
onClick={() => fillCurrentRow(number)}
|
||||
>
|
||||
{number}
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<span className="text-xs text-slate-400">
|
||||
{t("hall.quickFill.emptyHistory", { defaultValue: "暂无历史号码" })}
|
||||
<span className="inline-flex h-7 items-center rounded-full border border-dashed border-slate-200 bg-slate-50 px-3 text-xs text-slate-400">
|
||||
{t("hall.quickFill.emptyHistory")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -1122,7 +1128,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
: ""}
|
||||
</span>
|
||||
<span className="block text-[9px] font-medium text-[#9aa8bd]">
|
||||
{t("hall.table.amountPlaceholder", { defaultValue: "金额" })}
|
||||
{t("hall.table.amountPlaceholder")}
|
||||
</span>
|
||||
</th>
|
||||
))}
|
||||
@@ -1177,7 +1183,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
inputMode="decimal"
|
||||
placeholder={
|
||||
status === "sold_out"
|
||||
? t("hall.table.soldOut", { defaultValue: "售罄" })
|
||||
? t("hall.table.soldOut")
|
||||
: "-"
|
||||
}
|
||||
onFocus={() => setActiveRowId(row.id)}
|
||||
@@ -1192,11 +1198,11 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
/>
|
||||
{status === "sold_out" ? (
|
||||
<p className="mt-0.5 text-center text-[9px] font-bold text-slate-500">
|
||||
{t("hall.table.soldOut", { defaultValue: "售罄" })}
|
||||
{t("hall.table.soldOut")}
|
||||
</p>
|
||||
) : status === "warning" ? (
|
||||
<p className="mt-0.5 text-center text-[9px] font-bold text-amber-700">
|
||||
{t("hall.table.warning", { defaultValue: "接近售罄" })}
|
||||
{t("hall.table.warning")}
|
||||
</p>
|
||||
) : null}
|
||||
</td>
|
||||
@@ -1227,13 +1233,13 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
className="flex h-10 w-full items-center justify-center gap-1.5 border-t border-[#edf2f9] bg-white text-xs font-bold text-[#1d57b7] hover:bg-[#f7faff] disabled:text-slate-300"
|
||||
>
|
||||
<CirclePlus className="size-4" aria-hidden />
|
||||
{t("hall.table.addRow", { defaultValue: "添加一行" })}
|
||||
{t("hall.table.addRow")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between rounded-xl border border-[#e9eef7] bg-[#f8fbff] px-4 py-3 text-sm shadow-[0_6px_20px_rgba(15,23,42,0.04)]">
|
||||
<span className="text-xs font-medium text-slate-500">
|
||||
{t("hall.table.draftTotal", { defaultValue: "投注金额" })}
|
||||
{t("hall.table.draftTotal")}
|
||||
</span>
|
||||
<span className="text-base font-black tabular-nums text-[#0b3f96]">
|
||||
{formatMinorAsCurrency(debouncedSummary.actual, currencyCode)}
|
||||
@@ -1254,12 +1260,12 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
>
|
||||
<Ticket className="size-5" aria-hidden />
|
||||
{previewLoading
|
||||
? t("hall.table.previewing", { defaultValue: "预览中..." })
|
||||
? t("hall.table.previewing")
|
||||
: !isBettable
|
||||
? t("hall.closed.title")
|
||||
: availableMinor < debouncedSummary.actual
|
||||
? t("hall.table.insufficientBalance", { defaultValue: "余额不足" })
|
||||
: t("hall.table.submitBet", { defaultValue: "提交下注" })}
|
||||
? t("hall.table.insufficientBalance")
|
||||
: t("hall.table.submitBet")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -47,7 +47,7 @@ export function HallScreen() {
|
||||
href="/rules"
|
||||
className="shrink-0 rounded-full border border-[#e4eaf4] bg-[#f8fafc] px-3 py-1.5 text-xs font-bold text-[#0b3f96] hover:bg-[#f1f6ff]"
|
||||
>
|
||||
{tp("nav.rules", { defaultValue: "规则" })}
|
||||
{tp("nav.rules")}
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -42,7 +42,7 @@ export function JackpotBurstOverlay({ event, onClose }: JackpotBurstOverlayProps
|
||||
className="fixed inset-0 z-[90] flex items-center justify-center bg-[#08111f]/95 px-4 py-6 text-white"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label={t("hall.jackpotBurst.title", { defaultValue: "Jackpot 爆池" })}
|
||||
aria-label={t("hall.jackpotBurst.title")}
|
||||
>
|
||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
<div className="absolute left-0 top-1/4 h-px w-full animate-[pulse_1.8s_ease-in-out_infinite] bg-[#f5c542]" />
|
||||
@@ -56,7 +56,7 @@ export function JackpotBurstOverlay({ event, onClose }: JackpotBurstOverlayProps
|
||||
size="icon"
|
||||
className="absolute right-2 top-2 text-white hover:bg-white/10 hover:text-white"
|
||||
onClick={onClose}
|
||||
aria-label={t("hall.jackpotBurst.close", { defaultValue: "关闭" })}
|
||||
aria-label={t("hall.jackpotBurst.close")}
|
||||
>
|
||||
<X className="size-4" aria-hidden />
|
||||
</Button>
|
||||
@@ -66,11 +66,10 @@ export function JackpotBurstOverlay({ event, onClose }: JackpotBurstOverlayProps
|
||||
</div>
|
||||
|
||||
<p className="text-xs font-bold uppercase tracking-[0.18em] text-[#f5c542]">
|
||||
{t("hall.jackpotBurst.title", { defaultValue: "Jackpot 爆池" })}
|
||||
{t("hall.jackpotBurst.title")}
|
||||
</p>
|
||||
<p className="mt-2 text-sm font-semibold text-slate-200">
|
||||
{t("hall.jackpotBurst.subtitle", {
|
||||
defaultValue: "期号 {{drawNo}} 触发奖池派发",
|
||||
drawNo: event.draw_no,
|
||||
})}
|
||||
</p>
|
||||
@@ -80,26 +79,26 @@ export function JackpotBurstOverlay({ event, onClose }: JackpotBurstOverlayProps
|
||||
{event.first_prize_number || "----"}
|
||||
</div>
|
||||
<p className="mt-2 text-xs font-semibold text-slate-300">
|
||||
{t("hall.jackpotBurst.number", { defaultValue: "头奖号码" })}
|
||||
{t("hall.jackpotBurst.number")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="w-full space-y-2 text-left text-sm">
|
||||
<div className="flex items-center justify-between gap-4 rounded-md bg-white/[0.05] px-3 py-2">
|
||||
<span className="text-slate-300">
|
||||
{t("hall.jackpotBurst.amount", { defaultValue: "爆池金额" })}
|
||||
{t("hall.jackpotBurst.amount")}
|
||||
</span>
|
||||
<span className="text-right font-black text-[#f5c542]">{amount}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md bg-white/[0.05] px-3 py-2">
|
||||
<span className="text-slate-300">
|
||||
{t("hall.jackpotBurst.winners", { defaultValue: "中奖人数" })}
|
||||
{t("hall.jackpotBurst.winners")}
|
||||
</span>
|
||||
<span className="font-bold">{event.winner_count}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md bg-white/[0.05] px-3 py-2">
|
||||
<span className="text-slate-300">
|
||||
{t("hall.jackpotBurst.triggerLabel", { defaultValue: "触发方式" })}
|
||||
{t("hall.jackpotBurst.triggerLabel")}
|
||||
</span>
|
||||
<span className="font-bold">{triggerLabel(event.trigger_type, t)}</span>
|
||||
</div>
|
||||
|
||||
@@ -14,11 +14,8 @@ function notifyBrowser(event: JackpotBurstEvent, t: TFunction<"player">): void {
|
||||
|
||||
const currency = event.currency_code.toUpperCase();
|
||||
const amount = formatMinorAsCurrency(event.total_payout_amount, currency);
|
||||
const title = t("hall.jackpotBurst.notificationTitle", {
|
||||
defaultValue: "Jackpot 爆池",
|
||||
});
|
||||
const title = t("hall.jackpotBurst.notificationTitle");
|
||||
const body = t("hall.jackpotBurst.notificationBody", {
|
||||
defaultValue: "期号 {{drawNo}} 派发 {{amount}}",
|
||||
drawNo: event.draw_no,
|
||||
amount,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user