refactor: 合并多语言支持的显示名称字段,优化奖池手动爆发功能的返回数据结构,增强管理端权限控制
This commit is contained in:
@@ -11,10 +11,10 @@ import {
|
||||
postAdminCurrency,
|
||||
putAdminCurrency,
|
||||
} from "@/api/admin-currencies";
|
||||
import { AdminPageCard } from "@/components/admin/admin-page-card";
|
||||
import { AdminStatusBadge } from "@/components/admin/admin-status-badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { AdminTableExportButton } from "@/components/admin/admin-table-export-button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -204,16 +204,21 @@ export function CurrencySettingsPanel() {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="admin-list-card">
|
||||
<CardHeader className="admin-list-header flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<CardTitle className="admin-list-title">{t("currencies.title", { ns: "config" })}</CardTitle>
|
||||
<div className="flex items-center gap-2">
|
||||
<AdminTableExportButton tableId="admin-currencies-table" filename={exportLabels.filename}
|
||||
sheetName={exportLabels.sheetName} />
|
||||
<Button onClick={openCreate}>{t("currencies.actions.create", { ns: "config" })}</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="admin-list-content">
|
||||
<>
|
||||
<AdminPageCard
|
||||
title={t("currencies.title", { ns: "config" })}
|
||||
description={t("currencies.description", { ns: "config" })}
|
||||
actions={
|
||||
<>
|
||||
<AdminTableExportButton
|
||||
tableId="admin-currencies-table"
|
||||
filename={exportLabels.filename}
|
||||
sheetName={exportLabels.sheetName}
|
||||
/>
|
||||
<Button onClick={openCreate}>{t("currencies.actions.create", { ns: "config" })}</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="admin-table-shell">
|
||||
<Table id="admin-currencies-table">
|
||||
<TableHeader>
|
||||
@@ -277,7 +282,7 @@ export function CurrencySettingsPanel() {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</AdminPageCard>
|
||||
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent showCloseButton className="sm:max-w-md">
|
||||
@@ -385,6 +390,6 @@ export function CurrencySettingsPanel() {
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,11 @@ import {
|
||||
getAdminSettings,
|
||||
updateAdminSetting,
|
||||
} from "@/api/admin-settings";
|
||||
import { AdminPageCard } from "@/components/admin/admin-page-card";
|
||||
import { useConfirmAction } from "@/hooks/use-confirm-action";
|
||||
import { WalletConfigDocScreen } from "@/modules/config/doc/wallet-config-doc-screen";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
@@ -23,6 +26,8 @@ const DRAW_KEYS = {
|
||||
REQUIRE_MANUAL_REVIEW: "draw.require_manual_review",
|
||||
COOLDOWN_MINUTES: "draw.cooldown_minutes",
|
||||
AUTO_SETTLEMENT: "settlement.auto_run_on_tick",
|
||||
AUTO_APPROVE: "settlement.auto_approve_on_tick",
|
||||
AUTO_PAYOUT: "settlement.auto_payout_on_tick",
|
||||
} as const;
|
||||
|
||||
const FRONTEND_GROUP = "frontend";
|
||||
@@ -37,6 +42,8 @@ interface RuntimeDraft {
|
||||
requireManualReview: boolean;
|
||||
cooldownMinutes: string;
|
||||
autoSettlement: boolean;
|
||||
autoApprove: boolean;
|
||||
autoPayout: boolean;
|
||||
playRulesHtmlZh: string;
|
||||
playRulesHtmlEn: string;
|
||||
playRulesHtmlNe: string;
|
||||
@@ -116,10 +123,13 @@ function SaveActions({
|
||||
|
||||
export function SystemSettingsScreen() {
|
||||
const { t } = useTranslation(["common", "config", "adminUsers"]);
|
||||
const { request: requestConfirm, ConfirmDialog } = useConfirmAction();
|
||||
const [draft, setDraft] = useState<RuntimeDraft>({
|
||||
requireManualReview: false,
|
||||
cooldownMinutes: "15",
|
||||
autoSettlement: true,
|
||||
autoApprove: true,
|
||||
autoPayout: true,
|
||||
playRulesHtmlZh: "",
|
||||
playRulesHtmlEn: "",
|
||||
playRulesHtmlNe: "",
|
||||
@@ -128,6 +138,8 @@ export function SystemSettingsScreen() {
|
||||
requireManualReview: false,
|
||||
cooldownMinutes: "15",
|
||||
autoSettlement: true,
|
||||
autoApprove: true,
|
||||
autoPayout: true,
|
||||
playRulesHtmlZh: "",
|
||||
playRulesHtmlEn: "",
|
||||
playRulesHtmlNe: "",
|
||||
@@ -155,6 +167,8 @@ export function SystemSettingsScreen() {
|
||||
requireManualReview: Boolean(kv[DRAW_KEYS.REQUIRE_MANUAL_REVIEW] ?? false),
|
||||
cooldownMinutes: String(kv[DRAW_KEYS.COOLDOWN_MINUTES] ?? 15),
|
||||
autoSettlement: Boolean(kv[DRAW_KEYS.AUTO_SETTLEMENT] ?? true),
|
||||
autoApprove: Boolean(kv[DRAW_KEYS.AUTO_APPROVE] ?? true),
|
||||
autoPayout: Boolean(kv[DRAW_KEYS.AUTO_PAYOUT] ?? true),
|
||||
playRulesHtmlZh: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_ZH] ?? legacyHtml),
|
||||
playRulesHtmlEn: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_EN] ?? ""),
|
||||
playRulesHtmlNe: String(kv[FRONTEND_KEYS.PLAY_RULES_HTML_NE] ?? ""),
|
||||
@@ -189,6 +203,8 @@ export function SystemSettingsScreen() {
|
||||
Math.max(0, Number.parseInt(draft.cooldownMinutes || "0", 10) || 0),
|
||||
);
|
||||
await updateAdminSetting(DRAW_KEYS.AUTO_SETTLEMENT, draft.autoSettlement);
|
||||
await updateAdminSetting(DRAW_KEYS.AUTO_APPROVE, draft.autoApprove);
|
||||
await updateAdminSetting(DRAW_KEYS.AUTO_PAYOUT, draft.autoPayout);
|
||||
await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_ZH, draft.playRulesHtmlZh);
|
||||
await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_EN, draft.playRulesHtmlEn);
|
||||
await updateAdminSetting(FRONTEND_KEYS.PLAY_RULES_HTML_NE, draft.playRulesHtmlNe);
|
||||
@@ -210,12 +226,11 @@ export function SystemSettingsScreen() {
|
||||
const discardLabel = t("system.discard", { ns: "config" });
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-10">
|
||||
<section className="space-y-4">
|
||||
<h2 className="border-b border-border/60 pb-3 text-base font-semibold text-foreground">
|
||||
{t("system.title", { ns: "config" })}
|
||||
</h2>
|
||||
|
||||
<div className="flex w-full max-w-none flex-col gap-6">
|
||||
<AdminPageCard
|
||||
title={t("system.title", { ns: "config" })}
|
||||
description={t("system.description", { ns: "config" })}
|
||||
>
|
||||
<div className="space-y-5">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<Label className="text-sm font-medium">{t("system.fields.manualReview", { ns: "config" })}</Label>
|
||||
@@ -243,6 +258,32 @@ export function SystemSettingsScreen() {
|
||||
|
||||
<div className="h-px bg-border/60" />
|
||||
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<Label className="text-sm font-medium">{t("system.fields.autoApprove", { ns: "config" })}</Label>
|
||||
<BinaryChoice
|
||||
active={draft.autoApprove}
|
||||
disabled={loading || saving}
|
||||
onChange={(value) => updateDraft("autoApprove", value)}
|
||||
leftLabel={t("system.states.disabled", { ns: "config" })}
|
||||
rightLabel={t("system.states.enabled", { ns: "config" })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="h-px bg-border/60" />
|
||||
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<Label className="text-sm font-medium">{t("system.fields.autoPayout", { ns: "config" })}</Label>
|
||||
<BinaryChoice
|
||||
active={draft.autoPayout}
|
||||
disabled={loading || saving}
|
||||
onChange={(value) => updateDraft("autoPayout", value)}
|
||||
leftLabel={t("system.states.disabled", { ns: "config" })}
|
||||
rightLabel={t("system.states.enabled", { ns: "config" })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="h-px bg-border/60" />
|
||||
|
||||
<div className="grid max-w-xs gap-2">
|
||||
<Label htmlFor="cooldown-minutes" className="text-sm font-medium">
|
||||
{t("system.fields.cooldownMinutes", { ns: "config" })}
|
||||
@@ -258,21 +299,16 @@ export function SystemSettingsScreen() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AdminPageCard>
|
||||
|
||||
</section>
|
||||
|
||||
<section className="space-y-4">
|
||||
<h2 className="border-b border-border/60 pb-3 text-base font-semibold text-foreground">
|
||||
{t("wallet.title", { ns: "config" })}
|
||||
</h2>
|
||||
<AdminPageCard
|
||||
title={t("wallet.title", { ns: "config" })}
|
||||
description={t("wallet.description", { ns: "config" })}
|
||||
>
|
||||
<WalletConfigDocScreen embedded />
|
||||
</section>
|
||||
|
||||
<section className="space-y-4">
|
||||
<h2 className="border-b border-border/60 pb-3 text-base font-semibold text-foreground">
|
||||
{t("system.frontendConfig", { ns: "config" })}
|
||||
</h2>
|
||||
</AdminPageCard>
|
||||
|
||||
<AdminPageCard title={t("system.frontendConfig", { ns: "config" })}>
|
||||
<div className="grid gap-2">
|
||||
<Label className="text-sm font-medium">
|
||||
{t("system.fields.playRulesHtml", { ns: "config" })}
|
||||
@@ -318,22 +354,33 @@ export function SystemSettingsScreen() {
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</AdminPageCard>
|
||||
|
||||
</section>
|
||||
|
||||
<SaveActions
|
||||
dirty={dirty}
|
||||
loading={loading}
|
||||
saving={saving}
|
||||
onSave={() => void handleSave()}
|
||||
onDiscard={() => {
|
||||
setDraft(saved);
|
||||
setDirty(false);
|
||||
}}
|
||||
saveLabel={saveLabel}
|
||||
savingLabel={savingLabel}
|
||||
discardLabel={discardLabel}
|
||||
/>
|
||||
<Card className="admin-list-card">
|
||||
<CardContent className="admin-list-content">
|
||||
<SaveActions
|
||||
dirty={dirty}
|
||||
loading={loading}
|
||||
saving={saving}
|
||||
onSave={() =>
|
||||
requestConfirm({
|
||||
title: t("system.confirmSaveTitle", { ns: "config" }),
|
||||
description: t("system.confirmSaveDescription", { ns: "config" }),
|
||||
confirmLabel: t("confirm.confirmSave", { ns: "common" }),
|
||||
onConfirm: () => handleSave(),
|
||||
})
|
||||
}
|
||||
onDiscard={() => {
|
||||
setDraft(saved);
|
||||
setDirty(false);
|
||||
}}
|
||||
saveLabel={saveLabel}
|
||||
savingLabel={savingLabel}
|
||||
discardLabel={discardLabel}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<ConfirmDialog />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user