diff --git a/src/components/layout/player-bottom-nav.tsx b/src/components/layout/player-bottom-nav.tsx
index 922b0e2..27f791a 100644
--- a/src/components/layout/player-bottom-nav.tsx
+++ b/src/components/layout/player-bottom-nav.tsx
@@ -59,9 +59,6 @@ export function PlayerBottomNav() {
: "text-[#6b7280] hover:text-[#1f2937] active:text-[#1f2937]",
)}
>
- {active ? (
-
- ) : null}
- {t("hall.preview.totalBet")}{" "}
+ {t("hall.preview.amount")}{" "}
{formatMinorAsCurrency(summary.total_bet_amount, currencyCode)}
- {t("hall.preview.rebateDeduct")}{" "}
+ {t("hall.preview.rebate")}{" "}
{formatMinorAsCurrency(summary.total_rebate_amount, currencyCode)}
- {t("hall.preview.actualDeduct")}{" "}
+ {t("hall.preview.actual")}{" "}
{formatMinorAsCurrency(summary.total_actual_deduct, currencyCode)}
- {t("hall.preview.estimatedPayout")}{" "}
+ {t("hall.preview.total")}{" "}
- {formatMinorAsCurrency(summary.total_estimated_payout, currencyCode)}
+ {formatMinorAsCurrency(summary.total_actual_deduct, currencyCode)}
diff --git a/src/features/hall/hall-bet-result-dialog.tsx b/src/features/hall/hall-bet-result-dialog.tsx
index 677b8c2..014b46c 100644
--- a/src/features/hall/hall-bet-result-dialog.tsx
+++ b/src/features/hall/hall-bet-result-dialog.tsx
@@ -74,6 +74,12 @@ export function HallBetResultDialog({
{t("hall.result.draw", { defaultValue: "期号" })}{" "}
{data.draw.draw_id}
+
+ {t("hall.result.status", { defaultValue: "注单状态" })}{" "}
+
+ {t("ticketStatus.success", { defaultValue: "待开奖" })}
+
+
-
@@ -85,7 +91,25 @@ export function HallBetResultDialog({
{totalFailure}
-
- {t("hall.result.totalDeduct", { defaultValue: "成功扣款" })}{" "}
+ {t("hall.result.amount", { defaultValue: "金额" })}{" "}
+
+ {formatMinorAsCurrency(data.summary.total_bet_amount, currencyCode)}
+
+
+ -
+ {t("hall.result.rebate", { defaultValue: "回水" })}{" "}
+
+ {formatMinorAsCurrency(data.summary.total_rebate_amount, currencyCode)}
+
+
+ -
+ {t("hall.result.actual", { defaultValue: "实扣" })}{" "}
+
+ {formatMinorAsCurrency(data.summary.total_actual_deduct, currencyCode)}
+
+
+ -
+ {t("hall.result.total", { defaultValue: "合计" })}{" "}
{formatMinorAsCurrency(data.summary.total_actual_deduct, currencyCode)}
diff --git a/src/features/hall/hall-betting-grid.tsx b/src/features/hall/hall-betting-grid.tsx
index b5e2597..ea53651 100644
--- a/src/features/hall/hall-betting-grid.tsx
+++ b/src/features/hall/hall-betting-grid.tsx
@@ -50,6 +50,11 @@ type DraftEntry = {
line: TicketLineInput;
};
+type ClosedPlayCleanupData = {
+ cleanup_hint?: string;
+ cleanup_lines?: Array<{ client_line_no?: number; play_code?: string }>;
+};
+
type CellRiskState = "open" | "warning" | "sold_out";
type QuickFillState = Record;
@@ -569,6 +574,40 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
const buildLines = (): TicketLineInput[] => collectEntries().map((entry) => entry.line);
+ const applyClosedPlayCleanup = (data: unknown): boolean => {
+ const payload = data as ClosedPlayCleanupData | null;
+ const cleanupLines = Array.isArray(payload?.cleanup_lines) ? payload.cleanup_lines : [];
+ if (cleanupLines.length === 0) return false;
+
+ const entries = collectEntries();
+ const cleanupPairs = new Set();
+ cleanupLines.forEach((item) => {
+ const clientLineNo = Number(item?.client_line_no ?? 0);
+ const playCode = String(item?.play_code ?? "");
+ if (!Number.isInteger(clientLineNo) || clientLineNo <= 0 || playCode.trim() === "") return;
+ const entry = entries[clientLineNo - 1];
+ if (!entry) return;
+ cleanupPairs.add(`${entry.rowId}::${playCode}`);
+ });
+
+ if (cleanupPairs.size === 0) return false;
+
+ setRows((current) =>
+ current.map((row) => {
+ const nextAmounts = { ...row.amounts };
+ let changed = false;
+ Object.keys(nextAmounts).forEach((playCode) => {
+ if (!cleanupPairs.has(`${row.id}::${playCode}`)) return;
+ nextAmounts[playCode] = "";
+ changed = true;
+ });
+ return changed ? { ...row, amounts: nextAmounts } : row;
+ }),
+ );
+
+ return true;
+ };
+
const handlePreview = async () => {
if (!display) {
toast.error(t("hall.noDraw"));
@@ -609,6 +648,11 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
} catch (e) {
const code = e instanceof LotteryApiBizError ? e.code : 0;
const msg = e instanceof LotteryApiBizError ? e.message : t("hall.previewFailed");
+ if (e instanceof LotteryApiBizError && code === 2002 && applyClosedPlayCleanup(e.data)) {
+ const payload = e.data as ClosedPlayCleanupData;
+ toast.error(payload.cleanup_hint ?? t("hall.ticketError.2002"));
+ return;
+ }
toast.error(mapTicketBetError(code, msg, t));
} finally {
setPreviewLoading(false);
@@ -658,6 +702,13 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
} catch (e) {
const code = e instanceof LotteryApiBizError ? e.code : 0;
const msg = e instanceof LotteryApiBizError ? e.message : t("hall.placeFailed");
+ if (e instanceof LotteryApiBizError && code === 2002 && applyClosedPlayCleanup(e.data)) {
+ const payload = e.data as ClosedPlayCleanupData;
+ toast.error(payload.cleanup_hint ?? t("hall.ticketError.2002"));
+ setPreviewOpen(false);
+ setPreviewData(null);
+ return;
+ }
toast.error(mapTicketBetError(code, msg, t));
} finally {
setPlaceLoading(false);
diff --git a/src/features/results/draw-result-detail-screen.tsx b/src/features/results/draw-result-detail-screen.tsx
index 957197c..aff7adc 100644
--- a/src/features/results/draw-result-detail-screen.tsx
+++ b/src/features/results/draw-result-detail-screen.tsx
@@ -159,96 +159,127 @@ export function DrawResultDetailScreen({ drawNo }: DrawResultDetailScreenProps)
-
-
+
+
{data.previous_draw_no ? (
{t("results.previous")}
) : (
-
-
- {t("results.drawTime", {
- time: formatLotteryInstant(data.draw_time_iso ?? data.draw_time ?? null),
- })}
-
-
+
+
+
+
+ {t("results.detailTitle")}
+
+
+ {t("results.detail")}
+
+
+
+ {[
+ ["1st", data.results["1st"]],
+ ["2nd", data.results["2nd"]],
+ ["3rd", data.results["3rd"]],
+ ].map(([label, value]) => (
+
+
{label}
+
+ {value}
+
+
+ ))}
+
+
+
- {showMyPayout && myTotals ? (
-
-
- {t("results.myPayout")}
-
-
- {t("results.regular", {
- amount: formatMinorAsCurrency(myTotals.win, currency),
- })}
- {myTotals.jackpot > 0 ? (
- <>
- {" "}
- ·{" "}
- {t("results.jackpot", {
- amount: formatMinorAsCurrency(myTotals.jackpot, currency),
- })}
- >
- ) : null}
-
-
- ) : null}
- {showHitOnly ? (
-
- {t("results.hitPending")}
-
- ) : null}
+ {showMyPayout && myTotals ? (
+
+
+ {t("results.myPayout")}
+
+
+ {t("results.regular", {
+ amount: formatMinorAsCurrency(myTotals.win, currency),
+ })}
+ {myTotals.jackpot > 0 ? (
+ <>
+ {" "}
+ ·{" "}
+ {t("results.jackpot", {
+ amount: formatMinorAsCurrency(myTotals.jackpot, currency),
+ })}
+ >
+ ) : null}
+
+
+ ) : null}
-
-
- {t("results.hitHint")}
-
-
- {t("results.viewMyWinning")}
-
-
+ {showHitOnly ? (
+
+ {t("results.hitPending")}
+
+ ) : null}
+
+
+
+ {t("results.hitHint")}
+
+
+ {t("results.viewMyWinning")}
+
+
diff --git a/src/i18n/locales/en/player.json b/src/i18n/locales/en/player.json
index 0b84a37..c5033ee 100644
--- a/src/i18n/locales/en/player.json
+++ b/src/i18n/locales/en/player.json
@@ -143,6 +143,9 @@
"empty": "No preview data",
"draw": "Issue",
"status": "Status",
+ "amount": "Amount",
+ "rebate": "Rebate",
+ "total": "Total",
"totalBet": "Total stake",
"rebateDeduct": "Rebate deduction",
"actualDeduct": "Actual deduction",
diff --git a/src/i18n/locales/ne/player.json b/src/i18n/locales/ne/player.json
index 65c7f39..6aaef7b 100644
--- a/src/i18n/locales/ne/player.json
+++ b/src/i18n/locales/ne/player.json
@@ -143,6 +143,9 @@
"empty": "पूर्वावलोकन डेटा छैन",
"draw": "इश्यू",
"status": "स्थिति",
+ "amount": "रकम",
+ "rebate": "रिबेट",
+ "total": "जम्मा",
"totalBet": "कुल बेट",
"rebateDeduct": "रिबेट कट्टा",
"actualDeduct": "वास्तविक कट्टा",
diff --git a/src/i18n/locales/zh/player.json b/src/i18n/locales/zh/player.json
index 3889aec..5a1338f 100644
--- a/src/i18n/locales/zh/player.json
+++ b/src/i18n/locales/zh/player.json
@@ -143,6 +143,9 @@
"empty": "暂无预览数据",
"draw": "期号",
"status": "状态",
+ "amount": "金额",
+ "rebate": "回水",
+ "total": "合计",
"totalBet": "总下注",
"rebateDeduct": "回水抵扣",
"actualDeduct": "实扣金额",