feat(i18n, draws): 新增“随机填充”翻译并实现随机选号功能

在英文、尼泊尔语与中文语言包中新增 “Fill Randomly(随机填充)” 翻译文案,完善多语言支持。
在 DrawReviewConsole 组件中新增随机选号功能,用户可通过按钮一键填充随机号码。
优化开奖录入流程,减少手动输入操作,提升使用效率与用户体验。
This commit is contained in:
2026-06-01 14:54:53 +08:00
parent a550c418e5
commit d30c135dde
4 changed files with 21 additions and 1 deletions

View File

@@ -126,6 +126,7 @@
"enter23Numbers": "Please enter all 23 groups of 4 digits", "enter23Numbers": "Please enter all 23 groups of 4 digits",
"draftSaved": "Draft v{{version}} saved, waiting to be published", "draftSaved": "Draft v{{version}} saved, waiting to be published",
"saveFailed": "Failed to save", "saveFailed": "Failed to save",
"fillRandomNumbers": "Fill randomly",
"clear": "Clear", "clear": "Clear",
"saveDraft": "Save draft", "saveDraft": "Save draft",
"saving": "Saving…", "saving": "Saving…",

View File

@@ -126,6 +126,7 @@
"enter23Numbers": "कृपया 23 वटा 4-अङ्क समूह पूरा भर्नुहोस्", "enter23Numbers": "कृपया 23 वटा 4-अङ्क समूह पूरा भर्नुहोस्",
"draftSaved": "ड्राफ्ट v{{version}} सुरक्षित भयो, प्रकाशनको प्रतिक्षामा", "draftSaved": "ड्राफ्ट v{{version}} सुरक्षित भयो, प्रकाशनको प्रतिक्षामा",
"saveFailed": "सेभ असफल भयो", "saveFailed": "सेभ असफल भयो",
"fillRandomNumbers": "अनियमित भर्नुहोस्",
"clear": "खाली गर्नुहोस्", "clear": "खाली गर्नुहोस्",
"saveDraft": "ड्राफ्ट सुरक्षित गर्नुहोस्", "saveDraft": "ड्राफ्ट सुरक्षित गर्नुहोस्",
"saving": "सेभ हुँदैछ…", "saving": "सेभ हुँदैछ…",

View File

@@ -126,6 +126,7 @@
"enter23Numbers": "请完整输入 23 组 4 位数字", "enter23Numbers": "请完整输入 23 组 4 位数字",
"draftSaved": "已保存草稿 v{{version}},等待确认发布", "draftSaved": "已保存草稿 v{{version}},等待确认发布",
"saveFailed": "保存失败", "saveFailed": "保存失败",
"fillRandomNumbers": "随机填满",
"clear": "清空", "clear": "清空",
"saveDraft": "保存草稿", "saveDraft": "保存草稿",
"saving": "保存中…", "saving": "保存中…",

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { Rocket } from "lucide-react"; import { Dices, Rocket } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -46,6 +46,10 @@ const RESULT_SLOTS = [
})), })),
] as const; ] as const;
function randomDrawNumber4d(): string {
return String(Math.floor(Math.random() * 10_000)).padStart(4, "0");
}
export function DrawReviewConsole({ drawId }: { drawId: string }) { export function DrawReviewConsole({ drawId }: { drawId: string }) {
const { t } = useTranslation(["draws", "common"]); const { t } = useTranslation(["draws", "common"]);
const profile = useAdminProfile(); const profile = useAdminProfile();
@@ -91,6 +95,10 @@ export function DrawReviewConsole({ drawId }: { drawId: string }) {
data, data,
]); ]);
function fillRandomManualNumbers(): void {
setManualNumbers(RESULT_SLOTS.map(() => randomDrawNumber4d()));
}
async function saveManualDraft(): Promise<void> { async function saveManualDraft(): Promise<void> {
if (!Number.isFinite(idNum)) return; if (!Number.isFinite(idNum)) return;
const invalid = manualNumbers.some((n) => !/^[0-9]{4}$/.test(n)); const invalid = manualNumbers.some((n) => !/^[0-9]{4}$/.test(n));
@@ -163,6 +171,15 @@ export function DrawReviewConsole({ drawId }: { drawId: string }) {
))} ))}
</div> </div>
<div className="flex flex-wrap items-center justify-end gap-2"> <div className="flex flex-wrap items-center justify-end gap-2">
<Button
type="button"
variant="outline"
disabled={!canManageDraw || savingManual}
onClick={fillRandomManualNumbers}
>
<Dices className="size-4" aria-hidden />
{t("fillRandomNumbers")}
</Button>
<Button <Button
type="button" type="button"
variant="outline" variant="outline"