forked from quant-speed-AI/Scoring-System
创赢未来评分系统 - 初始化提交(移除大文件)
This commit is contained in:
124
frontend/src/components/ProfileModal.jsx
Normal file
124
frontend/src/components/ProfileModal.jsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Modal, Form, Input, Upload, Button, message, Avatar } from 'antd';
|
||||
import { UserOutlined, UploadOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { updateUserInfo, uploadUserAvatar } from '../api';
|
||||
|
||||
const ProfileModal = ({ visible, onClose }) => {
|
||||
const { user, updateUser } = useAuth();
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [avatarUrl, setAvatarUrl] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (visible && user) {
|
||||
form.setFieldsValue({
|
||||
nickname: user.nickname,
|
||||
});
|
||||
setAvatarUrl(user.avatar_url);
|
||||
}
|
||||
}, [visible, user, form]);
|
||||
|
||||
const handleUpload = async (file) => {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
||||
if (!isJpgOrPng) {
|
||||
message.error('You can only upload JPG/PNG file!');
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
if (!isLt2M) {
|
||||
message.error('Image must smaller than 2MB!');
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
setUploading(true);
|
||||
try {
|
||||
const res = await uploadUserAvatar(formData);
|
||||
if (res.data.success) {
|
||||
setAvatarUrl(res.data.file_url);
|
||||
message.success('头像上传成功');
|
||||
} else {
|
||||
message.error('头像上传失败: ' + (res.data.message || '未知错误'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload failed:', error);
|
||||
message.error('头像上传失败');
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
return false; // Prevent default auto upload
|
||||
};
|
||||
|
||||
const handleOk = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
setLoading(true);
|
||||
|
||||
const updateData = {
|
||||
nickname: values.nickname,
|
||||
avatar_url: avatarUrl
|
||||
};
|
||||
|
||||
const res = await updateUserInfo(updateData);
|
||||
updateUser(res.data);
|
||||
message.success('个人信息更新成功');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
console.error('Update failed:', error);
|
||||
message.error('更新失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="个人设置"
|
||||
open={visible}
|
||||
onOk={handleOk}
|
||||
onCancel={onClose}
|
||||
confirmLoading={loading}
|
||||
centered
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
style={{ marginTop: 20 }}
|
||||
>
|
||||
<Form.Item label="头像" style={{ textAlign: 'center' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 15 }}>
|
||||
<Avatar
|
||||
size={100}
|
||||
src={avatarUrl}
|
||||
icon={<UserOutlined />}
|
||||
/>
|
||||
<Upload
|
||||
name="avatar"
|
||||
showUploadList={false}
|
||||
beforeUpload={handleUpload}
|
||||
accept="image/*"
|
||||
>
|
||||
<Button icon={uploading ? <LoadingOutlined /> : <UploadOutlined />} loading={uploading}>
|
||||
{uploading ? '上传中...' : '更换头像'}
|
||||
</Button>
|
||||
</Upload>
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="nickname"
|
||||
label="昵称"
|
||||
rules={[{ required: true, message: '请输入昵称' }]}
|
||||
>
|
||||
<Input placeholder="请输入昵称" maxLength={20} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileModal;
|
||||
Reference in New Issue
Block a user