diff --git a/app/(admin)/settings/admin-settings-client.tsx b/app/(admin)/settings/admin-settings-client.tsx index 9e4cd0c6d..f1253ac09 100644 --- a/app/(admin)/settings/admin-settings-client.tsx +++ b/app/(admin)/settings/admin-settings-client.tsx @@ -70,6 +70,8 @@ import { Switch } from "@/components/ui/switch"; import { defaultMembershipConfig, defaultMembershipUserOverrides, + type MembershipFaqItem, + type MembershipPlanConfig, normalizeMembershipConfig, normalizeMembershipUserOverrides, } from "@/lib/membership/config"; @@ -440,12 +442,9 @@ export function AdminSettingsClient() { membershipConfig: defaultMembershipConfig, membershipUserOverrides: defaultMembershipUserOverrides, }); - const [membershipConfigDraft, setMembershipConfigDraft] = useState( - JSON.stringify(defaultMembershipConfig, null, 2) - ); - const [membershipOverridesDraft, setMembershipOverridesDraft] = useState( - JSON.stringify(defaultMembershipUserOverrides, null, 2) - ); + const [newOverrideUserId, setNewOverrideUserId] = useState(""); + const [newOverrideEmail, setNewOverrideEmail] = useState(""); + const [newOverridePlanId, setNewOverridePlanId] = useState(""); useEffect(() => { if (siteSettingsData) { @@ -513,8 +512,6 @@ export function AdminSettingsClient() { membershipConfig: normalizedMembershipConfig, membershipUserOverrides: normalizedMembershipOverrides, }); - setMembershipConfigDraft(JSON.stringify(normalizedMembershipConfig, null, 2)); - setMembershipOverridesDraft(JSON.stringify(normalizedMembershipOverrides, null, 2)); } }, [siteSettingsData]); @@ -1037,26 +1034,10 @@ export function AdminSettingsClient() { // --- 网站设置逻辑 --- const handleSaveSiteSettings = async () => { try { - let parsedMembershipConfig: ReturnType; - let parsedMembershipOverrides: ReturnType; - - try { - parsedMembershipConfig = normalizeMembershipConfig( - JSON.parse(membershipConfigDraft) - ); - } catch { - toast.error("会员配置 JSON 格式错误,请检查后再保存"); - return; - } - - try { - parsedMembershipOverrides = normalizeMembershipUserOverrides( - JSON.parse(membershipOverridesDraft) - ); - } catch { - toast.error("会员用户覆盖 JSON 格式错误,请检查后再保存"); - return; - } + const parsedMembershipConfig = normalizeMembershipConfig(siteSettings.membershipConfig); + const parsedMembershipOverrides = normalizeMembershipUserOverrides( + siteSettings.membershipUserOverrides + ); const parsedPointsPackages = normalizePointsPackages(siteSettings.pointsPackages); @@ -1074,8 +1055,6 @@ export function AdminSettingsClient() { }); if (!response.ok) throw new Error("保存失败"); setSiteSettings(payload); - setMembershipConfigDraft(JSON.stringify(parsedMembershipConfig, null, 2)); - setMembershipOverridesDraft(JSON.stringify(parsedMembershipOverrides, null, 2)); toast.success("网站设置保存成功"); mutateSiteSettings(); } catch (error) { @@ -1120,6 +1099,165 @@ export function AdminSettingsClient() { }); }; + const updateMembershipConfigState = ( + updater: (config: ReturnType) => ReturnType + ) => { + setSiteSettings((prev) => ({ + ...prev, + membershipConfig: updater(prev.membershipConfig), + })); + }; + + const updateMembershipOverridesState = ( + updater: ( + overrides: ReturnType + ) => ReturnType + ) => { + setSiteSettings((prev) => ({ + ...prev, + membershipUserOverrides: updater(prev.membershipUserOverrides), + })); + }; + + const updateMembershipPlan = ( + index: number, + updater: (plan: MembershipPlanConfig) => MembershipPlanConfig + ) => { + updateMembershipConfigState((config) => { + const plans = [...config.plans]; + if (!plans[index]) return config; + plans[index] = updater(plans[index]); + return { ...config, plans }; + }); + }; + + const addMembershipPlan = () => { + updateMembershipConfigState((config) => { + const nextIndex = config.plans.length + 1; + const id = `plan-${Date.now()}`; + const plans = [ + ...config.plans, + { + id, + name: `套餐${nextIndex}`, + monthlyPrice: 0, + annualPrice: 0, + monthlyCredits: 0, + dailyFreeCredits: 0, + features: [], + }, + ]; + return { + ...config, + plans, + defaultPlanId: config.defaultPlanId || id, + }; + }); + }; + + const removeMembershipPlan = (index: number) => { + updateMembershipConfigState((config) => { + if (config.plans.length <= 1) { + toast.error("至少保留一个会员套餐"); + return config; + } + + const target = config.plans[index]; + if (!target) return config; + + const plans = [...config.plans]; + plans.splice(index, 1); + const nextDefaultPlanId = + config.defaultPlanId === target.id ? plans[0]?.id || config.defaultPlanId : config.defaultPlanId; + + return { + ...config, + plans, + defaultPlanId: nextDefaultPlanId, + }; + }); + }; + + const updateMembershipFaq = ( + index: number, + updater: (faq: MembershipFaqItem) => MembershipFaqItem + ) => { + updateMembershipConfigState((config) => { + const faqs = [...config.faqs]; + if (!faqs[index]) return config; + faqs[index] = updater(faqs[index]); + return { ...config, faqs }; + }); + }; + + const addMembershipFaq = () => { + updateMembershipConfigState((config) => ({ + ...config, + faqs: [...config.faqs, { question: "", answer: "" }], + })); + }; + + const removeMembershipFaq = (index: number) => { + updateMembershipConfigState((config) => { + if (config.faqs.length <= 1) { + toast.error("至少保留一条 FAQ"); + return config; + } + const faqs = [...config.faqs]; + faqs.splice(index, 1); + return { ...config, faqs }; + }); + }; + + const addMembershipOverride = (kind: "id" | "email") => { + const key = kind === "id" ? newOverrideUserId.trim() : newOverrideEmail.trim().toLowerCase(); + const planId = newOverridePlanId.trim(); + + if (!key || !planId) { + toast.error("请先填写标识并选择套餐"); + return; + } + + updateMembershipOverridesState((overrides) => { + if (kind === "id") { + return { + ...overrides, + userPlansById: { + ...overrides.userPlansById, + [key]: planId, + }, + }; + } + + return { + ...overrides, + userPlansByEmail: { + ...overrides.userPlansByEmail, + [key]: planId, + }, + }; + }); + + if (kind === "id") { + setNewOverrideUserId(""); + } else { + setNewOverrideEmail(""); + } + }; + + const removeMembershipOverride = (kind: "id" | "email", key: string) => { + updateMembershipOverridesState((overrides) => { + if (kind === "id") { + const next = { ...overrides.userPlansById }; + delete next[key]; + return { ...overrides, userPlansById: next }; + } + const next = { ...overrides.userPlansByEmail }; + delete next[key]; + return { ...overrides, userPlansByEmail: next }; + }); + }; + // --- 抠图API配置逻辑 --- const handleSaveRmbgConfig = async () => { try { @@ -2949,37 +3087,387 @@ export function AdminSettingsClient() { variant="outline" size="sm" onClick={() => { - setMembershipConfigDraft(JSON.stringify(defaultMembershipConfig, null, 2)); - setMembershipOverridesDraft( - JSON.stringify(defaultMembershipUserOverrides, null, 2) - ); + setSiteSettings({ + ...siteSettings, + membershipConfig: defaultMembershipConfig, + membershipUserOverrides: defaultMembershipUserOverrides, + }); toast.success("已恢复会员配置默认模板"); }} > 恢复默认模板 -
- -