import Dialog from "@mui/material/Dialog"; import DialogActions from "@mui/material/DialogActions"; import DialogContent from "@mui/material/DialogContent"; import DialogTitle from "@mui/material/DialogTitle"; import { useEffect, useMemo, useRef, useState } from "react"; import { Button } from "@/shared/ui/Button.jsx"; import { applyDynamicStrategyDefaults, configToForm, correctAllStageProbabilities, formToConfig, nextStageMultiplier, stageSummary, validateLuckyGiftForm, } from "../configForm.js"; import { formatNumber, formatPercent } from "../format.js"; import { LuckyGiftConfigSections } from "./LuckyGiftConfigSections.jsx"; import { LuckyGiftStageDesigner } from "./LuckyGiftStageDesigner.jsx"; export function LuckyGiftConfigDialog({ appOptions = [], config, mode = "edit", onClose, onSubmit, saving }) { const [form, setForm] = useState(() => configToForm(config)); const [activeStage, setActiveStage] = useState("novice"); const [validationErrors, setValidationErrors] = useState([]); const validationRef = useRef(null); const stageSummaries = useMemo(() => form.stages.map((stage) => stageSummary(stage, form)), [form]); const activeStageKey = form.stages.some((stage) => stage.stage === activeStage) ? activeStage : form.stages[0]?.stage; const activeStageConfig = form.stages.find((stage) => stage.stage === activeStageKey); const activeSummary = stageSummaries.find((summary) => summary.stageKey === activeStageKey); useEffect(() => { if (!validationErrors.length) return; // 保存按钮位于固定底栏;失败后把焦点送回错误摘要,避免键盘或读屏用户停留在无变化的按钮上。 validationRef.current?.focus(); }, [validationErrors]); const updateField = (field, value) => { setValidationErrors([]); setForm((current) => { const next = { ...current, [field]: value }; if (field === "strategy_version" && value === "dynamic_v3" && current.strategy_version !== "dynamic_v3") { return applyDynamicStrategyDefaults(next); } // 目标 RTP 决定各奖档概率的闭合解,改动后全部阶段重算,避免展示的概率和将要发布的值不一致。 return field === "target_rtp_percent" ? correctAllStageProbabilities(next) : next; }); }; const updateStageField = (stageKey, field, value) => { setValidationErrors([]); setForm((current) => ({ ...current, stages: current.stages.map((stage) => (stage.stage === stageKey ? { ...stage, [field]: value } : stage)), })); }; const updateStageTier = (stageKey, tierIndex, patch) => { setValidationErrors([]); setForm((current) => correctAllStageProbabilities({ ...current, stages: current.stages.map((stage) => stage.stage === stageKey ? { ...stage, tiers: stage.tiers.map((tier, index) => index === tierIndex ? { ...tier, ...patch } : tier, ), } : stage, ), }), ); }; const addStageTier = (stageKey) => { setValidationErrors([]); setForm((current) => correctAllStageProbabilities({ ...current, stages: current.stages.map((stage) => stage.stage === stageKey ? { ...stage, tiers: [ ...stage.tiers, { enabled: true, // 10 倍以上属于高倍档,默认只在奖池高水位时开放,防止新档位直接击穿保底线。 highWaterOnly: nextStageMultiplier(stage.tiers) >= 10, multiplier: String(nextStageMultiplier(stage.tiers)), probabilityPercent: "0", tierId: "", }, ], } : stage, ), }), ); }; const removeStageTier = (stageKey, tierIndex) => { setValidationErrors([]); setForm((current) => correctAllStageProbabilities({ ...current, stages: current.stages.map((stage) => stage.stage === stageKey ? { ...stage, tiers: stage.tiers.filter((_, index) => index !== tierIndex) } : stage, ), }), ); }; const handleSubmit = (event) => { event.preventDefault(); const errors = validateLuckyGiftForm(form); if (errors.length) { setValidationErrors(errors); return; } onSubmit(formToConfig(config, form)); }; const isCreate = mode === "create"; const title = isCreate ? "添加幸运礼物配置" : config.is_default ? "发布幸运礼物配置" : "新增幸运礼物版本"; return ( ); } function ConfigMetric({ label, value }) { return (