Initial commit

This commit is contained in:
2026-02-06 14:06:49 +08:00
commit 5fc7b33b3b
28 changed files with 5004 additions and 0 deletions

202
src/pages/Profile.tsx Normal file
View File

@@ -0,0 +1,202 @@
import { useState, useEffect } from 'react';
import { Form, Input, Button, Card, message, Avatar, Descriptions, Space, Modal } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import { authApi } from '@/services/api';
import type { User } from '@/types';
function ProfilePage() {
const [profileForm] = Form.useForm();
const [passwordForm] = Form.useForm();
const [loading, setLoading] = useState(false);
const [passwordModalVisible, setPasswordModalVisible] = useState(false);
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
loadUserProfile();
}, []);
const loadUserProfile = () => {
const currentUser = authApi.getCurrentUser();
if (currentUser) {
setUser(currentUser);
profileForm.setFieldsValue({
username: currentUser.username,
name: currentUser.name,
email: currentUser.email,
role: currentUser.role,
createdAt: new Date(currentUser.createdAt).toLocaleString('zh-CN'),
});
}
};
const handleUpdateProfile = async (values: any) => {
setLoading(true);
try {
const updatedUser = await authApi.updateProfile({
name: values.name,
email: values.email,
});
setUser(updatedUser);
message.success('更新资料成功!');
} catch (error: any) {
message.error(error.message || '更新资料失败');
} finally {
setLoading(false);
}
};
const handleChangePassword = async (values: any) => {
setLoading(true);
try {
await authApi.changePassword(values.currentPassword, values.newPassword);
message.success('修改密码成功!');
setPasswordModalVisible(false);
passwordForm.resetFields();
} catch (error: any) {
message.error(error.message || '修改密码失败');
} finally {
setLoading(false);
}
};
return (
<div style={{ maxWidth: '800px', margin: '0 auto' }}>
<Card
title={
<span>
<UserOutlined />
</span>
}
style={{ marginBottom: '24px' }}
>
{user && (
<Descriptions column={1} bordered style={{ marginBottom: '24px' }}>
<Descriptions.Item label="头像">
<Avatar icon={<UserOutlined />} size={64} />
</Descriptions.Item>
<Descriptions.Item label="用户名">{user.username}</Descriptions.Item>
<Descriptions.Item label="姓名">{user.name}</Descriptions.Item>
<Descriptions.Item label="邮箱">{user.email || '-'}</Descriptions.Item>
<Descriptions.Item label="角色">{user.role}</Descriptions.Item>
<Descriptions.Item label="创建时间">
{new Date(user.createdAt).toLocaleString('zh-CN')}
</Descriptions.Item>
</Descriptions>
)}
<Form
form={profileForm}
onFinish={handleUpdateProfile}
layout="vertical"
>
<Form.Item
label="姓名"
name="name"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input />
</Form.Item>
<Form.Item
label="邮箱"
name="email"
rules={[{ type: 'email', message: '请输入有效的邮箱地址' }]}
>
<Input />
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit" loading={loading}>
</Button>
<Button onClick={loadUserProfile}>
</Button>
</Space>
</Form.Item>
</Form>
</Card>
<Card
title={
<span>
<LockOutlined />
</span>
}
extra={
<Button type="primary" onClick={() => setPasswordModalVisible(true)}>
</Button>
}
/>
<Modal
title="修改密码"
open={passwordModalVisible}
onCancel={() => setPasswordModalVisible(false)}
footer={null}
>
<Form
form={passwordForm}
onFinish={handleChangePassword}
layout="vertical"
>
<Form.Item
label="当前密码"
name="currentPassword"
rules={[{ required: true, message: '请输入当前密码' }]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="新密码"
name="newPassword"
rules={[
{ required: true, message: '请输入新密码' },
{ min: 6, message: '密码至少6位' },
]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="确认新密码"
name="confirmPassword"
dependencies={['newPassword']}
rules={[
{ required: true, message: '请确认新密码' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('newPassword') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次输入的密码不一致'));
},
}),
]}
>
<Input.Password />
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit" loading={loading}>
</Button>
<Button onClick={() => {
setPasswordModalVisible(false);
passwordForm.resetFields();
}}>
</Button>
</Space>
</Form.Item>
</Form>
</Modal>
</div>
);
}
export default ProfilePage;