import React, { useState, useEffect } from 'react'; import { Layout, Menu, Button, Table, Space, Form, Input, Select, message, Modal, Card, Spin, Row, Col, Breadcrumb, Avatar, Dropdown, ConfigProvider, theme, Typography, Switch, Badge, Image, Upload, Divider, Descriptions, Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer, InputNumber,ColorPicker, Popover } from 'antd'; import { UploadOutlined, ReloadOutlined, SaveOutlined, BgColorsOutlined } from '@ant-design/icons'; import { debounce } from 'lodash'; import { useQuery, useMutation, useQueryClient, } from '@tanstack/react-query'; import dayjs from 'dayjs'; import weekday from 'dayjs/plugin/weekday'; import localeData from 'dayjs/plugin/localeData'; import 'dayjs/locale/zh-cn'; import type { FileLibrary, FileCategory, KnowInfo, SystemSetting, SystemSettingValue, ColorScheme } from '../share/types.ts'; import { ThemeMode } from '../share/types.ts'; import { SystemSettingGroup, SystemSettingKey, FontSize, CompactMode, AllowedFileType } from '../share/types.ts'; import { getEnumOptions } from './utils.ts'; import { SystemAPI, } from './api.ts'; import { useTheme } from './hooks_sys.tsx'; import { Uploader } from './components_uploader.tsx'; // 配置 dayjs 插件 dayjs.extend(weekday); dayjs.extend(localeData); // 设置 dayjs 语言 dayjs.locale('zh-cn'); const { Title } = Typography; // 分组标题映射 const GROUP_TITLES: Record = { [SystemSettingGroup.BASIC]: '基础设置', [SystemSettingGroup.FEATURE]: '功能设置', [SystemSettingGroup.UPLOAD]: '上传设置', [SystemSettingGroup.NOTIFICATION]: '通知设置' }; // 分组描述映射 const GROUP_DESCRIPTIONS: Record = { [SystemSettingGroup.BASIC]: '配置站点的基本信息', [SystemSettingGroup.FEATURE]: '配置系统功能的开启状态', [SystemSettingGroup.UPLOAD]: '配置文件上传相关的参数', [SystemSettingGroup.NOTIFICATION]: '配置系统通知的触发条件' }; // 定义预设配色方案 - 按明暗模式分组 const COLOR_SCHEMES: Record> = { [ThemeMode.LIGHT]: { DEFAULT: { name: '默认浅色', primary: '#1890ff', background: '#f0f2f5', text: '#000000' }, BLUE: { name: '蓝色', primary: '#096dd9', background: '#e6f7ff', text: '#003a8c' }, GREEN: { name: '绿色', primary: '#52c41a', background: '#f6ffed', text: '#135200' }, WARM: { name: '暖橙', primary: '#fa8c16', background: '#fff7e6', text: '#873800' } }, [ThemeMode.DARK]: { DEFAULT: { name: '默认深色', primary: '#177ddc', background: '#141414', text: '#ffffff' }, MIDNIGHT: { name: '午夜蓝', primary: '#1a3b7a', background: '#0a0a1a', text: '#e0e0e0' }, FOREST: { name: '森林', primary: '#2e7d32', background: '#121212', text: '#e0e0e0' }, SUNSET: { name: '日落', primary: '#f5222d', background: '#1a1a1a', text: '#ffffff' } } }; // 颜色选择器组件 // const ColorPicker: React.FC<{ // value?: string; // onChange?: (color: string) => void; // label?: string; // }> = ({ value = '#1890ff', onChange, label = '选择颜色' }) => { // const [color, setColor] = useState(value); // const [open, setOpen] = useState(false); // // 更新颜色(预览) // const handleColorChange = (e: React.ChangeEvent) => { // const newColor = e.target.value; // setColor(newColor); // }; // // 关闭时确认颜色 // const handleOpenChange = (visible: boolean) => { // if (!visible && color) { // onChange?.(color); // } // setOpen(visible); // }; // return ( // // // // } // > // // // ); // }; // 基础设置页面 export const SettingsPage = () => { const [form] = Form.useForm(); const queryClient = useQueryClient(); const { isDark } = useTheme(); // 获取系统设置 const { data: settingsData, isLoading: isLoadingSettings } = useQuery({ queryKey: ['systemSettings'], queryFn: SystemAPI.getSettings, }); // 更新系统设置 const updateSettingsMutation = useMutation({ mutationFn: (values: Partial[]) => SystemAPI.updateSettings(values), onSuccess: () => { message.success('基础设置已更新'); queryClient.invalidateQueries({ queryKey: ['systemSettings'] }); }, onError: (error) => { message.error('更新基础设置失败'); console.error('更新基础设置失败:', error); }, }); // 重置系统设置 const resetSettingsMutation = useMutation({ mutationFn: SystemAPI.resetSettings, onSuccess: () => { message.success('基础设置已重置'); queryClient.invalidateQueries({ queryKey: ['systemSettings'] }); }, onError: (error) => { message.error('重置基础设置失败'); console.error('重置基础设置失败:', error); }, }); // 初始化表单数据 useEffect(() => { if (settingsData) { const formValues = settingsData.reduce((acc: Record, group) => { group.settings.forEach(setting => { // 根据值的类型进行转换 let value = setting.value; if (typeof value === 'string') { if (value === 'true' || value === 'false') { value = value === 'true'; } else if (!isNaN(Number(value)) && !value.includes('.')) { value = parseInt(value, 10); } else if (setting.key === SystemSettingKey.ALLOWED_FILE_TYPES) { value = (value ? (value as string).split(',') : []) as unknown as string; } } acc[setting.key] = value; }); return acc; }, {}); form.setFieldsValue(formValues); } }, [settingsData, form]); // 处理表单提交 const handleSubmit = async (values: Record) => { const settings = Object.entries(values).map(([key, value]) => ({ key: key as typeof SystemSettingKey[keyof typeof SystemSettingKey], value: String(value), group: key.startsWith('SITE_') ? SystemSettingGroup.BASIC : key.startsWith('ENABLE_') || key.includes('LOGIN_') || key.includes('SESSION_') ? SystemSettingGroup.FEATURE : key.includes('UPLOAD_') || key.includes('FILE_') || key.includes('IMAGE_') ? SystemSettingGroup.UPLOAD : SystemSettingGroup.NOTIFICATION })); updateSettingsMutation.mutate(settings); }; // 处理重置 const handleReset = () => { Modal.confirm({ title: '确认重置', content: '确定要将所有设置重置为默认值吗?此操作不可恢复。', okText: '确认', cancelText: '取消', onOk: () => { resetSettingsMutation.mutate(); }, }); }; // 根据设置类型渲染不同的输入控件 const renderSettingInput = (setting: SystemSetting) => { const value = setting.value; if (typeof value === 'boolean' || value === 'true' || value === 'false') { return ; } if (setting.key === SystemSettingKey.ALLOWED_FILE_TYPES) { return ; }; return (
系统设置 } extra={ } > ({ key: group, label: String(GROUP_TITLES[group]), children: (
{settingsData ?.find(g => g.name === group) ?.settings.map(setting => ( {renderSettingInput(setting)} ))}
) }))} />
); }; // 主题设置页面 export const ThemeSettingsPage = () => { const { isDark, currentTheme, updateTheme, saveTheme, resetTheme } = useTheme(); const [form] = Form.useForm(); const [loading, setLoading] = useState(false); // 处理配色方案选择 const handleColorSchemeChange = (schemeName: string) => { const currentMode = form.getFieldValue('theme_mode') as ThemeMode; const scheme = COLOR_SCHEMES[currentMode][schemeName]; if (!scheme) return; form.setFieldsValue({ primary_color: scheme.primary, background_color: scheme.background, text_color: scheme.text }); updateTheme({ primary_color: scheme.primary, background_color: scheme.background, text_color: scheme.text }); }; // 初始化表单数据 useEffect(() => { form.setFieldsValue({ theme_mode: currentTheme.theme_mode, primary_color: currentTheme.primary_color, background_color: currentTheme.background_color || (isDark ? '#141414' : '#f0f2f5'), font_size: currentTheme.font_size, is_compact: currentTheme.is_compact }); }, [currentTheme, form, isDark]); // 处理表单提交 const handleSubmit = async (values: any) => { try { setLoading(true); await saveTheme(values); } catch (error) { message.error('保存主题设置失败'); } finally { setLoading(false); } }; // 处理重置 const handleReset = async () => { try { setLoading(true); await resetTheme(); } catch (error) { message.error('重置主题设置失败'); } finally { setLoading(false); } }; // 处理表单值变化 - 实时预览 const handleValuesChange = (changedValues: any) => { updateTheme(changedValues); }; return (
主题设置
{/* 配色方案选择 */} {Object.entries(COLOR_SCHEMES[form.getFieldValue('theme_mode') as ThemeMode]).map(([key, scheme]) => ( ))} {/* 主题模式 */} 浅色模式 深色模式 {/* 主题色 */} { form.setFieldValue('primary_color', color.toHexString()); updateTheme({ primary_color: color.toHexString() }); }} allowClear /> {/* 背景色 */} { form.setFieldValue('background_color', color.toHexString()); updateTheme({ background_color: color.toHexString() }); }} allowClear /> {/* 文字颜色 */} { form.setFieldValue('text_color', color.toHexString()); updateTheme({ text_color: color.toHexString() }); }} allowClear /> {/* 圆角大小 */} min={0} max={20} addonAfter="px" /> {/* 字体大小 */} {/* 紧凑模式 */} checked ? CompactMode.COMPACT : CompactMode.NORMAL} getValueProps={(value: CompactMode) => ({ checked: value === CompactMode.COMPACT })} > {/* 操作按钮 */}
); };