diff --git a/src/api/admin-draws.ts b/src/api/admin-draws.ts index e883b30..be94763 100644 --- a/src/api/admin-draws.ts +++ b/src/api/admin-draws.ts @@ -53,6 +53,15 @@ export async function postAdminPublishResultBatch( ); } +export async function deleteAdminPendingResultBatch( + drawId: number, + batchId: number, +): Promise { + return adminRequest.delete( + `${A}/draws/${drawId}/result-batches/${batchId}`, + ); +} + export async function postAdminGenerateDrawPlan(): Promise { return adminRequest.post(`${A}/draws/generate-plan`); } diff --git a/src/i18n/locales/en/config.json b/src/i18n/locales/en/config.json index 1986fd3..a770516 100644 --- a/src/i18n/locales/en/config.json +++ b/src/i18n/locales/en/config.json @@ -177,7 +177,10 @@ "description": "Controls review flow after RNG draw generation, cooldown duration, and automatic settlement behavior. These are global runtime policies and do not belong to versioned operations config.", "loadFailed": "Failed to load system settings", "saveSuccess": "System settings saved", + "saveRuntimeSuccess": "Draw and settlement parameters saved", + "saveFrontendSuccess": "Front-end display settings saved", "saveFailed": "Failed to save system settings", + "unsavedChanges": "Unsaved changes", "frontendConfig": "Front-end configuration", "fields": { "manualReview": "Require manual review for draw results", @@ -211,7 +214,11 @@ }, "discard": "Discard changes", "confirmSaveTitle": "Save system runtime parameters?", - "confirmSaveDescription": "This updates draw review, cooldown, auto settlement/approval/payout, and play-rules display. It may affect site-wide operation." + "confirmSaveDescription": "This updates draw review, cooldown, auto settlement/approval/payout, and play-rules display. It may affect site-wide operation.", + "confirmSaveRuntimeTitle": "Save draw and settlement parameters?", + "confirmSaveRuntimeDescription": "This updates draw review, schedule timing, cooldown, and auto settlement/approval/payout. Play-rules HTML is not changed.", + "confirmSaveFrontendTitle": "Save front-end display settings?", + "confirmSaveFrontendDescription": "This updates play-rules HTML on the player site. Draw and settlement logic are not changed." }, "currencies": { "title": "Currency management", diff --git a/src/i18n/locales/en/draws.json b/src/i18n/locales/en/draws.json index 16c2704..2b5c80b 100644 --- a/src/i18n/locales/en/draws.json +++ b/src/i18n/locales/en/draws.json @@ -135,6 +135,11 @@ "batchId": "Batch ID", "numberCount": "Number count", "reviewAndPublishAction": "Review and publish", + "discardPendingBatch": "Delete draft", + "discardingPendingBatch": "Deleting…", + "discardPendingBatchSuccess": "Pending batch removed. You can re-enter numbers or run RNG.", + "discardPendingBatchFailed": "Delete failed", + "publishReadOnlyHint": "This page is read-only for verification. To change numbers, delete this batch and save a new draft under manual entry.", "noPublishPermission": "No publish permission", "batchNotFound": "Batch not found", "batchNotFoundDesc": "Return to the review list and confirm the batch ID.", @@ -196,6 +201,8 @@ "saveManualDraftDescription": "23 numbers will be saved for review.", "publishTitle": "Confirm publish results?", "publishDescription": "Results become visible to players and may trigger settlement.", + "discardPendingBatchTitle": "Delete pending result batch?", + "discardPendingBatchDescription": "This removes the 23-number draft and returns the draw to closed (awaiting draw). You can enter numbers again or run RNG. Published results are not affected.", "generatePlanTitle": "Confirm generate draw plan?", "generatePlanDescription": "Future bettable draws will be created per system rules." }, diff --git a/src/i18n/locales/ne/config.json b/src/i18n/locales/ne/config.json index 311410a..2610052 100644 --- a/src/i18n/locales/ne/config.json +++ b/src/i18n/locales/ne/config.json @@ -177,7 +177,10 @@ "description": "RNG ड्रअपछि समीक्षा प्रवाह, कूलडाउन अवधि र स्वचालित सेटलमेन्ट व्यवहार नियन्त्रण गर्छ। यी ग्लोबल रनटाइम नीति हुन् र संस्करणयुक्त सञ्चालन कन्फिगरेसनमा पर्दैनन्।", "loadFailed": "प्रणाली सेटिङ लोड असफल भयो", "saveSuccess": "प्रणाली सेटिङ सुरक्षित भयो", + "saveRuntimeSuccess": "ड्रअ र सेटलमेन्ट प्यारामिटर सुरक्षित भयो", + "saveFrontendSuccess": "फ्रन्ट-एन्ड प्रदर्शन सेटिङ सुरक्षित भयो", "saveFailed": "प्रणाली सेटिङ सुरक्षित गर्न असफल", + "unsavedChanges": "नसुरक्षित परिवर्तन छ", "frontendConfig": "फ्रन्ट-एन्ड कन्फिग", "fields": { "manualReview": "ड्रअ परिणामका लागि म्यानुअल समीक्षा चाहिने", @@ -211,7 +214,11 @@ }, "discard": "परिवर्तन त्याग्नुहोस्", "confirmSaveTitle": "प्रणाली रनटाइम प्यारामिटर सुरक्षित गर्ने?", - "confirmSaveDescription": "ड्रअ समीक्षा, कूलडाउन, स्वचालित सेटलमेन्ट/अनुमोदन/पेआउट र खेल नियम प्रदर्शन अद्यावधिक हुन्छ। साइटव्यापी सञ्चालनमा असर पर्न सक्छ।" + "confirmSaveDescription": "ड्रअ समीक्षा, कूलडाउन, स्वचालित सेटलमेन्ट/अनुमोदन/पेआउट र खेल नियम प्रदर्शन अद्यावधिक हुन्छ। साइटव्यापी सञ्चालनमा असर पर्न सक्छ।", + "confirmSaveRuntimeTitle": "ड्रअ र सेटलमेन्ट प्यारामिटर सुरक्षित गर्ने?", + "confirmSaveRuntimeDescription": "ड्रअ समीक्षा, तालिका, कूलडाउन, स्वचालित सेटलमेन्ट/अनुमोदन/पेआउट अद्यावधिक हुन्छ। खेल नियम HTML परिवर्तन हुँदैन।", + "confirmSaveFrontendTitle": "फ्रन्ट-एन्ड प्रदर्शन सेटिङ सुरक्षित गर्ने?", + "confirmSaveFrontendDescription": "खेलाडी साइटको खेल नियम HTML अद्यावधिक हुन्छ। ड्रअ र सेटलमेन्ट तर्क परिवर्तन हुँदैन।" }, "currencies": { "title": "मुद्रा व्यवस्थापन", diff --git a/src/i18n/locales/ne/draws.json b/src/i18n/locales/ne/draws.json index 5886898..64556ec 100644 --- a/src/i18n/locales/ne/draws.json +++ b/src/i18n/locales/ne/draws.json @@ -135,6 +135,11 @@ "batchId": "ब्याच ID", "numberCount": "नम्बर संख्या", "reviewAndPublishAction": "जाँचेर प्रकाशित गर्नुहोस्", + "discardPendingBatch": "ड्राफ्ट मेटाउनुहोस्", + "discardingPendingBatch": "मेटाउँदै…", + "discardPendingBatchSuccess": "पेन्डिङ ब्याच मेटियो। पुनः नम्बर राख्न वा RNG चलाउन सकिन्छ।", + "discardPendingBatchFailed": "मेटाउन असफल", + "publishReadOnlyHint": "यो पृष्ठ केवल जाँचका लागि हो। नम्बर बदल्न पहिले यो ब्याच मेटाउनुहोस् र म्यानुअल प्रविष्टिबाट नयाँ ड्राफ्ट सुरक्षित गर्नुहोस्।", "noPublishPermission": "प्रकाशन अनुमति छैन", "batchNotFound": "ब्याच भेटिएन", "batchNotFoundDesc": "समीक्षा सूचीमा फर्केर batch ID जाँच गर्नुहोस्।", @@ -196,6 +201,8 @@ "saveManualDraftDescription": "२३ नम्बर समीक्षाका लागि सुरक्षित हुनेछ।", "publishTitle": "नतिजा प्रकाशन पुष्टि?", "publishDescription": "खेलाडीहरूले नतिजा देख्नेछन्।", + "discardPendingBatchTitle": "पेन्डिङ नतिजा ब्याच मेटाउने?", + "discardPendingBatchDescription": "२३ नम्बरको ड्राफ्ट मेटिन्छ र ड्रअ «बन्द — नतिजा पर्खँदै» मा फर्किन्छ। पुनः प्रविष्टि वा RNG गर्न सकिन्छ।", "generatePlanTitle": "ड्रअ योजना सिर्जना पुष्टि?", "generatePlanDescription": "भविष्यका ड्रअहरू सिर्जना हुनेछन्।" }, diff --git a/src/i18n/locales/zh/config.json b/src/i18n/locales/zh/config.json index 4910c13..feac2d9 100644 --- a/src/i18n/locales/zh/config.json +++ b/src/i18n/locales/zh/config.json @@ -177,7 +177,10 @@ "description": "用于控制 RNG 开奖后的审核流转、冷静期时长和系统自动结算行为。这些参数属于全局运行策略,不跟随玩法/赔率版本发布。", "loadFailed": "系统设置加载失败", "saveSuccess": "系统设置已保存", + "saveRuntimeSuccess": "开奖与结算参数已保存", + "saveFrontendSuccess": "前端展示配置已保存", "saveFailed": "系统设置保存失败", + "unsavedChanges": "有未保存的更改", "frontendConfig": "前端配置", "fields": { "manualReview": "开奖结果必须人工审核", @@ -211,7 +214,11 @@ }, "discard": "放弃更改", "confirmSaveTitle": "确认保存系统运行参数?", - "confirmSaveDescription": "将更新开奖审核、冷静期、自动结算/审核/派彩及玩法规则展示,可能影响全站运行。" + "confirmSaveDescription": "将更新开奖审核、冷静期、自动结算/审核/派彩及玩法规则展示,可能影响全站运行。", + "confirmSaveRuntimeTitle": "确认保存开奖与结算参数?", + "confirmSaveRuntimeDescription": "将更新开奖审核、期号节奏、冷静期、自动结算/审核/派彩等,不影响玩法规则 HTML。", + "confirmSaveFrontendTitle": "确认保存前端展示配置?", + "confirmSaveFrontendDescription": "将更新玩家端玩法规则页面 HTML,不影响开奖与结算逻辑。" }, "currencies": { "title": "币种管理", diff --git a/src/i18n/locales/zh/draws.json b/src/i18n/locales/zh/draws.json index 12417d6..ae3e44c 100644 --- a/src/i18n/locales/zh/draws.json +++ b/src/i18n/locales/zh/draws.json @@ -135,6 +135,11 @@ "batchId": "批次 ID", "numberCount": "号码条数", "reviewAndPublishAction": "核对并发布", + "discardPendingBatch": "删除草稿", + "discardingPendingBatch": "删除中…", + "discardPendingBatchSuccess": "已删除待确认批次,可重新录入或 RNG", + "discardPendingBatchFailed": "删除失败", + "publishReadOnlyHint": "发布页仅用于核对;若要改号请先删除本批次,回到上方「人工录入」重新保存。", "noPublishPermission": "无发布权限", "batchNotFound": "未找到批次", "batchNotFoundDesc": "请返回审核列表确认 batch id。", @@ -196,6 +201,8 @@ "saveManualDraftDescription": "将写入 23 个开奖号码草稿,提交后进入审核流程。", "publishTitle": "确认发布开奖结果?", "publishDescription": "发布后将对玩家可见并可能触发结算,请再次核对号码。", + "discardPendingBatchTitle": "确认删除待确认批次?", + "discardPendingBatchDescription": "将删除本批次 23 个号码草稿,期号回到「已封盘待开奖」,可重新人工录入或 RNG。已发布的结果不受影响。", "generatePlanTitle": "确认批量生成期号计划?", "generatePlanDescription": "将按系统规则补充未来可下注期号。" }, diff --git a/src/modules/draws/draw-publish-console.tsx b/src/modules/draws/draw-publish-console.tsx index 9aa80d3..84a944d 100644 --- a/src/modules/draws/draw-publish-console.tsx +++ b/src/modules/draws/draw-publish-console.tsx @@ -1,11 +1,16 @@ "use client"; import Link from "next/link"; +import { useRouter } from "next/navigation"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; -import { getAdminDrawResultBatches, postAdminPublishResultBatch } from "@/api/admin-draws"; +import { + deleteAdminPendingResultBatch, + getAdminDrawResultBatches, + postAdminPublishResultBatch, +} from "@/api/admin-draws"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button, buttonVariants } from "@/components/ui/button"; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; @@ -29,6 +34,7 @@ import { PRD_DRAW_RESULT_MANAGE } from "./draw-prd"; export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchId: string }) { const { t } = useTranslation(["draws", "common"]); + const router = useRouter(); const profile = useAdminProfile(); const canManageDraw = adminHasAnyPermission(profile?.permissions, [ PRD_DRAW_RESULT_MANAGE, @@ -39,6 +45,7 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [publishing, setPublishing] = useState(false); + const [discarding, setDiscarding] = useState(false); const { request: requestConfirm, ConfirmDialog } = useConfirmAction(); const load = useCallback(async () => { @@ -71,6 +78,22 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI return data?.batches.find((b) => b.id === batchNum); }, [batchNum, data]); + async function discardBatch(): Promise { + if (!Number.isFinite(idNum) || !Number.isFinite(batchNum)) return; + setDiscarding(true); + try { + await deleteAdminPendingResultBatch(idNum, batchNum); + toast.success(t("discardPendingBatchSuccess")); + router.replace(`/admin/draws/${drawId}/review`); + } catch (e) { + toast.error( + e instanceof LotteryApiBizError ? e.message : t("discardPendingBatchFailed"), + ); + } finally { + setDiscarding(false); + } + } + async function publish(): Promise { if (!Number.isFinite(idNum) || !Number.isFinite(batchNum)) return; setPublishing(true); @@ -139,10 +162,13 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI ) : null} {canPublish ? ( - - {t("checkBeforePublish")} - {t("checkBeforePublishDesc")} - + <> + + {t("checkBeforePublish")} + {t("checkBeforePublishDesc")} + +

{t("publishReadOnlyHint")}

+ ) : null}
@@ -176,16 +202,33 @@ export function DrawPublishConsole({ drawId, batchId }: { drawId: string; batchI })}

- + {t("publishedView")} + {canPublish ? ( + + ) : null}
@@ -517,33 +622,27 @@ export function SystemSettingsScreen() { /> - - - - requestConfirm({ - title: t("system.confirmSaveTitle", { ns: "config" }), - description: t("system.confirmSaveDescription", { ns: "config" }), + title: t("system.confirmSaveFrontendTitle", { ns: "config" }), + description: t("system.confirmSaveFrontendDescription", { ns: "config" }), confirmLabel: t("confirm.confirmSave", { ns: "common" }), - onConfirm: () => handleSave(), + onConfirm: () => handleSaveFrontend(), }) } - onDiscard={() => { - setDraft(saved); - setDirty(false); - }} + onDiscard={() => discardSection(FRONTEND_DRAFT_KEYS)} saveLabel={saveLabel} savingLabel={savingLabel} discardLabel={discardLabel} /> - - + + + );