refactor(hall): 优化投注格子行数与号码输入逻辑
Some checks failed
lotteryfront CI / build (push) Has been cancelled

- 引入默认草稿行数常量及批量生成草稿行函数
- 根据玩法类别调整号码最大输入长度和清洗规则
- 更新号码输入组件以适应动态最大长度和格式规范
- 修正相关回调依赖,确保玩法类别变更时生效
- 改善行状态、占位符和样式传递,增强代码可读性

feat(results): 添加多提供商开奖结果切换功能

- 新增状态管理并展示多提供商按钮切换激活项
- 根据选中的提供商动态展示对应开奖结果数据
- 细化UI显示,支持多提供商名称并列渲染

feat(results): 在结果列表中显示多提供商名称

- 当存在多个提供商结果时展示其名称或代码
- 改善界面信息丰富度,方便用户辨识来源

feat(wallet): 支持账期还款释额类型的流水显示

- 调整账期流水类型文案,精准反映释额含义
- 引入账期时区参数以支持多时区时间格式化
- 自定义信用盘账期释额流水的颜色和文案显示
- 在流水明细和列表中根据时区格式化展示时间

feat(wallet): 支持钱包账期账单区间时区格式化

- 允许传入账期时区参数格式化账单区间时间
- 在账期账单区间显示组件中显示对应时区格式
- 根据玩家配置自动获取并传递账期时区信息
- 条件渲染中信用盘区块支持账期时区参数传递

chore(i18n): 更新中文钱包模块多处文案

- 新增“释额 {{amount}}”等账期释额相关文案
- 修改“账期收款”为“账期还款释额”以符合业务描述

refactor(types): 扩展开奖结果支持多提供商结构

- 新增DrawResultProviderRow类型定义以描述提供商结果
- 在DrawResultListItem中增加provider_results字段支持多结果
- 在玩家信息类型中新增settlement_timezone字段表示账期时区
This commit is contained in:
2026-07-09 15:48:36 +08:00
parent 4a6f021304
commit 56ba12fbfc
8 changed files with 173 additions and 43 deletions

View File

