'use client'; import { useState, useEffect, useMemo } from 'react'; import { SiteHeader, PageInfo } from '@/components/site-header'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@nice/ui/components/card'; import { Button } from '@nice/ui/components/button'; import { Input } from '@nice/ui/components/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@nice/ui/components/select'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@nice/ui/components/form'; import { useForm, useFieldArray } from 'react-hook-form'; import { IconPlus, IconTrash, IconHome, IconSettings, IconUsers, IconPhoto, IconHeart, IconSearch, IconMail, IconCalendar, IconBell } from '@tabler/icons-react'; import { SystemConfigGroup } from '@fenghuo/common/enum'; import { useSysConf } from '@fenghuo/client'; import { toast } from '@nice/ui/components/sonner'; import { useTRPC } from '@fenghuo/client'; import { useQuery } from '@tanstack/react-query'; import { useSetPageInfo } from '@/components/providers/dashboard-provider'; // 数据类型定义 interface NavItem { id: string; name: string; url: string; icon: string; } interface NavigationConfig { items: Array<{ id: string; name: string; url: string; }>; } interface SystemConfigForm { coverPoster: { url: string; }; navigation: NavigationConfig; navItems: NavItem[]; bannerImages: Array<{ id: string; url: string; }>; sidebarPosters: Array<{ id: string; url: string; }>; } // 可用图标选项 const iconOptions = [ { value: 'Home', label: '首页', icon: IconHome }, { value: 'Settings', label: '设置', icon: IconSettings }, { value: 'Users', label: '用户', icon: IconUsers }, { value: 'FileImage', label: '图片', icon: IconPhoto }, { value: 'Heart', label: '收藏', icon: IconHeart }, { value: 'Search', label: '搜索', icon: IconSearch }, { value: 'Mail', label: '邮件', icon: IconMail }, { value: 'Calendar', label: '日历', icon: IconCalendar }, { value: 'Bell', label: '通知', icon: IconBell }, ]; export default function ConfigPage() { const trpc = useTRPC(); const { setValue } = useSysConf(); const [isLoading, setIsLoading] = useState({ [SystemConfigGroup.COVER_POSTER]: false, [SystemConfigGroup.BANNER_IMAGES]: false, [SystemConfigGroup.SIDEBAR_POSTERS]: false, [SystemConfigGroup.NAVIGATION]: false, [SystemConfigGroup.NAV_ITEMS]: false, }); useSetPageInfo({ title: '系统配置', subtitle: '配置系统参数', }) // 使用 tRPC 获取各个配置 const { data: coverPosterData, isLoading: coverPosterLoading } = useQuery({ ...trpc.system_config.getValue.queryOptions({ key: SystemConfigGroup.COVER_POSTER }), }) as { data: { url: string } | null | undefined; isLoading: boolean }; const { data: navigationData, isLoading: navigationLoading } = useQuery({ ...trpc.system_config.getValue.queryOptions({ key: SystemConfigGroup.NAVIGATION }), }) as { data: NavigationConfig | null | undefined; isLoading: boolean }; const { data: navItemsData, isLoading: navItemsLoading } = useQuery({ ...trpc.system_config.getValue.queryOptions({ key: SystemConfigGroup.NAV_ITEMS }), }) as { data: NavItem[] | null | undefined; isLoading: boolean }; const { data: bannerImagesData, isLoading: bannerImagesLoading } = useQuery({ ...trpc.system_config.getValue.queryOptions({ key: SystemConfigGroup.BANNER_IMAGES }), }) as { data: Array<{ id: string; url: string }> | null | undefined; isLoading: boolean }; const { data: sidebarPostersData, isLoading: sidebarPostersLoading } = useQuery({ ...trpc.system_config.getValue.queryOptions({ key: SystemConfigGroup.SIDEBAR_POSTERS }), }) as { data: Array<{ id: string; url: string }> | null | undefined; isLoading: boolean }; // 计算最终的表单数据 const finalFormData = useMemo(() => { return { coverPoster: coverPosterData || { url: '' }, navigation: navigationData || { items: [] }, navItems: navItemsData || [], bannerImages: bannerImagesData || [], sidebarPosters: sidebarPostersData || [], }; }, [coverPosterData, navigationData, navItemsData, bannerImagesData, sidebarPostersData]); // 检查所有数据是否已加载完成 const allDataLoaded = !coverPosterLoading && !navigationLoading && !navItemsLoading && !bannerImagesLoading && !sidebarPostersLoading; const form = useForm({ defaultValues: finalFormData }); // 当数据更新时重置表单 useEffect(() => { if (allDataLoaded) { form.reset(finalFormData); } }, [allDataLoaded, finalFormData, form]); const handleSaveSection = async (section: SystemConfigGroup) => { setIsLoading(prev => ({ ...prev, [section]: true })); try { const formData = form.getValues(); let sectionData; switch (section) { case SystemConfigGroup.COVER_POSTER: sectionData = formData.coverPoster; break; case SystemConfigGroup.BANNER_IMAGES: sectionData = formData.bannerImages; break; case SystemConfigGroup.SIDEBAR_POSTERS: sectionData = formData.sidebarPosters; break; case SystemConfigGroup.NAVIGATION: sectionData = formData.navigation; break; case SystemConfigGroup.NAV_ITEMS: sectionData = formData.navItems; break; default: throw new Error(`未知的配置分组: ${section}`); } // 使用 setValue 保存配置 await setValue.mutateAsync({ key: section, // 使用 SystemConfigGroup 枚举值作为唯一 key value: sectionData, // 当前对象数据 type: 'json', // 类型设置为 json description: undefined, // 可选:添加描述信息 group: section, // 分组设置为对应的 SystemConfigGroup isPublic: true // 设置为公开配置 }); toast.success(`配置保存成功`); console.log(`${section} 配置保存成功`); } catch (error) { console.error(`保存 ${section} 配置失败:`, error); toast.error(`保存配置失败: ${error}`); } finally { setIsLoading(prev => ({ ...prev, [section]: false })); } }; // 检查是否仍在加载 const isDataLoading = !allDataLoaded; if (isDataLoading) { return (

