feat: 优化大厅 Jackpot 参与提示与玩家页头布局

This commit is contained in:
2026-05-22 14:34:11 +08:00
parent 0cd85ae287
commit b61a2ab07b
7 changed files with 104 additions and 34 deletions

View File

@@ -31,6 +31,7 @@ type HallBetPreviewDialogProps = {
currencyCode: string;
data: TicketPreviewData | null;
placing: boolean;
jackpotEnabled?: boolean;
/** 界面 §4.2:封盘后禁止提交,主按钮文案为「已封盘」 */
allowSubmit?: boolean;
onConfirmPlace: () => void;
@@ -107,6 +108,7 @@ export function HallBetPreviewDialog({
currencyCode,
data,
placing,
jackpotEnabled = false,
allowSubmit = true,
onConfirmPlace,
}: HallBetPreviewDialogProps) {
@@ -188,6 +190,16 @@ export function HallBetPreviewDialog({
</span>
</div>
{jackpotEnabled ? (
<Alert className="border-[#d9ecff] bg-[#f4f9ff] text-[#0b3f96]">
<CheckCircle2 className="size-4" />
<AlertTitle>{t("hall.jackpotParticipation.title")}</AlertTitle>
<AlertDescription className="text-xs leading-relaxed">
{t("hall.jackpotParticipation.previewDescription")}
</AlertDescription>
</Alert>
) : null}
<div className="overflow-x-auto rounded-xl border border-[#dfe8f6]">
<table className="min-w-[640px] w-full border-collapse text-xs">
<thead className="bg-[#f4f7fd] text-[#304f86]">

View File

@@ -21,6 +21,7 @@ type HallBetResultDialogProps = {
onOpenChange: (open: boolean) => void;
currencyCode: string;
data: TicketPlaceData | null;
jackpotEnabled?: boolean;
};
export function HallBetResultDialog({
@@ -28,6 +29,7 @@ export function HallBetResultDialog({
onOpenChange,
currencyCode,
data,
jackpotEnabled = false,
}: HallBetResultDialogProps) {
const { t } = useTranslation("player");
@@ -119,6 +121,13 @@ export function HallBetResultDialog({
</p>
</div>
{jackpotEnabled ? (
<div className="rounded-lg border border-[#d9ecff] bg-[#f4f9ff] px-3 py-3 text-sm leading-relaxed text-[#0b3f96]">
<p className="font-black">{t("hall.jackpotParticipation.title")}</p>
<p className="mt-1 text-xs">{t("hall.jackpotParticipation.resultDescription")}</p>
</div>
) : null}
<div className="space-y-2">
<p className="text-sm font-black text-[#e5002c]">
{t("hall.result.items")}

View File

@@ -84,7 +84,6 @@ const categoryTabs: { value: HallCategory; label: string }[] = [
{ value: "D2", label: "2D" },
{ value: "D3", label: "3D" },
{ value: "D4", label: "4D" },
{ value: "JACKPOT", label: "Jackpot" },
];
const D2_PLAY_ORDER = ["pos_2a", "pos_2b", "pos_2c", "pos_2abc"] as const;
@@ -496,8 +495,25 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
const currentQuickFill = quickFillState[activeCategory] ?? { favorites: [], history: [] };
const favorites = currentQuickFill.favorites;
const historyNumbers = currentQuickFill.history;
const jackpotPanelCopy = !jackpot?.enabled
? {
title: t("hall.jackpotPanel.disabledTitle"),
subtitle: t("hall.jackpotPanel.disabledSubtitle"),
description: t("hall.jackpotPanel.disabledDescription"),
}
: isBettable
? {
title: t("hall.jackpotPanel.infoTitle"),
subtitle: t("hall.jackpotPanel.infoSubtitle"),
description: t("hall.jackpotPanel.infoDescription"),
}
: {
title: t("hall.jackpotPanel.closedInfoTitle"),
subtitle: t("hall.jackpotPanel.closedInfoSubtitle"),
description: t("hall.jackpotPanel.closedInfoDescription"),
};
const tableDisabled = activeCategory === "JACKPOT" || !isBettable || catalogState.kind !== "ok";
const tableDisabled = !isBettable || catalogState.kind !== "ok";
const sealedBetUi = Boolean(display && isHallSealedCountdownUi(display.status));
const numberPlaceholder = activeCategory === "D2" ? "00" : activeCategory === "D3" ? "000" : "0000";
@@ -888,7 +904,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
<>
<section className="space-y-3" aria-label={t("hall.aria")}>
<div className="rounded-xl border border-[#e8eef7] bg-white p-1 shadow-[0_6px_18px_rgba(30,64,175,0.06)]">
<div className="grid grid-cols-4 gap-1">
<div className="grid grid-cols-3 gap-1">
{categoryTabs.map((tab) => {
const active = activeCategory === tab.value;
return (
@@ -941,33 +957,18 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
</div>
) : null}
{activeCategory === "JACKPOT" ? (
<div className="rounded-xl border border-[#edf1f7] bg-[#f7f9fc] p-7 text-center text-slate-500">
<div className="mx-auto flex size-14 items-center justify-center rounded-full bg-slate-200 text-slate-600">
<Ticket className="size-7" aria-hidden />
<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="mt-0.5 text-xs leading-5 text-slate-500">
{t("hall.quickFill.description")}
</p>
</div>
<p className="mt-3 text-lg font-bold text-slate-900">
{t("hall.closed.title")}
</p>
<p className="mt-1 text-xs">{t("hall.closed.subtitle")}</p>
<div className="mt-5 rounded-lg border border-[#cbdcf7] bg-white px-3 py-3 text-left text-xs text-[#315a9f]">
{t("hall.closed.description")}
</div>
</div>
) : (
<>
<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="mt-0.5 text-xs leading-5 text-slate-500">
{t("hall.quickFill.description")}
</p>
</div>
<div className="flex shrink-0 items-center gap-1.5">
{activeRow?.number ? (
<div className="flex shrink-0 items-center gap-1.5">
{activeRow?.number ? (
<Button
type="button"
variant="ghost"
@@ -1275,8 +1276,6 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
? t("hall.table.insufficientBalance")
: t("hall.table.submitBet")}
</Button>
</>
)}
</section>
<HallBetPreviewDialog
@@ -1288,6 +1287,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
currencyCode={currencyCode}
data={previewData}
placing={placeLoading}
jackpotEnabled={Boolean(jackpot?.enabled)}
allowSubmit={isBettable && availableMinor >= debouncedSummary.actual}
onConfirmPlace={() => void handlePlace()}
/>
@@ -1300,6 +1300,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
}}
currencyCode={currencyCode}
data={resultData}
jackpotEnabled={Boolean(jackpot?.enabled)}
/>
</>
);