Files
makemd/dashboard/src/pages/Settings/index.tsx

1192 lines
37 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect } from 'react';
import {
Card,
Row,
Col,
Button,
Tabs,
Form,
Input,
Switch,
Select,
Avatar,
Upload,
message,
Divider,
Typography,
Space,
Tag,
Table,
Modal,
Descriptions,
List,
Badge,
Popconfirm,
TimePicker,
Checkbox,
Radio,
Slider,
Tooltip,
Alert,
} from 'antd';
import {
UserOutlined,
TeamOutlined,
SettingOutlined,
LockOutlined,
BellOutlined,
GlobalOutlined,
SafetyOutlined,
UploadOutlined,
EditOutlined,
DeleteOutlined,
PlusOutlined,
KeyOutlined,
MailOutlined,
MobileOutlined,
DesktopOutlined,
ApiOutlined,
DatabaseOutlined,
CloudOutlined,
FileTextOutlined,
QuestionCircleOutlined,
SaveOutlined,
ReloadOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import moment from 'moment';
const { Title, Text, Paragraph } = Typography;
const { TabPane } = Tabs;
const { Option } = Select;
const { TextArea } = Input;
// 用户设置接口
interface UserProfile {
id: string;
username: string;
email: string;
phone: string;
avatar: string;
role: string;
department: string;
timezone: string;
language: string;
createdAt: string;
lastLoginAt: string;
}
// 通知设置接口
interface NotificationSettings {
emailEnabled: boolean;
smsEnabled: boolean;
pushEnabled: boolean;
orderAlerts: boolean;
inventoryAlerts: boolean;
complianceAlerts: boolean;
systemAlerts: boolean;
marketingEmails: boolean;
digestFrequency: 'realtime' | 'hourly' | 'daily' | 'weekly';
quietHoursStart: string;
quietHoursEnd: string;
}
// 安全设置接口
interface SecuritySettings {
twoFactorEnabled: boolean;
loginNotification: boolean;
passwordExpiryDays: number;
sessionTimeout: number;
ipWhitelist: string[];
apiKey: string;
lastPasswordChange: string;
}
// 系统设置接口
interface SystemSettings {
autoSync: boolean;
syncInterval: number;
dataRetentionDays: number;
backupEnabled: boolean;
backupFrequency: 'daily' | 'weekly' | 'monthly';
logLevel: 'debug' | 'info' | 'warn' | 'error';
theme: 'light' | 'dark' | 'auto';
dateFormat: string;
currency: string;
}
// API密钥接口
interface ApiKey {
id: string;
name: string;
key: string;
permissions: string[];
createdAt: string;
lastUsedAt: string;
status: 'active' | 'inactive';
}
// 操作日志接口
interface OperationLog {
id: string;
userId: string;
username: string;
action: string;
module: string;
details: string;
ip: string;
userAgent: string;
createdAt: string;
}
const MOCK_USER_PROFILE: UserProfile = {
id: '1',
username: 'admin',
email: 'admin@crawlful.com',
phone: '+86 13800138000',
avatar: '',
role: 'ADMIN',
department: '技术部',
timezone: 'Asia/Shanghai',
language: 'zh-CN',
createdAt: '2025-01-15',
lastLoginAt: '2026-03-18 10:30:00',
};
const MOCK_NOTIFICATION_SETTINGS: NotificationSettings = {
emailEnabled: true,
smsEnabled: false,
pushEnabled: true,
orderAlerts: true,
inventoryAlerts: true,
complianceAlerts: true,
systemAlerts: true,
marketingEmails: false,
digestFrequency: 'daily',
quietHoursStart: '22:00',
quietHoursEnd: '08:00',
};
const MOCK_SECURITY_SETTINGS: SecuritySettings = {
twoFactorEnabled: false,
loginNotification: true,
passwordExpiryDays: 90,
sessionTimeout: 30,
ipWhitelist: [],
apiKey: 'sk_live_xxxxxxxxxxxxxxxx',
lastPasswordChange: '2026-01-01',
};
const MOCK_SYSTEM_SETTINGS: SystemSettings = {
autoSync: true,
syncInterval: 15,
dataRetentionDays: 365,
backupEnabled: true,
backupFrequency: 'daily',
logLevel: 'info',
theme: 'light',
dateFormat: 'YYYY-MM-DD',
currency: 'CNY',
};
const MOCK_API_KEYS: ApiKey[] = [
{
id: '1',
name: 'Production API Key',
key: 'sk_live_prod_xxxxxxxx',
permissions: ['read', 'write'],
createdAt: '2026-01-01',
lastUsedAt: '2026-03-18 09:00:00',
status: 'active',
},
{
id: '2',
name: 'Test API Key',
key: 'sk_test_xxxxxxxx',
permissions: ['read'],
createdAt: '2026-02-01',
lastUsedAt: '2026-03-17 15:30:00',
status: 'active',
},
];
const MOCK_OPERATION_LOGS: OperationLog[] = [
{
id: '1',
userId: '1',
username: 'admin',
action: 'LOGIN',
module: 'AUTH',
details: '用户登录成功',
ip: '192.168.1.100',
userAgent: 'Mozilla/5.0',
createdAt: '2026-03-18 10:30:00',
},
{
id: '2',
userId: '1',
username: 'admin',
action: 'UPDATE_PRODUCT',
module: 'PRODUCT',
details: '更新产品信息: P001',
ip: '192.168.1.100',
userAgent: 'Mozilla/5.0',
createdAt: '2026-03-18 10:35:00',
},
{
id: '3',
userId: '1',
username: 'admin',
action: 'CREATE_ORDER',
module: 'ORDER',
details: '创建订单: ORD-2026-001',
ip: '192.168.1.100',
userAgent: 'Mozilla/5.0',
createdAt: '2026-03-18 11:00:00',
},
];
const Settings: React.FC = () => {
const [activeTab, setActiveTab] = useState('profile');
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
// 表单实例
const [profileForm] = Form.useForm();
const [notificationForm] = Form.useForm();
const [securityForm] = Form.useForm();
const [systemForm] = Form.useForm();
const [passwordForm] = Form.useForm();
const [apiKeyForm] = Form.useForm();
// 数据状态
const [userProfile, setUserProfile] = useState<UserProfile>(MOCK_USER_PROFILE);
const [notificationSettings, setNotificationSettings] = useState<NotificationSettings>(MOCK_NOTIFICATION_SETTINGS);
const [securitySettings, setSecuritySettings] = useState<SecuritySettings>(MOCK_SECURITY_SETTINGS);
const [systemSettings, setSystemSettings] = useState<SystemSettings>(MOCK_SYSTEM_SETTINGS);
const [apiKeys, setApiKeys] = useState<ApiKey[]>(MOCK_API_KEYS);
const [operationLogs, setOperationLogs] = useState<OperationLog[]>(MOCK_OPERATION_LOGS);
// 模态框状态
const [passwordModalVisible, setPasswordModalVisible] = useState(false);
const [apiKeyModalVisible, setApiKeyModalVisible] = useState(false);
const [twoFactorModalVisible, setTwoFactorModalVisible] = useState(false);
useEffect(() => {
// 初始化表单值
profileForm.setFieldsValue(userProfile);
notificationForm.setFieldsValue(notificationSettings);
securityForm.setFieldsValue(securitySettings);
systemForm.setFieldsValue(systemSettings);
}, []);
// ==================== 个人资料 ====================
const handleProfileSave = async () => {
try {
setSaving(true);
const values = await profileForm.validateFields();
await new Promise(resolve => setTimeout(resolve, 500));
setUserProfile({ ...userProfile, ...values });
message.success('个人资料已保存');
} catch (error) {
console.error('Save failed:', error);
} finally {
setSaving(false);
}
};
const handleAvatarUpload = (info: any) => {
if (info.file.status === 'done') {
message.success('头像上传成功');
}
};
// ==================== 通知设置 ====================
const handleNotificationSave = async () => {
try {
setSaving(true);
const values = await notificationForm.validateFields();
await new Promise(resolve => setTimeout(resolve, 500));
setNotificationSettings(values);
message.success('通知设置已保存');
} catch (error) {
console.error('Save failed:', error);
} finally {
setSaving(false);
}
};
// ==================== 安全设置 ====================
const handlePasswordChange = async () => {
try {
const values = await passwordForm.validateFields();
if (values.newPassword !== values.confirmPassword) {
message.error('两次输入的密码不一致');
return;
}
await new Promise(resolve => setTimeout(resolve, 500));
message.success('密码修改成功');
setPasswordModalVisible(false);
passwordForm.resetFields();
} catch (error) {
console.error('Password change failed:', error);
}
};
const handleTwoFactorToggle = async (enabled: boolean) => {
if (enabled) {
setTwoFactorModalVisible(true);
} else {
setSecuritySettings({ ...securitySettings, twoFactorEnabled: false });
message.success('双因素认证已关闭');
}
};
const handleSecuritySave = async () => {
try {
setSaving(true);
const values = await securityForm.validateFields();
await new Promise(resolve => setTimeout(resolve, 500));
setSecuritySettings({ ...securitySettings, ...values });
message.success('安全设置已保存');
} catch (error) {
console.error('Save failed:', error);
} finally {
setSaving(false);
}
};
// ==================== API密钥管理 ====================
const handleCreateApiKey = async () => {
try {
const values = await apiKeyForm.validateFields();
const newKey: ApiKey = {
id: `${Date.now()}`,
name: values.name,
key: `sk_${values.environment}_${Math.random().toString(36).substring(2, 15)}`,
permissions: values.permissions,
createdAt: moment().format('YYYY-MM-DD'),
lastUsedAt: '-',
status: 'active',
};
setApiKeys([newKey, ...apiKeys]);
setApiKeyModalVisible(false);
apiKeyForm.resetFields();
message.success('API密钥创建成功');
} catch (error) {
console.error('Create API key failed:', error);
}
};
const handleDeleteApiKey = (id: string) => {
setApiKeys(apiKeys.filter(key => key.id !== id));
message.success('API密钥已删除');
};
const handleCopyApiKey = (key: string) => {
navigator.clipboard.writeText(key);
message.success('API密钥已复制到剪贴板');
};
// ==================== 系统设置 ====================
const handleSystemSave = async () => {
try {
setSaving(true);
const values = await systemForm.validateFields();
await new Promise(resolve => setTimeout(resolve, 500));
setSystemSettings(values);
message.success('系统设置已保存');
} catch (error) {
console.error('Save failed:', error);
} finally {
setSaving(false);
}
};
// ==================== 表格列定义 ====================
const apiKeyColumns: ColumnsType<ApiKey> = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
},
{
title: '密钥',
dataIndex: 'key',
key: 'key',
render: (key) => (
<Space>
<Text copyable={{ text: key }}>{key.substring(0, 20)}...</Text>
</Space>
),
},
{
title: '权限',
dataIndex: 'permissions',
key: 'permissions',
render: (permissions) => (
<Space>
{permissions.map((perm: string) => (
<Tag key={perm} color={perm === 'write' ? 'blue' : 'green'}>
{perm === 'read' ? '读取' : '写入'}
</Tag>
))}
</Space>
),
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
render: (status) => (
<Badge status={status === 'active' ? 'success' : 'default'} text={status === 'active' ? '活跃' : '已停用'} />
),
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
},
{
title: '最后使用',
dataIndex: 'lastUsedAt',
key: 'lastUsedAt',
},
{
title: '操作',
key: 'action',
render: (_, record) => (
<Space size="small">
<Button type="link" size="small" onClick={() => handleCopyApiKey(record.key)}>
</Button>
<Popconfirm
title="确认删除"
description="确定要删除此API密钥吗此操作不可恢复。"
onConfirm={() => handleDeleteApiKey(record.id)}
okText="删除"
cancelText="取消"
>
<Button type="link" size="small" danger>
</Button>
</Popconfirm>
</Space>
),
},
];
const logColumns: ColumnsType<OperationLog> = [
{
title: '时间',
dataIndex: 'createdAt',
key: 'createdAt',
width: 160,
},
{
title: '用户',
dataIndex: 'username',
key: 'username',
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
render: (action) => {
const actionMap: Record<string, { color: string; text: string }> = {
LOGIN: { color: 'green', text: '登录' },
LOGOUT: { color: 'default', text: '登出' },
CREATE: { color: 'blue', text: '创建' },
UPDATE: { color: 'orange', text: '更新' },
DELETE: { color: 'red', text: '删除' },
};
const config = actionMap[action] || { color: 'default', text: action };
return <Tag color={config.color}>{config.text}</Tag>;
},
},
{
title: '模块',
dataIndex: 'module',
key: 'module',
},
{
title: '详情',
dataIndex: 'details',
key: 'details',
},
{
title: 'IP地址',
dataIndex: 'ip',
key: 'ip',
},
];
return (
<div className="settings-page" style={{ padding: 24 }}>
<div style={{ marginBottom: 24 }}>
<Title level={4}></Title>
<Text type="secondary"></Text>
</div>
<Tabs activeKey={activeTab} onChange={setActiveTab} type="card">
{/* 个人资料 */}
<TabPane
tab={
<span>
<UserOutlined />
</span>
}
key="profile"
>
<Card>
<Row gutter={24}>
<Col span={8} style={{ textAlign: 'center' }}>
<Avatar size={120} icon={<UserOutlined />} src={userProfile.avatar} />
<div style={{ marginTop: 16 }}>
<Upload
name="avatar"
showUploadList={false}
onChange={handleAvatarUpload}
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</div>
<Divider />
<Descriptions column={1} size="small">
<Descriptions.Item label="用户ID">{userProfile.id}</Descriptions.Item>
<Descriptions.Item label="角色">
<Tag color="blue">{userProfile.role}</Tag>
</Descriptions.Item>
<Descriptions.Item label="部门">{userProfile.department}</Descriptions.Item>
<Descriptions.Item label="注册时间">{userProfile.createdAt}</Descriptions.Item>
<Descriptions.Item label="最后登录">{userProfile.lastLoginAt}</Descriptions.Item>
</Descriptions>
</Col>
<Col span={16}>
<Form form={profileForm} layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="username"
label="用户名"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input prefix={<UserOutlined />} placeholder="用户名" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="email"
label="邮箱"
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '请输入有效的邮箱地址' },
]}
>
<Input prefix={<MailOutlined />} placeholder="邮箱" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="phone"
label="手机号"
rules={[{ required: true, message: '请输入手机号' }]}
>
<Input prefix={<MobileOutlined />} placeholder="手机号" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="department"
label="部门"
>
<Input placeholder="部门" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="timezone"
label="时区"
>
<Select placeholder="选择时区">
<Option value="Asia/Shanghai">Asia/Shanghai (GMT+8)</Option>
<Option value="Asia/Tokyo">Asia/Tokyo (GMT+9)</Option>
<Option value="America/New_York">America/New_York (GMT-5)</Option>
<Option value="Europe/London">Europe/London (GMT+0)</Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="language"
label="语言"
>
<Select placeholder="选择语言">
<Option value="zh-CN"></Option>
<Option value="en-US">English</Option>
<Option value="ja-JP"></Option>
</Select>
</Form.Item>
</Col>
</Row>
<Form.Item>
<Button type="primary" icon={<SaveOutlined />} onClick={handleProfileSave} loading={saving}>
</Button>
</Form.Item>
</Form>
</Col>
</Row>
</Card>
</TabPane>
{/* 通知设置 */}
<TabPane
tab={
<span>
<BellOutlined />
</span>
}
key="notifications"
>
<Card>
<Form form={notificationForm} layout="vertical">
<Title level={5}></Title>
<Row gutter={16}>
<Col span={8}>
<Card size="small">
<Form.Item name="emailEnabled" valuePropName="checked" noStyle>
<Switch />
</Form.Item>
<div style={{ marginTop: 8 }}>
<MailOutlined style={{ fontSize: 24, color: '#1890ff' }} />
<div style={{ marginTop: 8 }}>
<Text strong></Text>
<div><Text type="secondary"></Text></div>
</div>
</div>
</Card>
</Col>
<Col span={8}>
<Card size="small">
<Form.Item name="smsEnabled" valuePropName="checked" noStyle>
<Switch />
</Form.Item>
<div style={{ marginTop: 8 }}>
<MobileOutlined style={{ fontSize: 24, color: '#52c41a' }} />
<div style={{ marginTop: 8 }}>
<Text strong></Text>
<div><Text type="secondary"></Text></div>
</div>
</div>
</Card>
</Col>
<Col span={8}>
<Card size="small">
<Form.Item name="pushEnabled" valuePropName="checked" noStyle>
<Switch />
</Form.Item>
<div style={{ marginTop: 8 }}>
<DesktopOutlined style={{ fontSize: 24, color: '#faad14' }} />
<div style={{ marginTop: 8 }}>
<Text strong></Text>
<div><Text type="secondary"></Text></div>
</div>
</div>
</Card>
</Col>
</Row>
<Divider />
<Title level={5}></Title>
<Form.Item name="orderAlerts" valuePropName="checked">
<Checkbox> - </Checkbox>
</Form.Item>
<Form.Item name="inventoryAlerts" valuePropName="checked">
<Checkbox> - </Checkbox>
</Form.Item>
<Form.Item name="complianceAlerts" valuePropName="checked">
<Checkbox> - </Checkbox>
</Form.Item>
<Form.Item name="systemAlerts" valuePropName="checked">
<Checkbox> - </Checkbox>
</Form.Item>
<Form.Item name="marketingEmails" valuePropName="checked">
<Checkbox> - </Checkbox>
</Form.Item>
<Divider />
<Title level={5}></Title>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="digestFrequency" label="通知摘要频率">
<Select>
<Option value="realtime"></Option>
<Option value="hourly"></Option>
<Option value="daily"></Option>
<Option value="weekly"></Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="quietHoursStart" label="免打扰开始时间">
<TimePicker format="HH:mm" style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="quietHoursEnd" label="免打扰结束时间">
<TimePicker format="HH:mm" style={{ width: '100%' }} />
</Form.Item>
</Col>
</Row>
<Form.Item>
<Button type="primary" icon={<SaveOutlined />} onClick={handleNotificationSave} loading={saving}>
</Button>
</Form.Item>
</Form>
</Card>
</TabPane>
{/* 安全设置 */}
<TabPane
tab={
<span>
<SafetyOutlined />
</span>
}
key="security"
>
<Card>
<List>
<List.Item
actions={[
<Button type="primary" onClick={() => setPasswordModalVisible(true)}>
</Button>,
]}
>
<List.Item.Meta
avatar={<LockOutlined style={{ fontSize: 24, color: '#1890ff' }} />}
title="登录密码"
description={`上次修改: ${securitySettings.lastPasswordChange}`}
/>
</List.Item>
<List.Item
actions={[
<Switch
checked={securitySettings.twoFactorEnabled}
onChange={handleTwoFactorToggle}
/>,
]}
>
<List.Item.Meta
avatar={<SafetyOutlined style={{ fontSize: 24, color: '#52c41a' }} />}
title="双因素认证 (2FA)"
description="启用后,登录时需要输入手机验证码"
/>
</List.Item>
<List.Item
actions={[
<Switch
checked={securitySettings.loginNotification}
onChange={(checked) => setSecuritySettings({ ...securitySettings, loginNotification: checked })}
/>,
]}
>
<List.Item.Meta
avatar={<BellOutlined style={{ fontSize: 24, color: '#faad14' }} />}
title="登录通知"
description="新设备登录时发送通知"
/>
</List.Item>
</List>
<Divider />
<Form form={securityForm} layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="passwordExpiryDays"
label="密码过期天数"
tooltip="密码将在指定天数后过期,需要重新设置"
>
<Slider min={30} max={180} marks={{ 30: '30天', 90: '90天', 180: '180天' }} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="sessionTimeout"
label="会话超时时间(分钟)"
tooltip="超过指定时间无操作将自动登出"
>
<Slider min={5} max={120} marks={{ 15: '15分', 30: '30分', 60: '60分' }} />
</Form.Item>
</Col>
</Row>
<Form.Item>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSecuritySave} loading={saving}>
</Button>
</Form.Item>
</Form>
</Card>
</TabPane>
{/* API密钥 */}
<TabPane
tab={
<span>
<ApiOutlined />
API密钥
</span>
}
key="apikeys"
>
<Card
extra={
<Button type="primary" icon={<PlusOutlined />} onClick={() => setApiKeyModalVisible(true)}>
API密钥
</Button>
}
>
<Alert
message="API密钥安全提示"
description="请妥善保管您的API密钥不要在客户端代码中暴露。如怀疑密钥泄露请立即删除并重新创建。"
type="warning"
showIcon
style={{ marginBottom: 16 }}
/>
<Table
columns={apiKeyColumns}
dataSource={apiKeys}
rowKey="id"
pagination={{ pageSize: 5 }}
/>
</Card>
</TabPane>
{/* 系统设置 */}
<TabPane
tab={
<span>
<SettingOutlined />
</span>
}
key="system"
>
<Card>
<Form form={systemForm} layout="vertical">
<Title level={5}></Title>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="autoSync" valuePropName="checked" label="自动同步">
<Switch />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="syncInterval" label="同步间隔(分钟)">
<Select>
<Option value={5}>5</Option>
<Option value={15}>15</Option>
<Option value={30}>30</Option>
<Option value={60}>1</Option>
</Select>
</Form.Item>
</Col>
</Row>
<Divider />
<Title level={5}></Title>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="dataRetentionDays" label="数据保留天数">
<Slider min={30} max={1095} marks={{ 90: '3月', 365: '1年', 730: '2年', 1095: '3年' }} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="backupEnabled" valuePropName="checked" label="启用自动备份">
<Switch />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item name="backupFrequency" label="备份频率">
<Select>
<Option value="daily"></Option>
<Option value="weekly"></Option>
<Option value="monthly"></Option>
</Select>
</Form.Item>
</Col>
</Row>
<Divider />
<Title level={5}></Title>
<Row gutter={16}>
<Col span={8}>
<Form.Item name="theme" label="主题">
<Select>
<Option value="light"></Option>
<Option value="dark"></Option>
<Option value="auto"></Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="dateFormat" label="日期格式">
<Select>
<Option value="YYYY-MM-DD">YYYY-MM-DD</Option>
<Option value="DD/MM/YYYY">DD/MM/YYYY</Option>
<Option value="MM/DD/YYYY">MM/DD/YYYY</Option>
</Select>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="currency" label="货币">
<Select>
<Option value="CNY"> (CNY)</Option>
<Option value="USD"> (USD)</Option>
<Option value="EUR"> (EUR)</Option>
<Option value="JPY"> (JPY)</Option>
</Select>
</Form.Item>
</Col>
</Row>
<Divider />
<Title level={5}></Title>
<Form.Item name="logLevel" label="日志级别">
<Radio.Group>
<Radio.Button value="debug"></Radio.Button>
<Radio.Button value="info"></Radio.Button>
<Radio.Button value="warn"></Radio.Button>
<Radio.Button value="error"></Radio.Button>
</Radio.Group>
</Form.Item>
<Form.Item>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSystemSave} loading={saving}>
</Button>
</Form.Item>
</Form>
</Card>
</TabPane>
{/* 操作日志 */}
<TabPane
tab={
<span>
<FileTextOutlined />
</span>
}
key="logs"
>
<Card>
<Table
columns={logColumns}
dataSource={operationLogs}
rowKey="id"
pagination={{ pageSize: 10 }}
/>
</Card>
</TabPane>
{/* 配置管理 */}
<TabPane
tab={
<span>
<SettingOutlined />
</span>
}
key="configs"
>
<Row gutter={[16, 16]}>
<Col span={12}>
<Card
hoverable
onClick={() => window.location.href = '/Settings/PlatformAccountConfig'}
>
<div style={{ textAlign: 'center' }}>
<ApiOutlined style={{ fontSize: 48, color: '#1890ff' }} />
<Title level={4} style={{ marginTop: 16 }}></Title>
<Text type="secondary">API账号和授权信息</Text>
</div>
</Card>
</Col>
<Col span={12}>
<Card
hoverable
onClick={() => window.location.href = '/Settings/ExchangeRateConfig'}
>
<div style={{ textAlign: 'center' }}>
<GlobalOutlined style={{ fontSize: 48, color: '#52c41a' }} />
<Title level={4} style={{ marginTop: 16 }}></Title>
<Text type="secondary"></Text>
</div>
</Card>
</Col>
<Col span={12}>
<Card
hoverable
onClick={() => window.location.href = '/Settings/CostTemplateConfig'}
>
<div style={{ textAlign: 'center' }}>
<DollarOutlined style={{ fontSize: 48, color: '#faad14' }} />
<Title level={4} style={{ marginTop: 16 }}></Title>
<Text type="secondary"></Text>
</div>
</Card>
</Col>
<Col span={12}>
<Card
hoverable
onClick={() => window.location.href = '/Settings/WinNodeConfig'}
>
<div style={{ textAlign: 'center' }}>
<DesktopOutlined style={{ fontSize: 48, color: '#722ed1' }} />
<Title level={4} style={{ marginTop: 16 }}>WinNode配置</Title>
<Text type="secondary">Windows执行节点和浏览器实例</Text>
</div>
</Card>
</Col>
</Row>
</TabPane>
</Tabs>
{/* 修改密码模态框 */}
<Modal
title="修改密码"
open={passwordModalVisible}
onOk={handlePasswordChange}
onCancel={() => {
setPasswordModalVisible(false);
passwordForm.resetFields();
}}
>
<Form form={passwordForm} layout="vertical">
<Form.Item
name="currentPassword"
label="当前密码"
rules={[{ required: true, message: '请输入当前密码' }]}
>
<Input.Password placeholder="当前密码" />
</Form.Item>
<Form.Item
name="newPassword"
label="新密码"
rules={[
{ required: true, message: '请输入新密码' },
{ min: 8, message: '密码至少8位' },
]}
>
<Input.Password placeholder="新密码" />
</Form.Item>
<Form.Item
name="confirmPassword"
label="确认新密码"
rules={[{ required: true, message: '请确认新密码' }]}
>
<Input.Password placeholder="确认新密码" />
</Form.Item>
</Form>
</Modal>
{/* 创建API密钥模态框 */}
<Modal
title="创建API密钥"
open={apiKeyModalVisible}
onOk={handleCreateApiKey}
onCancel={() => {
setApiKeyModalVisible(false);
apiKeyForm.resetFields();
}}
>
<Form form={apiKeyForm} layout="vertical">
<Form.Item
name="name"
label="密钥名称"
rules={[{ required: true, message: '请输入密钥名称' }]}
>
<Input placeholder="例如Production API Key" />
</Form.Item>
<Form.Item
name="environment"
label="环境"
rules={[{ required: true, message: '请选择环境' }]}
>
<Select placeholder="选择环境">
<Option value="live"></Option>
<Option value="test"></Option>
</Select>
</Form.Item>
<Form.Item
name="permissions"
label="权限"
rules={[{ required: true, message: '请选择权限' }]}
>
<Checkbox.Group>
<Checkbox value="read"></Checkbox>
<Checkbox value="write"></Checkbox>
</Checkbox.Group>
</Form.Item>
</Form>
</Modal>
{/* 双因素认证模态框 */}
<Modal
title="启用双因素认证"
open={twoFactorModalVisible}
onOk={() => {
setSecuritySettings({ ...securitySettings, twoFactorEnabled: true });
setTwoFactorModalVisible(false);
message.success('双因素认证已启用');
}}
onCancel={() => setTwoFactorModalVisible(false)}
>
<div style={{ textAlign: 'center' }}>
<SafetyOutlined style={{ fontSize: 48, color: '#52c41a' }} />
<p style={{ marginTop: 16 }}>
</p>
<p>
</p>
</div>
</Modal>
</div>
);
};
export default Settings;