191 lines
6.3 KiB
JavaScript
191 lines
6.3 KiB
JavaScript
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { listResourceGroups } from "@/features/resources/api";
|
|
import {
|
|
getCumulativeRechargeRewardConfig,
|
|
listCumulativeRechargeRewardGrants,
|
|
updateCumulativeRechargeRewardConfig,
|
|
} from "@/features/cumulative-recharge-reward/api";
|
|
import { useCumulativeRechargeRewardAbilities } from "@/features/cumulative-recharge-reward/permissions.js";
|
|
import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js";
|
|
import { useToast } from "@/shared/ui/ToastProvider.jsx";
|
|
|
|
const pageSize = 50;
|
|
const emptyGrants = { items: [], page: 1, pageSize, total: 0 };
|
|
|
|
const emptyForm = {
|
|
enabled: false,
|
|
tiers: [],
|
|
};
|
|
|
|
export function useCumulativeRechargeRewardPage() {
|
|
const abilities = useCumulativeRechargeRewardAbilities();
|
|
const { showToast } = useToast();
|
|
const [config, setConfig] = useState(null);
|
|
const [configDrawerOpen, setConfigDrawerOpen] = useState(false);
|
|
const [form, setForm] = useState(emptyForm);
|
|
const [configLoading, setConfigLoading] = useState(false);
|
|
const [configSaving, setConfigSaving] = useState(false);
|
|
const [resourceGroups, setResourceGroups] = useState([]);
|
|
const [query, setQuery] = useState("");
|
|
const [cycleKey, setCycleKey] = useState("");
|
|
const [status, setStatus] = useState("");
|
|
const [page, setPage] = useState(1);
|
|
const filters = useMemo(() => ({ keyword: query, cycle_key: cycleKey, status }), [cycleKey, query, status]);
|
|
const {
|
|
data: grants = emptyGrants,
|
|
error: grantsError,
|
|
loading: grantsLoading,
|
|
reload: reloadGrants,
|
|
} = usePaginatedQuery({
|
|
errorMessage: "加载累充奖励记录失败",
|
|
fetcher: listCumulativeRechargeRewardGrants,
|
|
filters,
|
|
page,
|
|
pageSize,
|
|
queryKey: ["cumulative-recharge-reward-grants", filters, page],
|
|
});
|
|
|
|
const reloadConfig = useCallback(async () => {
|
|
setConfigLoading(true);
|
|
try {
|
|
const [config, groups] = await Promise.all([
|
|
getCumulativeRechargeRewardConfig(),
|
|
listResourceGroups({ page: 1, page_size: 100, status: "active" }),
|
|
]);
|
|
setConfig(config);
|
|
setForm(formFromConfig(config));
|
|
setResourceGroups(groups.items || []);
|
|
} catch (err) {
|
|
showToast(err.message || "加载累充奖励配置失败", "error");
|
|
} finally {
|
|
setConfigLoading(false);
|
|
}
|
|
}, [showToast]);
|
|
|
|
useEffect(() => {
|
|
void reloadConfig();
|
|
}, [reloadConfig]);
|
|
|
|
const openConfigDrawer = useCallback(() => {
|
|
setForm(config ? formFromConfig(config) : emptyForm);
|
|
setConfigDrawerOpen(true);
|
|
}, [config]);
|
|
|
|
const closeConfigDrawer = useCallback(() => {
|
|
setConfigDrawerOpen(false);
|
|
setForm(config ? formFromConfig(config) : emptyForm);
|
|
}, [config]);
|
|
|
|
const changeQuery = (value) => {
|
|
setQuery(value);
|
|
setPage(1);
|
|
};
|
|
|
|
const changeCycleKey = (value) => {
|
|
setCycleKey(value);
|
|
setPage(1);
|
|
};
|
|
|
|
const changeStatus = (value) => {
|
|
setStatus(value);
|
|
setPage(1);
|
|
};
|
|
|
|
const submitConfig = async (event) => {
|
|
event.preventDefault();
|
|
if (!abilities.canUpdate) {
|
|
return;
|
|
}
|
|
setConfigSaving(true);
|
|
try {
|
|
const saved = await updateCumulativeRechargeRewardConfig(payloadFromForm(form));
|
|
setConfig(saved);
|
|
setForm(formFromConfig(saved));
|
|
setConfigDrawerOpen(false);
|
|
showToast("累充奖励配置已保存", "success");
|
|
await reloadGrants();
|
|
} catch (err) {
|
|
showToast(err.message || "保存累充奖励配置失败", "error");
|
|
} finally {
|
|
setConfigSaving(false);
|
|
}
|
|
};
|
|
|
|
return {
|
|
abilities,
|
|
changeCycleKey,
|
|
changeQuery,
|
|
changeStatus,
|
|
closeConfigDrawer,
|
|
config,
|
|
configDrawerOpen,
|
|
configLoading,
|
|
configSaving,
|
|
cycleKey,
|
|
form,
|
|
grants,
|
|
grantsError,
|
|
grantsLoading,
|
|
openConfigDrawer,
|
|
page,
|
|
query,
|
|
reloadConfig,
|
|
reloadGrants,
|
|
resourceGroups,
|
|
setForm,
|
|
setPage,
|
|
status,
|
|
submitConfig,
|
|
};
|
|
}
|
|
|
|
function formFromConfig(config) {
|
|
return {
|
|
enabled: Boolean(config.enabled),
|
|
tiers: (config.tiers || []).map((tier) => ({
|
|
tierId: tier.tierId || 0,
|
|
tierCode: tier.tierCode || "",
|
|
tierName: tier.tierName || "",
|
|
thresholdUsd: tier.thresholdUsdMinor ? String((tier.thresholdUsdMinor / 100).toFixed(2)) : "",
|
|
resourceGroupId: tier.resourceGroupId ? String(tier.resourceGroupId) : "",
|
|
status: tier.status || "active",
|
|
sortOrder: String(tier.sortOrder || 0),
|
|
})),
|
|
};
|
|
}
|
|
|
|
function payloadFromForm(form) {
|
|
const tiers = (form.tiers || []).map((tier, index) => {
|
|
const thresholdUsdMinor = Math.round(Number(tier.thresholdUsd || 0) * 100);
|
|
const resourceGroupId = Number(tier.resourceGroupId || 0);
|
|
if (thresholdUsdMinor <= 0) {
|
|
throw new Error("充值 USD 金额必须大于 0");
|
|
}
|
|
if (resourceGroupId <= 0) {
|
|
throw new Error("请选择资源组");
|
|
}
|
|
const existingTier = Number(tier.tierId || 0) > 0;
|
|
const tierCode = String(tier.tierCode || "").trim() || `cumulative_recharge_${Date.now()}_${index + 1}`;
|
|
const tierName =
|
|
existingTier && String(tier.tierName || "").trim()
|
|
? String(tier.tierName).trim()
|
|
: `累充 ${(thresholdUsdMinor / 100).toFixed(2)} USD`;
|
|
return {
|
|
tier_id: Number(tier.tierId || 0),
|
|
tier_code: tierCode,
|
|
tier_name: tierName,
|
|
threshold_usd_minor: thresholdUsdMinor,
|
|
resource_group_id: resourceGroupId,
|
|
status: tier.status === "inactive" ? "inactive" : "active",
|
|
sort_order: index,
|
|
};
|
|
});
|
|
if (form.enabled && tiers.filter((tier) => tier.status === "active").length === 0) {
|
|
throw new Error("开启后至少需要一个启用档位");
|
|
}
|
|
return {
|
|
enabled: Boolean(form.enabled),
|
|
tiers,
|
|
};
|
|
}
|