2025-12-29 16:10:42 +08:00
|
|
|
|
import React, { useState, useEffect } from 'react';
|
2026-02-10 11:04:01 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Form,
|
|
|
|
|
|
Input,
|
|
|
|
|
|
Switch,
|
|
|
|
|
|
Button,
|
|
|
|
|
|
Card,
|
|
|
|
|
|
Space,
|
|
|
|
|
|
message,
|
|
|
|
|
|
Modal,
|
|
|
|
|
|
Tag,
|
|
|
|
|
|
Divider,
|
|
|
|
|
|
Descriptions,
|
|
|
|
|
|
Alert,
|
2026-02-12 14:36:33 +08:00
|
|
|
|
Row,
|
|
|
|
|
|
Col,
|
|
|
|
|
|
Typography,
|
|
|
|
|
|
Badge,
|
|
|
|
|
|
Tooltip,
|
2026-02-12 15:10:24 +08:00
|
|
|
|
Avatar,
|
2026-03-06 15:41:07 +08:00
|
|
|
|
ColorPicker,
|
2026-06-12 14:16:29 +08:00
|
|
|
|
InputNumber,
|
2026-02-10 11:04:01 +08:00
|
|
|
|
} from 'antd';
|
|
|
|
|
|
import {
|
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
|
GlobalOutlined,
|
|
|
|
|
|
BgColorsOutlined,
|
|
|
|
|
|
InfoCircleOutlined,
|
|
|
|
|
|
ExclamationCircleOutlined,
|
2026-02-12 14:36:33 +08:00
|
|
|
|
LockOutlined,
|
|
|
|
|
|
DatabaseOutlined,
|
2026-06-12 14:16:29 +08:00
|
|
|
|
CloudServerOutlined,
|
2026-02-12 14:36:33 +08:00
|
|
|
|
MailOutlined,
|
|
|
|
|
|
PhoneOutlined,
|
|
|
|
|
|
EnvironmentOutlined,
|
|
|
|
|
|
FileTextOutlined,
|
|
|
|
|
|
SafetyCertificateOutlined,
|
|
|
|
|
|
ReloadOutlined,
|
|
|
|
|
|
SaveOutlined,
|
2026-06-12 14:16:29 +08:00
|
|
|
|
EyeOutlined,
|
2026-02-12 15:10:24 +08:00
|
|
|
|
MenuFoldOutlined,
|
|
|
|
|
|
MenuUnfoldOutlined,
|
2026-02-10 11:04:01 +08:00
|
|
|
|
} from '@ant-design/icons';
|
2025-12-29 16:10:42 +08:00
|
|
|
|
import axios from 'axios';
|
2026-05-08 11:17:29 +08:00
|
|
|
|
import { useConfig } from '../hooks/useConfig';
|
2025-12-29 16:10:42 +08:00
|
|
|
|
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const { Title, Text, Paragraph } = Typography;
|
2025-12-29 16:10:42 +08:00
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 系统设置页面
|
|
|
|
|
|
* 3个Tab:基本设置、外观设置、关于系统
|
|
|
|
|
|
*/
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const SystemSettings = () => {
|
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
|
|
const [settings, setSettings] = useState({});
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const [activeMenu, setActiveMenu] = useState('general');
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const [systemInfo, setSystemInfo] = useState(null);
|
|
|
|
|
|
const [form] = Form.useForm();
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
|
2026-01-21 10:40:30 +08:00
|
|
|
|
const { reloadConfig } = useConfig();
|
2025-12-29 16:10:42 +08:00
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
fetchSettings();
|
|
|
|
|
|
fetchSystemInfo();
|
2026-03-27 19:12:16 +08:00
|
|
|
|
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const handleResize = () => {
|
|
|
|
|
|
setIsMobile(window.innerWidth < 768);
|
|
|
|
|
|
};
|
|
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
|
return () => window.removeEventListener('resize', handleResize);
|
2025-12-29 16:10:42 +08:00
|
|
|
|
}, []);
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 获取所有系统设置 */
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const fetchSettings = async () => {
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await axios.get('/api/system-settings');
|
|
|
|
|
|
setSettings(response.data);
|
2026-02-10 11:04:01 +08:00
|
|
|
|
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const formValues = {};
|
|
|
|
|
|
Object.entries(response.data).forEach(([key, data]) => {
|
|
|
|
|
|
formValues[key] = data.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
form.setFieldsValue(formValues);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.error('获取设置失败');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 获取系统运行信息 */
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const fetchSystemInfo = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await axios.get('/api/system-settings/system/info');
|
|
|
|
|
|
setSystemInfo(response.data);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取系统信息失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 保存设置 */
|
2026-02-10 11:04:01 +08:00
|
|
|
|
const handleSaveSettings = async values => {
|
2025-12-29 16:10:42 +08:00
|
|
|
|
setSaving(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const updates = {};
|
|
|
|
|
|
Object.entries(values).forEach(([key, value]) => {
|
|
|
|
|
|
if (settings[key] && settings[key].isEditable) {
|
|
|
|
|
|
updates[key] = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
await axios.put('/api/system-settings', { settings: updates });
|
2026-06-12 14:16:29 +08:00
|
|
|
|
message.success('设置保存成功');
|
2026-02-05 10:32:10 +08:00
|
|
|
|
|
2025-12-29 16:10:42 +08:00
|
|
|
|
fetchSettings();
|
2026-01-21 10:40:30 +08:00
|
|
|
|
await reloadConfig();
|
2025-12-29 16:10:42 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
message.error('保存设置失败');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setSaving(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 预览Logo */
|
|
|
|
|
|
const handlePreviewLogo = () => {
|
|
|
|
|
|
const logoUrl = form.getFieldValue('site_logo');
|
|
|
|
|
|
if (!logoUrl) {
|
|
|
|
|
|
message.warning('请先输入Logo URL');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
Modal.info({
|
|
|
|
|
|
title: 'Logo 预览',
|
|
|
|
|
|
content: (
|
|
|
|
|
|
<div style={{ textAlign: 'center', padding: '16px 0' }}>
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={logoUrl}
|
|
|
|
|
|
alt="Logo预览"
|
|
|
|
|
|
style={{ maxWidth: '100%', maxHeight: 200, objectFit: 'contain' }}
|
|
|
|
|
|
onError={e => {
|
|
|
|
|
|
e.target.style.display = 'none';
|
|
|
|
|
|
e.target.parentNode.innerHTML =
|
|
|
|
|
|
'<div style="color:#ff4d4f;padding:20px;">图片加载失败,请检查URL是否正确</div>';
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
okText: '关闭',
|
|
|
|
|
|
width: 480,
|
2025-12-29 16:10:42 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
// 预设颜色
|
2026-03-06 15:41:07 +08:00
|
|
|
|
const presetColors = [
|
2026-06-12 14:16:29 +08:00
|
|
|
|
'#667eea', '#764ba2', '#f093fb', '#4facfe', '#43e97b',
|
|
|
|
|
|
'#fa709a', '#fee140', '#00b4db', '#0083b0', '#fcb045',
|
|
|
|
|
|
'#1890ff', '#52c41a', '#eb2f96', '#722ed1', '#13c2c2', '#fa8c16',
|
2026-03-06 15:41:07 +08:00
|
|
|
|
];
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 颜色变更处理 */
|
2026-03-06 15:41:07 +08:00
|
|
|
|
const handleColorChange = (color, key) => {
|
|
|
|
|
|
const hexColor = typeof color === 'string' ? color : color.toHexString();
|
|
|
|
|
|
form.setFieldValue(key, hexColor);
|
2026-03-27 19:12:16 +08:00
|
|
|
|
|
2026-03-06 15:41:07 +08:00
|
|
|
|
const root = document.documentElement;
|
|
|
|
|
|
if (key === 'primary_color') {
|
|
|
|
|
|
root.style.setProperty('--primary-color', hexColor);
|
|
|
|
|
|
root.style.setProperty('--primary-light', `${hexColor}20`);
|
|
|
|
|
|
} else if (key === 'secondary_color') {
|
|
|
|
|
|
root.style.setProperty('--secondary-color', hexColor);
|
|
|
|
|
|
root.style.setProperty('--secondary-light', `${hexColor}20`);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 渲染基本设置Tab */
|
|
|
|
|
|
const renderGeneralSettings = () => {
|
|
|
|
|
|
const maintenanceMode = form.getFieldValue('maintenance_mode');
|
2026-03-27 19:12:16 +08:00
|
|
|
|
|
2026-03-06 15:41:07 +08:00
|
|
|
|
return (
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Form form={form} layout="vertical" onFinish={handleSaveSettings}>
|
|
|
|
|
|
<div style={{ paddingBottom: 80 }}>
|
|
|
|
|
|
{/* 站点信息卡片 */}
|
|
|
|
|
|
<Card
|
|
|
|
|
|
style={{ marginBottom: 24, borderRadius: 12, border: '1px solid #e8e8e8', boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}
|
|
|
|
|
|
bodyStyle={{ padding: '24px' }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style={{ textAlign: 'center', marginBottom: 24 }}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
width: 48, height: 48, borderRadius: '50%',
|
|
|
|
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
|
|
|
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
|
|
|
|
|
marginBottom: 12,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<GlobalOutlined style={{ color: '#fff', fontSize: 24 }} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style={{ fontSize: 18, fontWeight: 600, color: '#262626', marginBottom: 6 }}>站点信息</div>
|
|
|
|
|
|
<div style={{ fontSize: 14, color: '#666' }}>配置系统基本信息和站点标识</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Divider style={{ margin: '0 0 24px 0' }} />
|
|
|
|
|
|
<Row gutter={[32, 16]}>
|
|
|
|
|
|
<Col xs={24} md={12}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={<span style={{ fontSize: 14, color: '#262626', fontWeight: 500 }}>网站名称</span>}
|
|
|
|
|
|
name="site_name"
|
|
|
|
|
|
style={{ marginBottom: 0 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input placeholder="请输入网站名称" style={{ height: 40, borderRadius: 8 }} />
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col xs={24} md={12}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={<span style={{ fontSize: 14, color: '#262626', fontWeight: 500 }}>网站Logo URL</span>}
|
|
|
|
|
|
name="site_logo"
|
|
|
|
|
|
style={{ marginBottom: 0 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
placeholder="请输入Logo图片URL"
|
|
|
|
|
|
style={{ height: 40, borderRadius: 8 }}
|
|
|
|
|
|
suffix={
|
|
|
|
|
|
<Button type="link" size="small" style={{ padding: 0 }} onClick={handlePreviewLogo}>
|
|
|
|
|
|
<EyeOutlined /> 预览
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 安全设置卡片 */}
|
|
|
|
|
|
<Card
|
|
|
|
|
|
style={{ marginBottom: 24, borderRadius: 12, border: '1px solid #e8e8e8', boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}
|
|
|
|
|
|
bodyStyle={{ padding: '24px' }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style={{ textAlign: 'center', marginBottom: 24 }}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
width: 48, height: 48, borderRadius: '50%',
|
|
|
|
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
|
|
|
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
|
|
|
|
|
marginBottom: 12,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<SafetyCertificateOutlined style={{ color: '#fff', fontSize: 24 }} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style={{ fontSize: 18, fontWeight: 600, color: '#262626', marginBottom: 6 }}>安全设置</div>
|
|
|
|
|
|
<div style={{ fontSize: 14, color: '#666' }}>配置登录安全策略和维护模式</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Divider style={{ margin: '0 0 24px 0' }} />
|
|
|
|
|
|
|
|
|
|
|
|
{/* 维护模式警告 */}
|
|
|
|
|
|
{maintenanceMode && (
|
|
|
|
|
|
<Alert
|
|
|
|
|
|
message="维护模式已开启"
|
|
|
|
|
|
description="开启后普通用户将无法登录和访问系统,仅管理员可正常使用。请在维护完成后及时关闭。"
|
|
|
|
|
|
type="warning"
|
|
|
|
|
|
showIcon
|
|
|
|
|
|
style={{ marginBottom: 24, borderRadius: 8 }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<Row gutter={[32, 16]} align="middle">
|
|
|
|
|
|
<Col xs={24} md={8}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={<span style={{ fontSize: 14, color: '#262626', fontWeight: 500 }}>空闲超时时间</span>}
|
|
|
|
|
|
name="idle_timeout"
|
|
|
|
|
|
style={{ marginBottom: 0 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputNumber
|
|
|
|
|
|
min={1}
|
|
|
|
|
|
max={120}
|
|
|
|
|
|
placeholder="超时时间"
|
|
|
|
|
|
style={{ width: '100%', height: 40, borderRadius: 8 }}
|
|
|
|
|
|
addonAfter="分钟"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col xs={24} md={8}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={<span style={{ fontSize: 14, color: '#262626', fontWeight: 500 }}>最大登录尝试次数</span>}
|
|
|
|
|
|
name="max_login_attempts"
|
|
|
|
|
|
style={{ marginBottom: 0 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputNumber
|
|
|
|
|
|
min={1}
|
|
|
|
|
|
max={20}
|
|
|
|
|
|
placeholder="尝试次数"
|
|
|
|
|
|
style={{ width: '100%', height: 40, borderRadius: 8 }}
|
|
|
|
|
|
addonAfter="次"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col xs={24} md={8}>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
label={<span style={{ fontSize: 14, color: '#262626', fontWeight: 500 }}>维护模式</span>}
|
|
|
|
|
|
name="maintenance_mode"
|
|
|
|
|
|
valuePropName="checked"
|
|
|
|
|
|
style={{ marginBottom: 0 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Tooltip title="开启后普通用户将无法登录和访问系统">
|
|
|
|
|
|
<Switch checkedChildren="开启" unCheckedChildren="关闭" style={{ marginTop: 8 }} />
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{renderFixedFooter()}
|
|
|
|
|
|
</Form>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 渲染外观设置Tab */
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const renderAppearanceSettings = () => {
|
2026-03-27 19:12:16 +08:00
|
|
|
|
const primaryColor =
|
|
|
|
|
|
form.getFieldValue('primary_color') || settings.primary_color?.value || '#667eea';
|
|
|
|
|
|
const secondaryColor =
|
|
|
|
|
|
form.getFieldValue('secondary_color') || settings.secondary_color?.value || '#764ba2';
|
2026-03-06 15:41:07 +08:00
|
|
|
|
|
2025-12-29 16:10:42 +08:00
|
|
|
|
return (
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Form form={form} layout="vertical" onFinish={handleSaveSettings}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ paddingBottom: 80 }}>
|
|
|
|
|
|
<Alert
|
|
|
|
|
|
message="主题颜色设置"
|
2026-03-06 15:41:07 +08:00
|
|
|
|
description="选择颜色后可实时预览效果,保存设置后永久生效。建议选择对比度适中的颜色组合。"
|
2026-02-12 15:10:24 +08:00
|
|
|
|
type="info"
|
|
|
|
|
|
showIcon
|
|
|
|
|
|
style={{ marginBottom: 24, borderRadius: 12 }}
|
|
|
|
|
|
/>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
|
2026-03-06 15:41:07 +08:00
|
|
|
|
<Card
|
2026-06-12 14:16:29 +08:00
|
|
|
|
style={{ marginBottom: 24, borderRadius: 12, border: '1px solid #e8e8e8', boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
bodyStyle={{ padding: '24px' }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div style={{ textAlign: 'center', marginBottom: 24 }}>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
2026-06-12 14:16:29 +08:00
|
|
|
|
width: 48, height: 48, borderRadius: '50%',
|
2026-03-27 19:12:16 +08:00
|
|
|
|
background: `linear-gradient(135deg, ${primaryColor} 0%, ${secondaryColor} 100%)`,
|
2026-06-12 14:16:29 +08:00
|
|
|
|
display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
|
2026-03-27 19:12:16 +08:00
|
|
|
|
marginBottom: 12,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
<BgColorsOutlined style={{ color: '#fff', fontSize: 24 }} />
|
|
|
|
|
|
</div>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ fontSize: 18, fontWeight: 600, color: '#262626', marginBottom: 6 }}>主题颜色</div>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div style={{ fontSize: 14, color: '#666' }}>自定义系统主题配色方案</div>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<Divider style={{ margin: '0 0 24px 0' }} />
|
|
|
|
|
|
|
|
|
|
|
|
<Row gutter={[32, 24]}>
|
|
|
|
|
|
<Col xs={24} md={12}>
|
|
|
|
|
|
<div style={{ marginBottom: 8 }}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text strong style={{ fontSize: 14, color: '#262626' }}>主色调</Text>
|
|
|
|
|
|
<Text type="secondary" style={{ fontSize: 12, marginLeft: 8 }}>用于按钮、链接等主要交互元素</Text>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<Space direction="vertical" style={{ width: '100%' }}>
|
|
|
|
|
|
<ColorPicker
|
|
|
|
|
|
value={primaryColor}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onChange={color => handleColorChange(color, 'primary_color')}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
format="hex"
|
|
|
|
|
|
showText
|
2026-06-12 14:16:29 +08:00
|
|
|
|
presets={[{ label: '推荐配色', colors: presetColors }]}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
|
/>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Input
|
2026-03-06 15:41:07 +08:00
|
|
|
|
value={primaryColor}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onChange={e => handleColorChange(e.target.value, 'primary_color')}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
placeholder="#667eea"
|
|
|
|
|
|
style={{ borderRadius: 8 }}
|
|
|
|
|
|
prefix={<BgColorsOutlined style={{ color: '#bfbfbf' }} />}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Space>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col xs={24} md={12}>
|
|
|
|
|
|
<div style={{ marginBottom: 8 }}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text strong style={{ fontSize: 14, color: '#262626' }}>次色调</Text>
|
|
|
|
|
|
<Text type="secondary" style={{ fontSize: 12, marginLeft: 8 }}>用于渐变、悬停效果等辅助元素</Text>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<Space direction="vertical" style={{ width: '100%' }}>
|
|
|
|
|
|
<ColorPicker
|
|
|
|
|
|
value={secondaryColor}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onChange={color => handleColorChange(color, 'secondary_color')}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
format="hex"
|
|
|
|
|
|
showText
|
2026-06-12 14:16:29 +08:00
|
|
|
|
presets={[{ label: '推荐配色', colors: presetColors }]}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
|
|
/>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Input
|
2026-03-06 15:41:07 +08:00
|
|
|
|
value={secondaryColor}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onChange={e => handleColorChange(e.target.value, 'secondary_color')}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
placeholder="#764ba2"
|
|
|
|
|
|
style={{ borderRadius: 8 }}
|
|
|
|
|
|
prefix={<BgColorsOutlined style={{ color: '#bfbfbf' }} />}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Space>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
|
|
|
|
|
|
|
|
|
|
|
<Divider style={{ margin: '24px 0' }} />
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
{/* 实时预览 */}
|
|
|
|
|
|
<div style={{ padding: 16, background: '#fafafa', borderRadius: 8, border: '1px solid #f0f0f0' }}>
|
|
|
|
|
|
<Text strong style={{ fontSize: 13, color: '#595959', marginBottom: 12, display: 'block' }}>实时预览</Text>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
<Space size="middle" wrap>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
style={{
|
2026-03-06 15:41:07 +08:00
|
|
|
|
background: `linear-gradient(135deg, ${primaryColor} 0%, ${secondaryColor} 100%)`,
|
2026-03-27 19:12:16 +08:00
|
|
|
|
border: 'none',
|
2026-03-06 15:41:07 +08:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
主要按钮
|
|
|
|
|
|
</Button>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Button style={{ borderColor: primaryColor, color: primaryColor }}>
|
2026-03-06 15:41:07 +08:00
|
|
|
|
次要按钮
|
|
|
|
|
|
</Button>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Tag color={primaryColor} style={{ borderRadius: 4 }}>标签样式</Tag>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
2026-06-12 14:16:29 +08:00
|
|
|
|
width: 60, height: 24, borderRadius: 4,
|
2026-03-06 15:41:07 +08:00
|
|
|
|
background: `linear-gradient(135deg, ${primaryColor} 0%, ${secondaryColor} 100%)`,
|
2026-03-27 19:12:16 +08:00
|
|
|
|
}}
|
2026-03-06 15:41:07 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</Space>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Card>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
{renderFixedFooter()}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 渲染关于系统Tab */
|
2025-12-29 16:10:42 +08:00
|
|
|
|
const renderAboutPage = () => {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Card
|
2026-06-12 14:16:29 +08:00
|
|
|
|
style={{ marginBottom: 16, borderRadius: 12, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', border: 'none' }}
|
2026-02-12 15:10:24 +08:00
|
|
|
|
bodyStyle={{ padding: '24px' }}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Row gutter={[20, 20]} align="middle">
|
|
|
|
|
|
<Col xs={24} sm={6} md={5}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
2026-06-12 14:16:29 +08:00
|
|
|
|
width: 80, height: 80, borderRadius: 16,
|
2026-02-12 15:10:24 +08:00
|
|
|
|
backgroundColor: 'rgba(255,255,255,0.15)',
|
2026-06-12 14:16:29 +08:00
|
|
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
2026-02-12 15:10:24 +08:00
|
|
|
|
margin: '0 auto',
|
2026-02-12 14:36:33 +08:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatabaseOutlined style={{ fontSize: 40, color: '#fff' }} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={24} sm={18} md={19}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Title level={3} style={{ color: '#fff', margin: 0, marginBottom: 6, fontSize: '22px' }}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
机柜管理系统
|
|
|
|
|
|
</Title>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Space size={12} wrap style={{ color: 'rgba(255,255,255,0.9)' }}>
|
|
|
|
|
|
<span style={{ fontSize: 14 }}>版本 {settings.app_version?.value || '1.0.0'}</span>
|
|
|
|
|
|
<span style={{ opacity: 0.5 }}>|</span>
|
|
|
|
|
|
<Badge status="success" text={<span style={{ color: '#fff' }}>运行正常</span>} />
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</Space>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Paragraph style={{ color: 'rgba(255,255,255,0.85)', marginTop: 8, marginBottom: 0, fontSize: 13 }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
专业的数据中心设备管理平台,提供机房、机柜、设备的全生命周期管理
|
|
|
|
|
|
</Paragraph>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
|
|
{systemInfo && (
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Card
|
2026-02-12 15:10:24 +08:00
|
|
|
|
style={{ marginBottom: 16, borderRadius: 12, border: '1px solid #e8e8e8' }}
|
|
|
|
|
|
bodyStyle={{ padding: '20px' }}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ marginBottom: 16 }}>
|
|
|
|
|
|
<Space size={10}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Avatar style={{ backgroundColor: '#52c41a', borderRadius: 8 }} icon={<CloudServerOutlined />} size={32} />
|
|
|
|
|
|
<Text strong style={{ fontSize: 15 }}>系统统计</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</Space>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Row gutter={[12, 12]}>
|
|
|
|
|
|
<Col xs={12} sm={6}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ textAlign: 'center', borderRadius: 10, background: 'linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%)', padding: '16px 12px' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ fontSize: 24, fontWeight: 700, color: '#52c41a', marginBottom: 2 }}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
{systemInfo.statistics?.devices || 0}
|
|
|
|
|
|
</div>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text type="secondary" style={{ fontSize: 12 }}>设备总数</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={12} sm={6}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ textAlign: 'center', borderRadius: 10, background: 'linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%)', padding: '16px 12px' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ fontSize: 24, fontWeight: 700, color: '#1890ff', marginBottom: 2 }}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
{systemInfo.statistics?.racks || 0}
|
|
|
|
|
|
</div>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text type="secondary" style={{ fontSize: 12 }}>机柜总数</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={12} sm={6}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ textAlign: 'center', borderRadius: 10, background: 'linear-gradient(135deg, #f9f0ff 0%, #efdbff 100%)', padding: '16px 12px' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ fontSize: 24, fontWeight: 700, color: '#722ed1', marginBottom: 2 }}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
{systemInfo.statistics?.rooms || 0}
|
|
|
|
|
|
</div>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text type="secondary" style={{ fontSize: 12 }}>机房总数</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={12} sm={6}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ textAlign: 'center', borderRadius: 10, background: 'linear-gradient(135deg, #fff7e6 0%, #ffd591 100%)', padding: '16px 12px' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ fontSize: 24, fontWeight: 700, color: '#fa8c16', marginBottom: 2 }}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
{systemInfo.statistics?.users || 0}
|
|
|
|
|
|
</div>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text type="secondary" style={{ fontSize: 12 }}>用户总数</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
|
|
|
|
|
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Divider style={{ margin: '20px 0' }} />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Descriptions column={{ xs: 1, sm: 2, md: 3 }} size="small" labelStyle={{ fontWeight: 500, fontSize: 13 }}>
|
2026-02-10 11:04:01 +08:00
|
|
|
|
<Descriptions.Item label="Node.js 版本">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Tag color="blue" size="small">{systemInfo.system?.nodeVersion}</Tag>
|
2026-02-10 11:04:01 +08:00
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="运行平台">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Text style={{ fontSize: 13 }}>{systemInfo.system?.platform} ({systemInfo.system?.arch})</Text>
|
2026-02-10 11:04:01 +08:00
|
|
|
|
</Descriptions.Item>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Descriptions.Item label="进程 ID">
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Tag size="small">{systemInfo.system?.pid}</Tag>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Descriptions.Item>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
<Descriptions.Item label="运行时间">
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Text style={{ fontSize: 13 }}>
|
|
|
|
|
|
{systemInfo.system?.uptime
|
|
|
|
|
|
? `${Math.floor(systemInfo.system.uptime / 3600)}小时${Math.floor((systemInfo.system.uptime % 3600) / 60)}分钟`
|
|
|
|
|
|
: '-'}
|
|
|
|
|
|
</Text>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="内存使用">
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Text style={{ fontSize: 13 }}>
|
|
|
|
|
|
{systemInfo.system?.memoryUsage
|
|
|
|
|
|
? `${(systemInfo.system.memoryUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`
|
|
|
|
|
|
: '-'}
|
|
|
|
|
|
</Text>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
|
<Descriptions.Item label="系统时间">
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<Text style={{ fontSize: 13 }}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
{systemInfo.timestamp ? new Date(systemInfo.timestamp).toLocaleString('zh-CN') : '-'}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
</Text>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</Descriptions.Item>
|
|
|
|
|
|
</Descriptions>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
{/* 公司信息编辑 */}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Card
|
2026-02-12 15:10:24 +08:00
|
|
|
|
style={{ marginBottom: 16, borderRadius: 12, border: '1px solid #e8e8e8' }}
|
|
|
|
|
|
bodyStyle={{ padding: '20px' }}
|
2026-02-12 14:36:33 +08:00
|
|
|
|
>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ marginBottom: 16 }}>
|
|
|
|
|
|
<Space size={10}>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Avatar style={{ backgroundColor: '#667eea', borderRadius: 8 }} icon={<FileTextOutlined />} size={32} />
|
|
|
|
|
|
<Text strong style={{ fontSize: 15 }}>公司信息</Text>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</Space>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Form form={form} layout="vertical" onFinish={handleSaveSettings}>
|
|
|
|
|
|
<Row gutter={[24, 8]}>
|
|
|
|
|
|
<Col xs={24} sm={12}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Form.Item label="公司名称" name="company_name">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Input prefix={<GlobalOutlined style={{ color: '#bfbfbf' }} />} placeholder="请输入公司名称" />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={24} sm={12}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Form.Item label="联系邮箱" name="contact_email">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Input prefix={<MailOutlined style={{ color: '#bfbfbf' }} />} placeholder="请输入联系邮箱" />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={24} sm={12}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Form.Item label="联系电话" name="contact_phone">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Input prefix={<PhoneOutlined style={{ color: '#bfbfbf' }} />} placeholder="请输入联系电话" />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Col xs={24} sm={12}>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
<Form.Item label="公司地址" name="company_address">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Input prefix={<EnvironmentOutlined style={{ color: '#bfbfbf' }} />} placeholder="请输入公司地址" />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
|
<Form.Item label="系统描述" name="system_description">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Input.TextArea rows={3} placeholder="请输入系统描述" style={{ borderRadius: 8 }} />
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Divider style={{ margin: '16px 0' }} />
|
|
|
|
|
|
<Space size="middle">
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Button type="primary" htmlType="submit" loading={saving} icon={<SaveOutlined />} style={{ borderRadius: 8 }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
保存信息
|
|
|
|
|
|
</Button>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Button onClick={() => fetchSettings()} icon={<ReloadOutlined />} style={{ borderRadius: 8 }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
重置
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Space>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Form>
|
|
|
|
|
|
</Card>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 底部固定操作栏 */
|
|
|
|
|
|
const renderFixedFooter = () => (
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
position: 'sticky', bottom: 0, left: 0, right: 0,
|
|
|
|
|
|
background: '#fff', borderTop: '1px solid #e8e8e8',
|
|
|
|
|
|
padding: '16px 24px', display: 'flex', justifyContent: 'center', gap: 16,
|
|
|
|
|
|
boxShadow: '0 -2px 8px rgba(0,0,0,0.06)', zIndex: 10, marginTop: 24,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="primary" htmlType="submit" loading={saving} icon={<SaveOutlined />} size="large"
|
|
|
|
|
|
style={{ borderRadius: 8, minWidth: 140, height: 44, fontSize: 15, fontWeight: 500 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
保存设置
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
onClick={() => fetchSettings()} icon={<ReloadOutlined />} size="large"
|
|
|
|
|
|
style={{ borderRadius: 8, minWidth: 120, height: 44, fontSize: 15 }}
|
|
|
|
|
|
>
|
|
|
|
|
|
重置表单
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/** 渲染当前Tab内容 */
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const renderContent = () => {
|
|
|
|
|
|
switch (activeMenu) {
|
|
|
|
|
|
case 'general':
|
|
|
|
|
|
return renderGeneralSettings();
|
|
|
|
|
|
case 'appearance':
|
|
|
|
|
|
return renderAppearanceSettings();
|
|
|
|
|
|
case 'about':
|
|
|
|
|
|
return renderAboutPage();
|
|
|
|
|
|
default:
|
|
|
|
|
|
return renderGeneralSettings();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
const menuItems = [
|
|
|
|
|
|
{ key: 'general', icon: <GlobalOutlined />, label: '基本设置', description: '站点信息、安全设置' },
|
|
|
|
|
|
{ key: 'appearance', icon: <BgColorsOutlined />, label: '外观设置', description: '主题颜色' },
|
|
|
|
|
|
{ key: 'about', icon: <InfoCircleOutlined />, label: '关于系统', description: '系统信息、版本详情' },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
/** 桌面端顶部导航栏 */
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const renderTopNav = () => (
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
2026-06-12 14:16:29 +08:00
|
|
|
|
display: 'flex', alignItems: 'center', gap: '4px',
|
|
|
|
|
|
flexWrap: 'nowrap', overflowX: 'auto', scrollbarWidth: 'none', msOverflowStyle: 'none',
|
2026-03-27 19:12:16 +08:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
{menuItems.map(item => (
|
|
|
|
|
|
<div
|
|
|
|
|
|
key={item.key}
|
|
|
|
|
|
onClick={() => setActiveMenu(item.key)}
|
|
|
|
|
|
style={{
|
2026-06-12 14:16:29 +08:00
|
|
|
|
display: 'flex', alignItems: 'center', padding: '8px 16px',
|
|
|
|
|
|
borderRadius: 20, cursor: 'pointer', transition: 'all 0.3s ease',
|
2026-02-12 15:10:24 +08:00
|
|
|
|
backgroundColor: activeMenu === item.key ? 'rgba(255,255,255,0.25)' : 'transparent',
|
2026-06-12 14:16:29 +08:00
|
|
|
|
color: '#fff', whiteSpace: 'nowrap', fontSize: 14,
|
2026-02-12 15:10:24 +08:00
|
|
|
|
fontWeight: activeMenu === item.key ? 600 : 400,
|
|
|
|
|
|
}}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onMouseEnter={e => {
|
2026-06-12 14:16:29 +08:00
|
|
|
|
if (activeMenu !== item.key) e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.1)';
|
2026-02-12 15:10:24 +08:00
|
|
|
|
}}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onMouseLeave={e => {
|
2026-06-12 14:16:29 +08:00
|
|
|
|
if (activeMenu !== item.key) e.currentTarget.style.backgroundColor = 'transparent';
|
2026-02-12 15:10:24 +08:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span style={{ marginRight: 6, fontSize: 16 }}>{item.icon}</span>
|
|
|
|
|
|
<span>{item.label}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
/** 移动端下拉导航 */
|
2026-02-12 15:10:24 +08:00
|
|
|
|
const renderMobileNav = () => (
|
|
|
|
|
|
<Select
|
|
|
|
|
|
value={activeMenu}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
onChange={value => setActiveMenu(value)}
|
2026-02-12 15:10:24 +08:00
|
|
|
|
style={{ width: 140 }}
|
|
|
|
|
|
bordered={false}
|
|
|
|
|
|
dropdownStyle={{ borderRadius: 8 }}
|
|
|
|
|
|
suffixIcon={<MenuUnfoldOutlined style={{ color: '#fff' }} />}
|
|
|
|
|
|
>
|
|
|
|
|
|
{menuItems.map(item => (
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Select.Option key={item.key} value={item.key}>
|
|
|
|
|
|
<Space>{item.icon}{item.label}</Space>
|
|
|
|
|
|
</Select.Option>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
))}
|
|
|
|
|
|
</Select>
|
|
|
|
|
|
);
|
2026-02-12 14:36:33 +08:00
|
|
|
|
|
2025-12-29 16:10:42 +08:00
|
|
|
|
return (
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ minHeight: '100vh', background: '#f5f7fa', display: 'flex', flexDirection: 'column' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
{/* 顶部固定导航栏 */}
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
2026-06-12 14:16:29 +08:00
|
|
|
|
padding: '16px 24px', position: 'sticky', top: 0, zIndex: 100,
|
2026-03-27 19:12:16 +08:00
|
|
|
|
boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<div style={{ maxWidth: '100%', margin: '0 auto', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<Space align="center">
|
|
|
|
|
|
<SettingOutlined style={{ fontSize: 20, color: '#fff' }} />
|
2026-06-12 14:16:29 +08:00
|
|
|
|
<Title level={4} style={{ margin: 0, color: '#fff', fontSize: 18 }}>系统设置</Title>
|
2026-02-12 14:36:33 +08:00
|
|
|
|
</Space>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
{!isMobile && renderTopNav()}
|
|
|
|
|
|
{isMobile && renderMobileNav()}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-12 14:16:29 +08:00
|
|
|
|
{/* 主内容区 */}
|
2026-02-12 15:10:24 +08:00
|
|
|
|
<div style={{ flex: 1, padding: '16px 24px' }}>
|
2026-03-27 19:12:16 +08:00
|
|
|
|
<div style={{ maxWidth: '100%' }}>{renderContent()}</div>
|
2026-02-12 15:10:24 +08:00
|
|
|
|
</div>
|
2025-12-29 16:10:42 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default SystemSettings;
|