159 lines
5.1 KiB
TypeScript
159 lines
5.1 KiB
TypeScript
import {
|
|
Button,
|
|
Card,
|
|
Form,
|
|
Input,
|
|
message,
|
|
Tabs,
|
|
Typography,
|
|
Row,
|
|
Col,
|
|
Space,
|
|
Avatar
|
|
} from "antd";
|
|
import { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { getCurrentUser, updateMyProfile, updateMyPassword } from "../api";
|
|
import { UserOutlined, LockOutlined, SaveOutlined, SolutionOutlined } from "@ant-design/icons";
|
|
import type { UserProfile } from "../types";
|
|
import PageHeader from "../components/shared/PageHeader";
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
export default function Profile() {
|
|
const { t } = useTranslation();
|
|
const [loading, setLoading] = useState(false);
|
|
const [saving, setSaving] = useState(false);
|
|
const [user, setUser] = useState<UserProfile | null>(null);
|
|
const [profileForm] = Form.useForm();
|
|
const [pwdForm] = Form.useForm();
|
|
|
|
const loadUser = async () => {
|
|
setLoading(true);
|
|
try {
|
|
const data = await getCurrentUser();
|
|
setUser(data);
|
|
profileForm.setFieldsValue(data);
|
|
} catch (e) {
|
|
// Interceptor handles error
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadUser();
|
|
}, []);
|
|
|
|
const handleUpdateProfile = async () => {
|
|
try {
|
|
const values = await profileForm.validateFields();
|
|
setSaving(true);
|
|
await updateMyProfile(values);
|
|
message.success(t('common.success'));
|
|
loadUser();
|
|
} catch (e) {
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleUpdatePassword = async () => {
|
|
try {
|
|
const values = await pwdForm.validateFields();
|
|
setSaving(true);
|
|
await updateMyPassword(values);
|
|
message.success(t('common.success'));
|
|
pwdForm.resetFields();
|
|
} catch (e) {
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="p-6 max-w-4xl mx-auto">
|
|
<PageHeader
|
|
title="个人中心"
|
|
subtitle="管理您的个人基础信息及账号安全设置"
|
|
/>
|
|
|
|
<Row gutter={24}>
|
|
<Col span={8}>
|
|
<Card className="text-center shadow-sm">
|
|
<Avatar size={80} icon={<UserOutlined />} style={{ backgroundColor: '#1677ff', marginBottom: 16 }} />
|
|
<Title level={5} style={{ margin: 0 }}>{user?.displayName}</Title>
|
|
<Text type="secondary">@{user?.username}</Text>
|
|
<div className="mt-4">
|
|
{user?.isPlatformAdmin ? <Tag color="gold">平台管理员</Tag> : <Tag color="blue">普通用户</Tag>}
|
|
</div>
|
|
</Card>
|
|
</Col>
|
|
|
|
<Col span={16}>
|
|
<Card className="shadow-sm">
|
|
<Tabs defaultActiveKey="basic">
|
|
<Tabs.TabPane
|
|
tab={<span><SolutionOutlined />基本信息</span>}
|
|
key="basic"
|
|
>
|
|
<Form form={profileForm} layout="vertical" onFinish={handleUpdateProfile} style={{ marginTop: 16 }}>
|
|
<Form.Item label="显示姓名" name="displayName" rules={[{ required: true }]}>
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item label="邮箱" name="email">
|
|
<Input />
|
|
</Form.Item>
|
|
<Form.Item label="手机号" name="phone">
|
|
<Input />
|
|
</Form.Item>
|
|
<Button type="primary" icon={<SaveOutlined />} loading={saving} onClick={() => profileForm.submit()}>
|
|
保存修改
|
|
</Button>
|
|
</Form>
|
|
</Tabs.TabPane>
|
|
|
|
<Tabs.TabPane
|
|
tab={<span><LockOutlined />安全设置</span>}
|
|
key="password"
|
|
>
|
|
<Form form={pwdForm} layout="vertical" onFinish={handleUpdatePassword} style={{ marginTop: 16 }}>
|
|
<Form.Item label="旧密码" name="oldPassword" rules={[{ required: true }]}>
|
|
<Input.Password />
|
|
</Form.Item>
|
|
<Form.Item label="新密码" name="newPassword" rules={[{ required: true, min: 6 }]}>
|
|
<Input.Password />
|
|
</Form.Item>
|
|
<Form.Item
|
|
label="确认新密码"
|
|
name="confirmPassword"
|
|
dependencies={['newPassword']}
|
|
rules={[
|
|
{ required: true },
|
|
({ getFieldValue }) => ({
|
|
validator(_, value) {
|
|
if (!value || getFieldValue('newPassword') === value) {
|
|
return Promise.resolve();
|
|
}
|
|
return Promise.reject(new Error('两次输入的密码不一致'));
|
|
},
|
|
}),
|
|
]}
|
|
>
|
|
<Input.Password />
|
|
</Form.Item>
|
|
<Button type="primary" danger loading={saving} onClick={() => pwdForm.submit()}>
|
|
修改密码
|
|
</Button>
|
|
</Form>
|
|
</Tabs.TabPane>
|
|
</Tabs>
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
import { Tag } from "antd";
|