@@ -150,6 +150,11 @@ const D4_PLAY_ORDER = [
"digit_small",
] as const;
const MOBILE_QUICK_AMOUNT_PRESETS = ["10", "50", "100"] as const;
const DEFAULT_DRAFT_ROW_COUNT = 20;
function newDraftRows(count = DEFAULT_DRAFT_ROW_COUNT): DraftRow[] {
return Array.from({ length: count }, newDraftRow);
}
function newDraftRow(): DraftRow {
const id =
@@ -215,8 +220,18 @@ function playColumnsForCategory(
});
}
function sanitizeNumber(raw: string): string {
return raw.replace(/[^0-9Rr]/g, "").toUpperCase().slice(0, 4);
function numberMaxCharsForCategory(category: PlayHallCategory): number {
return category === "D2" ? 2 : category === "D3" ? 3 : 4;
}
function sanitizeNumber(raw: string, category: PlayHallCategory): string {
const normalized =
category === "D4"
? raw.replace(/[^0-9Rr]/g, "").toUpperCase()
: raw.replace(/\D/g, "");
const maxChars = numberMaxCharsForCategory(category);
return category === "D4" ? normalized.slice(0, maxChars) : normalized.slice(-maxChars);
}
function sanitizeAmount(raw: string): string {
@@ -439,7 +454,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
const creditMode = isCreditFundingPlayer(usePlayerSessionStore((state) => state.profile));
const isMobile = useIsMobile();
const [rows, setRows] = useState<DraftRow[]>(() => Array.from({ length: 20 }, newDraftRow));
const [rows, setRows] = useState<DraftRow[]>(() => newDraftRows());
const [activeRowId, setActiveRowId] = useState<string | null>(null);
const [catalogState, setCatalogState] = useState<
| { kind: "loading" }
@@ -642,15 +657,16 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
const sealedBetUi = Boolean(display && isHallSealedCountdownUi(display.status));
const numberPlaceholder =
activeCategory === "D2" ? "00" : activeCategory === "D3" ? "000" : "0000";
const numberMaxChars = numberMaxCharsForCategory(activeCategory);
const updateRowNumber = useCallback((id: string, value: string) => {
setRows((current) =>
current.map((row) =>
row.id === id ? { ...row, number: sanitizeNumber(value) } : row,
row.id === id ? { ...row, number: sanitizeNumber(value, activeCategory) } : row,
),
);
setActiveRowId(id);
}, []);
}, [activeCategory]);
const updateAmount = useCallback((rowId: string, playCode: string, value: string) => {
setRows((current) =>
@@ -1151,7 +1167,7 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
setPreviewData(null);
setResultData(data);
setResultOpen(true);
setRows([newDraftRow()]);
setRows(newDraftRows());
setActiveRowId(null);
triggerWalletPollingAfterBet();
void refreshWallet();
@@ -1752,6 +1768,8 @@ export function HallBettingGrid({ drawLive }: { drawLive: HallDrawLiveSnapshot }
rowActive={activeRowId === row.id}
tableDisabled={tableDisabled}
numberPlaceholder={numberPlaceholder}
activeCategory={activeCategory}
numberMaxChars={numberMaxChars}
playColumns={playColumns}
alertRows={alertRows}
liveSoldOutNumbers={liveSoldOutNumbers}
@@ -1905,6 +1923,8 @@ const DraftRowItem = memo(function DraftRowItem({
rowActive,
tableDisabled,
numberPlaceholder,
activeCategory,
numberMaxChars,
playColumns,
alertRows,
liveSoldOutNumbers,
@@ -1919,16 +1939,18 @@ const DraftRowItem = memo(function DraftRowItem({
indexColClass,
numberColClass,
stickyNumberLeftClass,
}: {
row: DraftRow;
index: number;
rowActive: boolean;
tableDisabled: boolean;
numberPlaceholder: string;
playColumns: PlayColumn[];
alertRows: DrawCurrentRiskPoolAlert[];
liveSoldOutNumbers: Set<string>;
liveWarningNumbers: Set<string>;
}: {
row: DraftRow;
index: number;
rowActive: boolean;
tableDisabled: boolean;
numberPlaceholder: string;
activeCategory: PlayHallCategory;
numberMaxChars: number;
playColumns: PlayColumn[];
alertRows: DrawCurrentRiskPoolAlert[];
liveSoldOutNumbers: Set<string>;
liveWarningNumbers: Set<string>;
updateRowNumber: (id: string, value: string) => void;
updateAmount: (rowId: string, playCode: string, value: string) => void;
setActiveRowId: (id: string) => void;
@@ -1937,10 +1959,12 @@ const DraftRowItem = memo(function DraftRowItem({
isMobile: boolean;
removable: boolean;
indexColClass: string;
numberColClass: string;
stickyNumberLeftClass: string;
}) {
return (
numberColClass: string;
stickyNumberLeftClass: string;
}) {
const displayNumber = sanitizeNumber(row.number, activeCategory);
return (
<tr
className={cn(
"border-b border-[#f0f3f8] last:border-b-0",
@@ -1964,13 +1988,14 @@ const DraftRowItem = memo(function DraftRowItem({
rowActive ? "bg-[#f5f9ff]" : "bg-white",
)}
>
<Input
value={row.number}
disabled={tableDisabled}
inputMode="numeric"
pattern="[0-9Rr]*"
autoComplete="off"
placeholder={numberPlaceholder}
<Input
value={displayNumber}
disabled={tableDisabled}
inputMode="numeric"
pattern="[0-9Rr]*"
autoComplete="off"
placeholder={numberPlaceholder}
maxLength={numberMaxChars}
onFocus={() => setActiveRowId(row.id)}
onClick={() => setActiveRowId(row.id)}
onChange={(event) => updateRowNumber(row.id, event.target.value)}