feat: 添加前端页面和业务说明书
refactor(server): 重构服务层代码结构 feat(server): 添加基础设施、跨境电商、AI决策等核心服务 docs: 完善前端业务说明书和开发进度文档 style: 格式化代码和文档
This commit is contained in:
189
dashboard/src/pages/Settings/ProfileSettings.tsx
Normal file
189
dashboard/src/pages/Settings/ProfileSettings.tsx
Normal file
@@ -0,0 +1,189 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Form, Input, Button, Upload, Avatar, message } from 'antd';
|
||||
import { UserOutlined, SaveOutlined, ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
interface ProfileData {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
position: string;
|
||||
department: string;
|
||||
bio: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
const ProfileSettings: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [avatar, setAvatar] = useState<string>('https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50');
|
||||
|
||||
const initialProfile: ProfileData = {
|
||||
name: 'John Doe',
|
||||
email: 'john.doe@example.com',
|
||||
phone: '+1 (123) 456-7890',
|
||||
position: 'Product Manager',
|
||||
department: 'Marketing',
|
||||
bio: 'Product manager with 5 years of experience in e-commerce.',
|
||||
avatar: 'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50',
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: any) => {
|
||||
setLoading(true);
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
message.success('个人设置已更新');
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
navigate('/settings');
|
||||
};
|
||||
|
||||
const handleAvatarChange = (info: any) => {
|
||||
if (info.file.status === 'done') {
|
||||
// 模拟上传成功
|
||||
setAvatar('https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50');
|
||||
message.success('头像上传成功');
|
||||
} else if (info.file.status === 'error') {
|
||||
message.error('头像上传失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="profile-settings">
|
||||
<div className="page-header">
|
||||
<h1>个人设置</h1>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={handleBack}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card title="个人信息">
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
initialValues={initialProfile}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 24 }}>
|
||||
<Upload
|
||||
name="avatar"
|
||||
showUploadList={false}
|
||||
action="/api/upload"
|
||||
onChange={handleAvatarChange}
|
||||
>
|
||||
<Avatar size={100} icon={<UserOutlined />} src={avatar} />
|
||||
</Upload>
|
||||
<div style={{ marginLeft: 24 }}>
|
||||
<p>点击头像上传新的头像</p>
|
||||
<p style={{ color: '#999' }}>支持 JPG, PNG 格式,最大 2MB</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="姓名"
|
||||
rules={[{ required: true, message: '请输入姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入姓名" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="email"
|
||||
label="邮箱"
|
||||
rules={[{ required: true, message: '请输入邮箱' }]}
|
||||
>
|
||||
<Input placeholder="请输入邮箱" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="phone"
|
||||
label="电话"
|
||||
rules={[{ required: true, message: '请输入电话' }]}
|
||||
>
|
||||
<Input placeholder="请输入电话" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="position"
|
||||
label="职位"
|
||||
rules={[{ required: true, message: '请输入职位' }]}
|
||||
>
|
||||
<Input placeholder="请输入职位" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="department"
|
||||
label="部门"
|
||||
rules={[{ required: true, message: '请输入部门' }]}
|
||||
>
|
||||
<Input placeholder="请输入部门" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
name="bio"
|
||||
label="个人简介"
|
||||
>
|
||||
<TextArea rows={4} placeholder="请输入个人简介" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={loading} icon={<SaveOutlined />}>
|
||||
保存
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card title="密码设置" style={{ marginTop: 24 }}>
|
||||
<Form
|
||||
layout="vertical"
|
||||
>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
|
||||
<Form.Item
|
||||
name="currentPassword"
|
||||
label="当前密码"
|
||||
rules={[{ required: true, message: '请输入当前密码' }]}
|
||||
>
|
||||
<Input.Password placeholder="请输入当前密码" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="newPassword"
|
||||
label="新密码"
|
||||
rules={[{ required: true, message: '请输入新密码' }]}
|
||||
>
|
||||
<Input.Password placeholder="请输入新密码" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="confirmPassword"
|
||||
label="确认密码"
|
||||
rules={[{ required: true, message: '请确认新密码' }]}
|
||||
>
|
||||
<Input.Password placeholder="请确认新密码" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" icon={<SaveOutlined />}>
|
||||
修改密码
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileSettings;
|
||||
187
dashboard/src/pages/Settings/TenantSettings.tsx
Normal file
187
dashboard/src/pages/Settings/TenantSettings.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Form, Input, Select, Button, Switch, message } from 'antd';
|
||||
import { SaveOutlined, ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
interface TenantData {
|
||||
name: string;
|
||||
domain: string;
|
||||
industry: string;
|
||||
timezone: string;
|
||||
currency: string;
|
||||
language: string;
|
||||
enableTwoFactor: boolean;
|
||||
enableNotifications: boolean;
|
||||
enableAnalytics: boolean;
|
||||
}
|
||||
|
||||
const TenantSettings: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const initialTenant: TenantData = {
|
||||
name: 'Acme Inc.',
|
||||
domain: 'acme.example.com',
|
||||
industry: 'E-commerce',
|
||||
timezone: 'Asia/Shanghai',
|
||||
currency: 'USD',
|
||||
language: 'en',
|
||||
enableTwoFactor: false,
|
||||
enableNotifications: true,
|
||||
enableAnalytics: true,
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: any) => {
|
||||
setLoading(true);
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
message.success('租户设置已更新');
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
navigate('/settings');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="tenant-settings">
|
||||
<div className="page-header">
|
||||
<h1>租户设置</h1>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={handleBack}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card title="基本信息">
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
initialValues={initialTenant}
|
||||
>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="租户名称"
|
||||
rules={[{ required: true, message: '请输入租户名称' }]}
|
||||
>
|
||||
<Input placeholder="请输入租户名称" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="domain"
|
||||
label="域名"
|
||||
rules={[{ required: true, message: '请输入域名' }]}
|
||||
>
|
||||
<Input placeholder="请输入域名" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="industry"
|
||||
label="行业"
|
||||
rules={[{ required: true, message: '请选择行业' }]}
|
||||
>
|
||||
<Select placeholder="请选择行业">
|
||||
<Option value="E-commerce">E-commerce</Option>
|
||||
<Option value="Retail">Retail</Option>
|
||||
<Option value="Manufacturing">Manufacturing</Option>
|
||||
<Option value="Technology">Technology</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="timezone"
|
||||
label="时区"
|
||||
rules={[{ required: true, message: '请选择时区' }]}
|
||||
>
|
||||
<Select placeholder="请选择时区">
|
||||
<Option value="Asia/Shanghai">Asia/Shanghai</Option>
|
||||
<Option value="America/New_York">America/New_York</Option>
|
||||
<Option value="Europe/London">Europe/London</Option>
|
||||
<Option value="Asia/Tokyo">Asia/Tokyo</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="currency"
|
||||
label="货币"
|
||||
rules={[{ required: true, message: '请选择货币' }]}
|
||||
>
|
||||
<Select placeholder="请选择货币">
|
||||
<Option value="USD">USD</Option>
|
||||
<Option value="CNY">CNY</Option>
|
||||
<Option value="EUR">EUR</Option>
|
||||
<Option value="GBP">GBP</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="language"
|
||||
label="语言"
|
||||
rules={[{ required: true, message: '请选择语言' }]}
|
||||
>
|
||||
<Select placeholder="请选择语言">
|
||||
<Option value="en">English</Option>
|
||||
<Option value="zh">中文</Option>
|
||||
<Option value="ja">日本語</Option>
|
||||
<Option value="ko">한국어</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={loading} icon={<SaveOutlined />}>
|
||||
保存
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card title="功能设置" style={{ marginTop: 24 }}>
|
||||
<Form
|
||||
layout="vertical"
|
||||
initialValues={initialTenant}
|
||||
>
|
||||
<Form.Item
|
||||
name="enableTwoFactor"
|
||||
label="启用双因素认证"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="enableNotifications"
|
||||
label="启用通知"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="enableAnalytics"
|
||||
label="启用数据分析"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" icon={<SaveOutlined />}>
|
||||
保存设置
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TenantSettings;
|
||||
315
dashboard/src/pages/Settings/UserManagement.tsx
Normal file
315
dashboard/src/pages/Settings/UserManagement.tsx
Normal file
@@ -0,0 +1,315 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Button, Input, Select, message, Card, Modal, Form } from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, SearchOutlined, ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const { Option } = Select;
|
||||
const { Search } = Input;
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role: string;
|
||||
status: 'active' | 'inactive';
|
||||
createdAt: string;
|
||||
lastLogin: string;
|
||||
}
|
||||
|
||||
const UserManagement: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [filters, setFilters] = useState({
|
||||
role: '',
|
||||
status: '',
|
||||
search: '',
|
||||
});
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
useEffect(() => {
|
||||
fetchUsers();
|
||||
}, [filters]);
|
||||
|
||||
const fetchUsers = async () => {
|
||||
setLoading(true);
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
const mockUsers: User[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Doe',
|
||||
email: 'john.doe@example.com',
|
||||
role: 'ADMIN',
|
||||
status: 'active',
|
||||
createdAt: '2026-01-01',
|
||||
lastLogin: '2026-03-17',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Jane Smith',
|
||||
email: 'jane.smith@example.com',
|
||||
role: 'MANAGER',
|
||||
status: 'active',
|
||||
createdAt: '2026-01-02',
|
||||
lastLogin: '2026-03-16',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Bob Johnson',
|
||||
email: 'bob.johnson@example.com',
|
||||
role: 'OPERATOR',
|
||||
status: 'active',
|
||||
createdAt: '2026-01-03',
|
||||
lastLogin: '2026-03-15',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Alice Brown',
|
||||
email: 'alice.brown@example.com',
|
||||
role: 'FINANCE',
|
||||
status: 'inactive',
|
||||
createdAt: '2026-01-04',
|
||||
lastLogin: '2026-03-10',
|
||||
},
|
||||
];
|
||||
setUsers(mockUsers);
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleAddUser = () => {
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const handleEditUser = (id: string) => {
|
||||
message.info('编辑用户功能开发中');
|
||||
};
|
||||
|
||||
const handleDeleteUser = (id: string) => {
|
||||
message.success('用户已删除');
|
||||
fetchUsers();
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: any) => {
|
||||
setLoading(true);
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
message.success('用户已添加');
|
||||
setIsModalVisible(false);
|
||||
setLoading(false);
|
||||
fetchUsers();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const handleBack = () => {
|
||||
navigate('/settings');
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
dataIndex: 'email',
|
||||
key: 'email',
|
||||
},
|
||||
{
|
||||
title: '角色',
|
||||
dataIndex: 'role',
|
||||
key: 'role',
|
||||
render: (role: string) => {
|
||||
const roleMap = {
|
||||
ADMIN: '管理员',
|
||||
MANAGER: '运营主管',
|
||||
OPERATOR: '运营专员',
|
||||
FINANCE: '财务主管',
|
||||
SOURCING: '采购专家',
|
||||
LOGISTICS: '物流专家',
|
||||
ANALYST: '数据分析师',
|
||||
};
|
||||
return roleMap[role] || role;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => {
|
||||
const statusMap = {
|
||||
active: '活跃',
|
||||
inactive: '非活跃',
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
},
|
||||
{
|
||||
title: '最后登录',
|
||||
dataIndex: 'lastLogin',
|
||||
key: 'lastLogin',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_: any, record: User) => (
|
||||
<div>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleEditUser(record.id)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteUser(record.id)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="user-management">
|
||||
<div className="page-header">
|
||||
<h1>用户管理</h1>
|
||||
<div style={{ display: 'flex', gap: 16 }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAddUser}
|
||||
>
|
||||
添加用户
|
||||
</Button>
|
||||
<Button
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={handleBack}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="filter-section" style={{ marginBottom: 24, display: 'flex', gap: 16, flexWrap: 'wrap' }}>
|
||||
<Search
|
||||
placeholder="搜索用户名或邮箱"
|
||||
style={{ width: 300 }}
|
||||
onChange={(e) => setFilters({ ...filters, search: e.target.value })}
|
||||
/>
|
||||
<Select
|
||||
placeholder="角色"
|
||||
style={{ width: 120 }}
|
||||
onChange={(value) => setFilters({ ...filters, role: value })}
|
||||
>
|
||||
<Option value="">全部</Option>
|
||||
<Option value="ADMIN">管理员</Option>
|
||||
<Option value="MANAGER">运营主管</Option>
|
||||
<Option value="OPERATOR">运营专员</Option>
|
||||
<Option value="FINANCE">财务主管</Option>
|
||||
</Select>
|
||||
<Select
|
||||
placeholder="状态"
|
||||
style={{ width: 120 }}
|
||||
onChange={(value) => setFilters({ ...filters, status: value })}
|
||||
>
|
||||
<Option value="">全部</Option>
|
||||
<Option value="active">活跃</Option>
|
||||
<Option value="inactive">非活跃</Option>
|
||||
</Select>
|
||||
<Button
|
||||
icon={<SearchOutlined />}
|
||||
onClick={fetchUsers}
|
||||
>
|
||||
筛选
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Card title="用户列表">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={users}
|
||||
loading={loading}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
title="添加用户"
|
||||
open={isModalVisible}
|
||||
onCancel={() => setIsModalVisible(false)}
|
||||
footer={null}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="姓名"
|
||||
rules={[{ required: true, message: '请输入姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入姓名" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="email"
|
||||
label="邮箱"
|
||||
rules={[{ required: true, message: '请输入邮箱' }]}
|
||||
>
|
||||
<Input placeholder="请输入邮箱" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password"
|
||||
label="密码"
|
||||
rules={[{ required: true, message: '请输入密码' }]}
|
||||
>
|
||||
<Input.Password placeholder="请输入密码" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="role"
|
||||
label="角色"
|
||||
rules={[{ required: true, message: '请选择角色' }]}
|
||||
>
|
||||
<Select placeholder="请选择角色">
|
||||
<Option value="ADMIN">管理员</Option>
|
||||
<Option value="MANAGER">运营主管</Option>
|
||||
<Option value="OPERATOR">运营专员</Option>
|
||||
<Option value="FINANCE">财务主管</Option>
|
||||
<Option value="SOURCING">采购专家</Option>
|
||||
<Option value="LOGISTICS">物流专家</Option>
|
||||
<Option value="ANALYST">数据分析师</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={loading}>
|
||||
保存
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserManagement;
|
||||
13
dashboard/src/pages/Settings/index.ts
Normal file
13
dashboard/src/pages/Settings/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import Settings from './index';
|
||||
import ProfileSettings from './ProfileSettings';
|
||||
import TenantSettings from './TenantSettings';
|
||||
import UserManagement from './UserManagement';
|
||||
|
||||
export {
|
||||
Settings,
|
||||
ProfileSettings,
|
||||
TenantSettings,
|
||||
UserManagement,
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
115
dashboard/src/pages/Settings/index.tsx
Normal file
115
dashboard/src/pages/Settings/index.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import React from 'react';
|
||||
import { Card, Row, Col, Button, Tabs } from 'antd';
|
||||
import { UserOutlined, TeamOutlined, SettingOutlined, LockOutlined, BellOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div className="settings">
|
||||
<div className="page-header">
|
||||
<h1>设置</h1>
|
||||
</div>
|
||||
|
||||
<Row gutter={16} style={{ marginBottom: 24 }}>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
icon={<UserOutlined />}
|
||||
onClick={() => navigate('/settings/profile')}
|
||||
>
|
||||
个人设置
|
||||
</Button>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
icon={<TeamOutlined />}
|
||||
onClick={() => navigate('/settings/tenant')}
|
||||
>
|
||||
租户设置
|
||||
</Button>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
icon={<UserOutlined />}
|
||||
onClick={() => navigate('/settings/users')}
|
||||
>
|
||||
用户管理
|
||||
</Button>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Card>
|
||||
<Button
|
||||
type="primary"
|
||||
block
|
||||
icon={<LockOutlined />}
|
||||
>
|
||||
安全设置
|
||||
</Button>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Tabs defaultActiveKey="overview">
|
||||
<TabPane tab="设置概览" key="overview">
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Card title="账户信息">
|
||||
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
||||
<p>账户信息设置</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card title="通知设置">
|
||||
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
||||
<p>通知设置</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="个人设置" key="profile">
|
||||
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
||||
<Button type="primary" onClick={() => navigate('/settings/profile')}>
|
||||
查看个人设置
|
||||
</Button>
|
||||
</div>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="租户设置" key="tenant">
|
||||
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
||||
<Button type="primary" onClick={() => navigate('/settings/tenant')}>
|
||||
查看租户设置
|
||||
</Button>
|
||||
</div>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="用户管理" key="users">
|
||||
<div style={{ textAlign: 'center', padding: '50px 0' }}>
|
||||
<Button type="primary" onClick={() => navigate('/settings/users')}>
|
||||
查看用户管理
|
||||
</Button>
|
||||
</div>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
Reference in New Issue
Block a user