feat(auth): add user information update feature and refactor the authentication service.

This commit is contained in:
ShiYu
2025-05-20 20:43:08 +08:00
parent 2c73fc29df
commit 97e3586cf8
10 changed files with 507 additions and 246 deletions

View File

@@ -1,4 +1,4 @@
import {type BaseResult, type AuthResponse, type LoginRequest, type RegisterRequest, type UserProfile} from './types';
import {type BaseResult, type AuthResponse, type LoginRequest, type RegisterRequest, type UserProfile, type UpdateUserRequest} from './types';
import {fetchApi, BASE_URL} from './fetchClient';
// 认证数据本地存储键
@@ -59,6 +59,36 @@ export async function getCurrentUser(): Promise<BaseResult<UserProfile>> {
}
}
// 更新用户信息
export async function updateUserInfo(data: UpdateUserRequest): Promise<BaseResult<UserProfile>> {
try {
const response = await fetchApi<UserProfile>('/auth/update', {
method: 'PUT',
body: JSON.stringify(data),
});
// 如果成功更新用户数据,更新本地存储
if (response.success && response.data) {
const user = getStoredUser();
if (user) {
const updatedUser = {
...user,
...response.data
};
localStorage.setItem(USER_KEY, JSON.stringify(updatedUser));
}
}
return response;
} catch (error: any) {
return {
success: false,
message: `更新用户信息失败: ${error.message}`,
code: 500
};
}
}
// 保存认证数据到本地存储
export const saveAuthData = (authData: AuthResponse): void => {
localStorage.setItem(TOKEN_KEY, authData.token);

View File

@@ -10,6 +10,7 @@ export {
register,
login,
getCurrentUser,
updateUserInfo, // 添加导出更新用户信息函数
saveAuthData,
clearAuthData,
isAuthenticated,

View File

@@ -198,3 +198,10 @@ export const UserRole = {
User: "User" as UserRole,
Guest: "" as UserRole
};
export interface UpdateUserRequest {
userName?: string;
email?: string;
currentPassword?: string;
newPassword?: string;
}

View File

@@ -1,12 +1,70 @@
import React from 'react';
import { Card, Form, Input, Button } from 'antd';
import React, { useState } from 'react';
import { Card, Form, Input, Button, message } from 'antd';
import { useAuth } from '../../api/AuthContext';
import UserAvatar from '../../components/UserAvatar';
import useIsMobile from '../../hooks/useIsMobile';
import { updateUserInfo } from '../../api';
const UserProfile: React.FC = () => {
const { user } = useAuth();
const { user, refreshUser } = useAuth();
const isMobile = useIsMobile();
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const handleSubmit = async (values: any) => {
// 验证两次密码输入是否一致
if (values.newPassword && values.newPassword !== values.confirmPassword) {
message.error('两次输入的密码不一致');
return;
}
setLoading(true);
try {
const updateData = {
userName: values.username !== user?.userName ? values.username : undefined,
email: values.email !== user?.email ? values.email : undefined,
currentPassword: values.currentPassword,
newPassword: values.newPassword
};
// 过滤掉空值
Object.keys(updateData).forEach(key => {
if (updateData[key as keyof typeof updateData] === undefined ||
updateData[key as keyof typeof updateData] === '') {
delete updateData[key as keyof typeof updateData];
}
});
// 如果没有需要更新的内容,直接返回
if (Object.keys(updateData).length === 0) {
message.info('没有内容需要更新');
setLoading(false);
return;
}
const response = await updateUserInfo(updateData);
if (response.success && response.data) {
message.success('个人信息更新成功');
// 更新Context中的用户信息
refreshUser();
// 清除密码字段
form.setFieldsValue({
currentPassword: '',
newPassword: '',
confirmPassword: ''
});
} else {
message.error(response.message || '更新失败');
}
} catch (error) {
console.error('更新个人信息时出错:', error);
message.error('系统错误,请稍后再试');
} finally {
setLoading(false);
}
};
return (
<Card
@@ -33,14 +91,23 @@ const UserProfile: React.FC = () => {
</div>
<Form
form={form}
layout="vertical"
initialValues={{
username: user?.userName || '',
email: user?.email || '',
}}
size={isMobile ? "middle" : "large"}
onFinish={handleSubmit}
>
<Form.Item name="username" label="用户名">
<Form.Item
name="username"
label="用户名"
rules={[
{ required: true, message: '请输入用户名' },
{ max: 50, message: '用户名最长50个字符' }
]}
>
<Input placeholder="用户名" />
</Form.Item>
@@ -48,19 +115,57 @@ const UserProfile: React.FC = () => {
<Input placeholder="邮箱" disabled />
</Form.Item>
<Form.Item name="password" label="更新密码">
<Input.Password placeholder="留空则不更改" />
<Form.Item
name="currentPassword"
label="当前密码"
rules={[
{
required: false,
message: '更改密码时需要输入当前密码'
}
]}
tooltip="修改密码时必填,其他情况可不填"
>
<Input.Password placeholder="只有修改密码时才需要填写" />
</Form.Item>
<Form.Item name="confirmPassword" label="确认新密码">
<Form.Item
name="newPassword"
label="新密码"
rules={[
{ min: 6, message: '密码至少6位' },
{ max: 20, message: '密码最长20位' }
]}
dependencies={['currentPassword']}
>
<Input.Password placeholder="留空则不更改密码" />
</Form.Item>
<Form.Item
name="confirmPassword"
label="确认新密码"
dependencies={['newPassword']}
rules={[
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('newPassword') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次输入的密码不一致'));
},
}),
]}
>
<Input.Password placeholder="确认新密码" />
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
block={isMobile}
size={isMobile ? "middle" : "large"}
loading={loading}
style={{
height: isMobile ? 40 : 'auto'
}}