imeeting/frontend/src/pages/Profile.tsx

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";