正在加载配置数据...

); } // 只有在数据加载完成后才渲染表单内容 return (
); } // 独立的表单内容组件,在数据加载完成后才会挂载 function ConfigFormContent({ form, handleSaveSection, isLoading }: { form: any; handleSaveSection: (section: SystemConfigGroup) => Promise; isLoading: Record; }) { // useFieldArray 在这里初始化,此时表单数据已经是最终数据 const { fields: navigationFields, append: appendNavigation, remove: removeNavigation } = useFieldArray({ control: form.control, name: 'navigation.items', }); const { fields: navItemFields, append: appendNavItem, remove: removeNavItem } = useFieldArray({ control: form.control, name: 'navItems', }); const { fields: sidebarFields, append: appendSidebar, remove: removeSidebar } = useFieldArray({ control: form.control, name: 'sidebarPosters', }); const { fields: bannerFields, append: appendBanner, remove: removeBanner } = useFieldArray({ control: form.control, name: 'bannerImages', }); return (
{/* 左列 */}
{/* 封面海报配置 */} 封面海报配置 配置网站主页的封面海报图片
( 图片URL )} />
{/* 横幅图片配置 */} 横幅图片配置 配置页面顶部的横幅广告图片
{bannerFields.map((field, index) => (
( 图片URL
)} />
))}
{/* 侧边海报配置 */} 侧边海报配置 配置侧边栏的推广海报图片
{sidebarFields.map((field, index) => (
( 图片URL
)} />
))}
{/* 右列 */}
{/* 导航栏配置 */} 导航栏配置 配置顶部导航栏的菜单项
{navigationFields.map((field, index) => (
( 菜单名称 )} /> ( 跳转URL )} />
))}
{/* 导航项配置 */} 导航项配置 配置侧边栏或应用内的导航项目
{navItemFields.map((field, index) => (
( 项目名称 )} /> ( 跳转URL )} /> ( 图标 )} />
))}
); }