hyapp-admin-platform/ops-center/src/components/LuckyGiftPoolAdjustmentDialog.jsx

133 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 TextField from "@mui/material/TextField";
import { useState } from "react";
import { Button } from "@/shared/ui/Button.jsx";
import { formatNumber } from "../format.js";
export function LuckyGiftPoolAdjustmentDialog({ adjustmentId, direction, onClose, onSubmit, pool, submitting }) {
const [amount, setAmount] = useState("");
const [reason, setReason] = useState("");
const [errors, setErrors] = useState({});
const debit = direction === "out";
const appCode = pool.app_code;
const poolID = pool.pool_id;
const strategyVersion = pool.strategy_version;
const availableBalance = Number(pool.available_balance || 0);
const title = debit ? "扣减奖池水位" : "添加奖池水位";
const submit = (event) => {
event.preventDefault();
const nextErrors = validateAdjustment({ amount, availableBalance, debit, reason });
setErrors(nextErrors);
if (Object.keys(nextErrors).length) {
return;
}
// adjustmentId 在打开弹窗时创建,此处只原样透传。请求失败后组件不会卸载,因此用户修正或直接重试时
// 仍使用同一幂等键,网络超时场景不会把已成功的资金动作重复执行。
onSubmit({
adjustmentId,
amountCoins: Number(amount),
appCode,
direction,
poolId: poolID,
reason: reason.trim(),
strategyVersion,
});
};
return (
<Dialog
fullWidth
maxWidth="sm"
open
aria-labelledby="lucky-pool-adjustment-title"
onClose={submitting ? undefined : onClose}
>
<form className="ops-pool-adjustment-form" onSubmit={submit}>
<DialogTitle id="lucky-pool-adjustment-title">{title}</DialogTitle>
<DialogContent dividers className="ops-pool-adjustment-content">
<div className="ops-config-metrics ops-pool-adjustment-metrics">
<PoolMetric label="应用" value={appCode} />
<PoolMetric label="奖池" value={poolID} />
<PoolMetric label="策略" value={strategyVersion} />
<PoolMetric label="当前余额" value={formatNumber(pool.balance)} />
<PoolMetric label="保底线" value={formatNumber(pool.reserve_floor)} />
<PoolMetric label="可用余额" value={formatNumber(availableBalance)} />
</div>
{pool.materialized === false ? (
<div className="ops-pool-adjustment-note" role="status">
当前为默认水位提交后将物化为独立策略奖池
</div>
) : null}
<TextField
autoFocus
disabled={submitting}
error={Boolean(errors.amount)}
fullWidth
helperText={errors.amount || (debit ? `最多可扣减 ${formatNumber(availableBalance)} 金币` : "")}
label="调整金币"
required
slotProps={{ htmlInput: { inputMode: "numeric", pattern: "[0-9]*" } }}
value={amount}
onChange={(event) => {
setAmount(event.target.value);
setErrors((current) => ({ ...current, amount: "" }));
}}
/>
<TextField
disabled={submitting}
error={Boolean(errors.reason)}
fullWidth
helperText={errors.reason}
label="调整原因"
multiline
required
rows={3}
slotProps={{ htmlInput: { maxLength: 255 } }}
value={reason}
onChange={(event) => {
setReason(event.target.value);
setErrors((current) => ({ ...current, reason: "" }));
}}
/>
</DialogContent>
<DialogActions>
<Button disabled={submitting} onClick={onClose}>
取消
</Button>
<Button disabled={submitting} type="submit" variant={debit ? "danger" : "primary"}>
{debit ? "确认扣减" : "确认添加"}
</Button>
</DialogActions>
</form>
</Dialog>
);
}
function PoolMetric({ label, value }) {
return (
<div className="ops-config-metric">
<span>{label}</span>
<strong>{value || "-"}</strong>
</div>
);
}
function validateAdjustment({ amount, availableBalance, debit, reason }) {
const errors = {};
const rawAmount = String(amount || "").trim();
if (!/^[1-9]\d*$/.test(rawAmount) || !Number.isSafeInteger(Number(rawAmount))) {
errors.amount = "请输入大于 0 的整数金币数量";
} else if (debit && Number(rawAmount) > availableBalance) {
errors.amount = `扣减不能超过可用余额 ${formatNumber(availableBalance)}`;
}
if (!String(reason || "").trim()) {
errors.reason = "请输入调整原因";
}
return errors;
}