137 lines
5.6 KiB
JavaScript
137 lines
5.6 KiB
JavaScript
import AddOutlined from "@mui/icons-material/AddOutlined";
|
|
import EditOutlined from "@mui/icons-material/EditOutlined";
|
|
import RefreshOutlined from "@mui/icons-material/RefreshOutlined";
|
|
import MenuItem from "@mui/material/MenuItem";
|
|
import TextField from "@mui/material/TextField";
|
|
import { AdminActionIconButton } from "@/shared/ui/AdminListLayout.jsx";
|
|
import { Button } from "@/shared/ui/Button.jsx";
|
|
import { TimeText } from "@/shared/ui/TimeText.jsx";
|
|
import { stageOptions } from "@/features/lucky-gift/constants.js";
|
|
import { formFromConfig } from "@/features/lucky-gift/configModel.js";
|
|
import styles from "@/features/lucky-gift/lucky-gift.module.css";
|
|
|
|
export function LuckyGiftConfigSummary({
|
|
canUpdate,
|
|
config,
|
|
configLoading,
|
|
onAddPool,
|
|
onEdit,
|
|
onPoolChange,
|
|
onRefresh,
|
|
poolId,
|
|
poolOptions,
|
|
}) {
|
|
const form = formFromConfig(config);
|
|
|
|
return (
|
|
<section className={styles.summaryPanel}>
|
|
<div className={styles.summaryScrollArea}>
|
|
<div className={styles.summaryContent}>
|
|
<div className={styles.summaryHeader}>
|
|
<span className={styles.title}>幸运礼物配置</span>
|
|
<span className={styles.meta}>奖池 {poolId}</span>
|
|
</div>
|
|
<div className={styles.summaryItems}>
|
|
<ConfigStatus config={config} loading={configLoading} />
|
|
<SummaryItem label="RTP">{formatPercent(config?.targetRTPPercent)}</SummaryItem>
|
|
<SummaryItem label="入池">{formatPercent(config?.poolRatePercent)}</SummaryItem>
|
|
<SummaryItem label="窗口">{formatNumber(config?.settlementWindowWager)}</SummaryItem>
|
|
<SummaryItem label="波动">{formatPercent(config?.controlBandPercent)}</SummaryItem>
|
|
<SummaryItem label="参考价格">{formatNumber(config?.giftPriceReference)}</SummaryItem>
|
|
<SummaryItem label="新手等价抽">{formatNumber(config?.noviceMaxEquivalentDraws)}</SummaryItem>
|
|
<SummaryItem label="正常等价抽">{formatNumber(config?.normalMaxEquivalentDraws)}</SummaryItem>
|
|
<SummaryItem label="单次上限">{formatNumber(config?.maxSinglePayout)}</SummaryItem>
|
|
<SummaryItem label="房间小时">{formatNumber(config?.roomHourlyPayoutCap)}</SummaryItem>
|
|
<SummaryItem label="阶段">{formatStages(form.stages)}</SummaryItem>
|
|
<SummaryItem label="更新时间">
|
|
{config?.createdAtMs ? <TimeText value={config.createdAtMs} /> : configLoading ? "加载中" : "-"}
|
|
</SummaryItem>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className={styles.summaryActions}>
|
|
<TextField
|
|
select
|
|
className={styles.poolSelector}
|
|
disabled={configLoading}
|
|
label="奖池 ID"
|
|
value={poolId}
|
|
onChange={(event) => onPoolChange(event.target.value)}
|
|
>
|
|
{(poolOptions || [poolId]).map((option) => (
|
|
<MenuItem key={option} value={option}>
|
|
{option}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
<AdminActionIconButton disabled={configLoading || !canUpdate} label="添加奖池" type="button" onClick={onAddPool}>
|
|
<AddOutlined fontSize="small" />
|
|
</AdminActionIconButton>
|
|
<AdminActionIconButton disabled={configLoading} label="刷新配置" type="button" onClick={onRefresh}>
|
|
<RefreshOutlined fontSize="small" />
|
|
</AdminActionIconButton>
|
|
<Button
|
|
disabled={!canUpdate || configLoading}
|
|
startIcon={<EditOutlined fontSize="small" />}
|
|
type="button"
|
|
variant="primary"
|
|
onClick={onEdit}
|
|
>
|
|
编辑配置
|
|
</Button>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function formatStages(stages) {
|
|
if (!Array.isArray(stages) || stages.length === 0) {
|
|
return "-";
|
|
}
|
|
return stageOptions
|
|
.map(([stageKey, stageLabel]) => {
|
|
const stage = stages.find((item) => item.stage === stageKey);
|
|
return `${stageLabel} ${stage?.tiers?.length || 0}`;
|
|
})
|
|
.join(" / ");
|
|
}
|
|
|
|
function SummaryItem({ children, label }) {
|
|
return (
|
|
<div className={styles.summaryItem}>
|
|
<span className={styles.summaryLabel}>{label}</span>
|
|
<span className={styles.summaryValue}>{children}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ConfigStatus({ config, loading }) {
|
|
return (
|
|
<span
|
|
className={[
|
|
"status-badge",
|
|
config?.enabled ? "status-badge--running" : loading ? "status-badge--warning" : "status-badge--stopped",
|
|
].join(" ")}
|
|
>
|
|
<span className="status-point" />
|
|
{config?.enabled ? "已开启" : loading ? "加载中" : "已关闭"}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
function formatPercent(value) {
|
|
const number = Number(value || 0);
|
|
if (!number) {
|
|
return "-";
|
|
}
|
|
return `${number.toFixed(2).replace(/\.?0+$/, "")}%`;
|
|
}
|
|
|
|
function formatNumber(value) {
|
|
const number = Number(value || 0);
|
|
if (!number) {
|
|
return "-";
|
|
}
|
|
return new Intl.NumberFormat("zh-CN").format(number);
|
|
}
|