2026-06-07 14:45:51 +08:00

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,
};
}