refactor: 优化配置与奖池页面多语言编辑及管理端列表布局
This commit is contained in:
@@ -150,149 +150,158 @@ export function JackpotPoolsConsole({ embedded = false }: JackpotPoolsConsolePro
|
||||
}
|
||||
};
|
||||
|
||||
const body = (
|
||||
<Card className={embedded ? "border-border/60 shadow-none" : undefined}>
|
||||
{!embedded ? (
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">{t("configTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
const poolList = (
|
||||
<div className={embedded ? "space-y-4" : "space-y-8"}>
|
||||
{loading ? <p className="text-muted-foreground text-sm">{t("states.loading", { ns: "common" })}</p> : null}
|
||||
{!loading && items.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">{t("noPoolData")}</p>
|
||||
) : null}
|
||||
<CardContent className="space-y-8">
|
||||
{loading ? <p className="text-muted-foreground text-sm">{t("states.loading", { ns: "common" })}</p> : null}
|
||||
{!loading && items.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">{t("noPoolData")}</p>
|
||||
) : null}
|
||||
{items.map((p) => {
|
||||
const d = drafts[p.id] ?? toDraft(p);
|
||||
return (
|
||||
<div key={p.id} className="space-y-4 rounded-lg border border-border p-4">
|
||||
<h3 className="font-mono text-sm font-semibold">{p.currency_code}</h3>
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`amt-${p.id}`}>{t("currentAmount")}</Label>
|
||||
<Input
|
||||
id={`amt-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.current_amount}
|
||||
onChange={(e) => updateDraft(p.id, { current_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`cr-${p.id}`}>{t("contributionRate")}</Label>
|
||||
<Input
|
||||
id={`cr-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.contribution_rate}
|
||||
onChange={(e) => updateDraft(p.id, { contribution_rate: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`th-${p.id}`}>{t("triggerThreshold")}</Label>
|
||||
<Input
|
||||
id={`th-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.trigger_threshold}
|
||||
onChange={(e) => updateDraft(p.id, { trigger_threshold: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`pr-${p.id}`}>{t("payoutRate")}</Label>
|
||||
<Input
|
||||
id={`pr-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.payout_rate}
|
||||
onChange={(e) => updateDraft(p.id, { payout_rate: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`gap-${p.id}`}>{t("forceTriggerGap")}</Label>
|
||||
<Input
|
||||
id={`gap-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.force_trigger_draw_gap}
|
||||
onChange={(e) => updateDraft(p.id, { force_trigger_draw_gap: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`min-${p.id}`}>{t("minBetAmount")}</Label>
|
||||
<Input
|
||||
id={`min-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.min_bet_amount}
|
||||
onChange={(e) => updateDraft(p.id, { min_bet_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`combo-${p.id}`}>{t("comboTriggerPlays")}</Label>
|
||||
<Input
|
||||
id={`combo-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.combo_trigger_play_codes}
|
||||
placeholder="straight,ibox"
|
||||
onChange={(e) => updateDraft(p.id, { combo_trigger_play_codes: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label>{t("status")}</Label>
|
||||
<Select
|
||||
value={d.status}
|
||||
onValueChange={(v) => updateDraft(p.id, { status: v ?? "0" })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue>{d.status === "1" ? t("enabled") : t("disabled")}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="0">{t("disabled")}</SelectItem>
|
||||
<SelectItem value="1">{t("enabled")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<Button type="button" disabled={savingId === p.id} onClick={() => void save(p)}>
|
||||
{savingId === p.id ? t("saving") : t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="rounded-md border border-amber-200 bg-amber-50 p-3">
|
||||
<div className="grid gap-3 sm:grid-cols-[1fr_1fr_auto] sm:items-end">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`burst-draw-${p.id}`}>{t("manualBurstDrawId")}</Label>
|
||||
<Input
|
||||
id={`burst-draw-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.manual_burst_draw_id}
|
||||
onChange={(e) => updateDraft(p.id, { manual_burst_draw_id: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`burst-amount-${p.id}`}>{t("manualBurstAmount")}</Label>
|
||||
<Input
|
||||
id={`burst-amount-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.manual_burst_amount}
|
||||
onChange={(e) => updateDraft(p.id, { manual_burst_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
disabled={burstingId === p.id}
|
||||
onClick={() => void manualBurst(p)}
|
||||
>
|
||||
{burstingId === p.id ? t("processing") : t("manualBurst")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{items.map((p) => {
|
||||
const d = drafts[p.id] ?? toDraft(p);
|
||||
return (
|
||||
<div
|
||||
key={p.id}
|
||||
className="space-y-4 rounded-xl border border-border/60 bg-muted/10 p-4"
|
||||
>
|
||||
<h3 className="font-mono text-sm font-semibold">{p.currency_code}</h3>
|
||||
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`amt-${p.id}`}>{t("currentAmount")}</Label>
|
||||
<Input
|
||||
id={`amt-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.current_amount}
|
||||
onChange={(e) => updateDraft(p.id, { current_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`cr-${p.id}`}>{t("contributionRate")}</Label>
|
||||
<Input
|
||||
id={`cr-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.contribution_rate}
|
||||
onChange={(e) => updateDraft(p.id, { contribution_rate: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`th-${p.id}`}>{t("triggerThreshold")}</Label>
|
||||
<Input
|
||||
id={`th-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.trigger_threshold}
|
||||
onChange={(e) => updateDraft(p.id, { trigger_threshold: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`pr-${p.id}`}>{t("payoutRate")}</Label>
|
||||
<Input
|
||||
id={`pr-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.payout_rate}
|
||||
onChange={(e) => updateDraft(p.id, { payout_rate: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`gap-${p.id}`}>{t("forceTriggerGap")}</Label>
|
||||
<Input
|
||||
id={`gap-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.force_trigger_draw_gap}
|
||||
onChange={(e) => updateDraft(p.id, { force_trigger_draw_gap: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`min-${p.id}`}>{t("minBetAmount")}</Label>
|
||||
<Input
|
||||
id={`min-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.min_bet_amount}
|
||||
onChange={(e) => updateDraft(p.id, { min_bet_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`combo-${p.id}`}>{t("comboTriggerPlays")}</Label>
|
||||
<Input
|
||||
id={`combo-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.combo_trigger_play_codes}
|
||||
placeholder="straight,ibox"
|
||||
onChange={(e) => updateDraft(p.id, { combo_trigger_play_codes: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor={`status-${p.id}`}>{t("status")}</Label>
|
||||
<Select
|
||||
value={d.status}
|
||||
onValueChange={(v) => updateDraft(p.id, { status: v ?? "0" })}
|
||||
>
|
||||
<SelectTrigger id={`status-${p.id}`} className="w-full">
|
||||
<SelectValue>{d.status === "1" ? t("enabled") : t("disabled")}</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="0">{t("disabled")}</SelectItem>
|
||||
<SelectItem value="1">{t("enabled")}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end border-t border-border/60 pt-3">
|
||||
<Button type="button" disabled={savingId === p.id} onClick={() => void save(p)}>
|
||||
{savingId === p.id ? t("saving") : t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="rounded-lg border border-amber-200/80 bg-amber-50/80 p-4 dark:border-amber-900/50 dark:bg-amber-950/30">
|
||||
<p className="mb-3 text-xs font-medium text-amber-900 dark:text-amber-200">
|
||||
{t("manualBurst")}
|
||||
</p>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-end">
|
||||
<div className="min-w-0 flex-1 space-y-1.5 sm:max-w-xs">
|
||||
<Label htmlFor={`burst-draw-${p.id}`}>{t("manualBurstDrawId")}</Label>
|
||||
<Input
|
||||
id={`burst-draw-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.manual_burst_draw_id}
|
||||
onChange={(e) => updateDraft(p.id, { manual_burst_draw_id: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 space-y-1.5 sm:max-w-xs">
|
||||
<Label htmlFor={`burst-amount-${p.id}`}>{t("manualBurstAmount")}</Label>
|
||||
<Input
|
||||
id={`burst-amount-${p.id}`}
|
||||
className="font-mono"
|
||||
value={d.manual_burst_amount}
|
||||
onChange={(e) => updateDraft(p.id, { manual_burst_amount: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
className="shrink-0 sm:ml-auto"
|
||||
disabled={burstingId === p.id}
|
||||
onClick={() => void manualBurst(p)}
|
||||
>
|
||||
{burstingId === p.id ? t("processing") : t("manualBurst")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (embedded) {
|
||||
return body;
|
||||
return poolList;
|
||||
}
|
||||
|
||||
return <ModuleScaffold>{body}</ModuleScaffold>;
|
||||
return (
|
||||
<ModuleScaffold>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">{t("configTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>{poolList}</CardContent>
|
||||
</Card>
|
||||
</ModuleScaffold>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user