feat(hall): 支持全保金额整除校验与规则提示,优化桌面端转账按钮布局
Some checks failed
lotteryfront CI / build (push) Has been cancelled
Some checks failed
lotteryfront CI / build (push) Has been cancelled
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { ChevronDown, ChevronUp, Lock, Ticket, Trash2, Star } from "lucide-react";
|
||||
import { ChevronDown, ChevronUp, CircleHelp, Lock, Ticket, Trash2, Star } from "lucide-react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, memo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "sonner";
|
||||
import { Tooltip } from "@base-ui/react/tooltip";
|
||||
|
||||
import { getBetProviders } from "@/api/bet-providers";
|
||||
import { getPlayEffective } from "@/api/play";
|
||||
@@ -34,6 +35,7 @@ import {
|
||||
type DraftLineIssueReason,
|
||||
} from "@/features/hall/hall-bet-rules";
|
||||
import {
|
||||
isFullCoverAmountDivisible,
|
||||
isHighCostSelectionType,
|
||||
resolveSelectionTotalBet,
|
||||
selectionCombinationCount,
|
||||
@@ -1111,6 +1113,18 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
playCode: column.play.play_code,
|
||||
reason,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const comboCount = selectionCombinationCount(row.number, row.selectionType);
|
||||
if (
|
||||
row.selectionType === "full_cover"
|
||||
&& !isFullCoverAmountDivisible(amount, comboCount)
|
||||
) {
|
||||
issues.push({
|
||||
rowNo: rowIndex + 1,
|
||||
playCode: column.play.play_code,
|
||||
reason: "full_cover_amount_not_divisible",
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2257,7 +2271,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<DialogFooter className="gap-2 border-t border-[#eef2f8] px-5 py-4 sm:justify-end">
|
||||
<DialogFooter className="mx-0 mb-0 gap-2 rounded-b-2xl border-t border-[#eef2f8] bg-white px-5 py-4 sm:justify-end">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
@@ -2341,6 +2355,10 @@ const DraftRowItem = memo(function DraftRowItem({
|
||||
}) {
|
||||
const displayNumber = sanitizeNumber(row.number, activeCategory);
|
||||
const comboCount = selectionCombinationCount(displayNumber, row.selectionType);
|
||||
const hasFullCoverAmountError = row.selectionType === "full_cover" && playColumns.some((column) => {
|
||||
const amount = parseDecimalInputToMinor(row.amounts[column.key] ?? "", currencyCode);
|
||||
return amount !== null && amount > 0 && !isFullCoverAmountDivisible(amount, comboCount);
|
||||
});
|
||||
const rowTotalMinor =
|
||||
playColumns.reduce((total, column) => {
|
||||
if (draftLineIssueReason(column.play.play_code, row.number, column.digitSlot) !== null) {
|
||||
@@ -2359,7 +2377,7 @@ const DraftRowItem = memo(function DraftRowItem({
|
||||
>
|
||||
<td
|
||||
className={cn(
|
||||
"sticky left-0 z-20 px-0.5 py-1.5 text-center font-black text-[#17408d] shadow-[2px_0_6px_rgba(15,23,42,0.04)]",
|
||||
"sticky left-0 z-20 align-top px-0.5 py-1.5 text-center font-black text-[#17408d] shadow-[2px_0_6px_rgba(15,23,42,0.04)]",
|
||||
indexColClass,
|
||||
rowActive ? "bg-[#f5f9ff]" : "bg-white",
|
||||
)}
|
||||
@@ -2368,7 +2386,7 @@ const DraftRowItem = memo(function DraftRowItem({
|
||||
</td>
|
||||
<td
|
||||
className={cn(
|
||||
"sticky z-20 px-1 py-1.5 shadow-[2px_0_6px_rgba(15,23,42,0.04)]",
|
||||
"sticky z-20 align-top px-1 py-1.5 shadow-[2px_0_6px_rgba(15,23,42,0.04)]",
|
||||
stickyNumberLeftClass,
|
||||
numberColClass,
|
||||
rowActive ? "bg-[#f5f9ff]" : "bg-white",
|
||||
@@ -2455,7 +2473,7 @@ const DraftRowItem = memo(function DraftRowItem({
|
||||
);
|
||||
})}
|
||||
{showSelectionTypeColumn ? (
|
||||
<td className={cn(selectionTypeColClass, "px-1 py-1.5 text-center", rowActive && "bg-[#f5f9ff]")}>
|
||||
<td className={cn(selectionTypeColClass, "align-top px-1 py-1.5 text-center", rowActive && "bg-[#f5f9ff]")}>
|
||||
<select
|
||||
value={row.selectionType}
|
||||
disabled={tableDisabled}
|
||||
@@ -2470,8 +2488,33 @@ const DraftRowItem = memo(function DraftRowItem({
|
||||
))}
|
||||
</select>
|
||||
{comboCount > 1 && displayNumber.length >= 2 ? (
|
||||
<p className="mt-0.5 text-[9px] font-bold leading-none text-[#0b56b7]">
|
||||
{t("hall.table.comboCount", { count: comboCount })}
|
||||
<div className="mt-0.5 flex items-center justify-center gap-0.5 text-[9px] font-bold leading-none text-[#0b56b7]">
|
||||
<span>{t("hall.table.comboCount", { count: comboCount })}</span>
|
||||
{row.selectionType === "full_cover" || row.selectionType === "half_play" ? (
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger
|
||||
className="inline-flex size-3 items-center justify-center rounded-full text-[#5378b5] outline-none hover:text-[#0b56b7] focus-visible:ring-1 focus-visible:ring-[#0b56b7]"
|
||||
aria-label={t("hall.table.selectionTypeRule")}
|
||||
title={t("hall.table.selectionTypeRule")}
|
||||
>
|
||||
<CircleHelp className="size-3" aria-hidden />
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Positioner side="bottom" sideOffset={6}>
|
||||
<Tooltip.Popup className="z-[70] max-w-52 rounded-md bg-slate-900 px-2 py-1.5 text-left text-[11px] font-medium leading-snug text-white shadow-lg">
|
||||
{row.selectionType === "full_cover"
|
||||
? t("hall.table.fullCoverSplitHint", { count: comboCount })
|
||||
: t("hall.table.halfPlayHint")}
|
||||
</Tooltip.Popup>
|
||||
</Tooltip.Positioner>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{row.selectionType === "full_cover" && comboCount > 1 && hasFullCoverAmountError ? (
|
||||
<p className="mt-0.5 text-[9px] font-medium leading-tight text-red-600">
|
||||
{t("hall.table.fullCoverDivisibilityError", { count: comboCount })}
|
||||
</p>
|
||||
) : null}
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user