diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index aa32961..28626f5 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -8,7 +8,7 @@ using Foxel.Models.Response.Auth; namespace Foxel.Controllers; [Route("api/auth")] -public class AuthController(IUserService userService, IConfigService configService) : BaseApiController +public class AuthController(IAuthService authService, IConfigService configService) : BaseApiController { [HttpPost("register")] public async Task>> Register([FromBody] RegisterRequest request) @@ -18,13 +18,13 @@ public class AuthController(IUserService userService, IConfigService configServi return Error("请求数据无效"); } - var (success, message, user) = await userService.RegisterUserAsync(request); + var (success, message, user) = await authService.RegisterUserAsync(request); if (!success) { return Error(message); } - var token = await userService.GenerateJwtTokenAsync(user!); + var token = await authService.GenerateJwtTokenAsync(user!); var response = new AuthResponse { Token = token, @@ -48,13 +48,13 @@ public class AuthController(IUserService userService, IConfigService configServi return Error("请求数据无效"); } - var (success, message, user) = await userService.AuthenticateUserAsync(request); + var (success, message, user) = await authService.AuthenticateUserAsync(request); if (!success) { return Error(message, 401); } - var token = await userService.GenerateJwtTokenAsync(user!); + var token = await authService.GenerateJwtTokenAsync(user!); var response = new AuthResponse { Token = token, @@ -80,7 +80,7 @@ public class AuthController(IUserService userService, IConfigService configServi return Error("用户ID未找到"); } - var user = await userService.GetUserByIdAsync(userId.Value); + var user = await authService.GetUserByIdAsync(userId.Value); if (user == null) { return Error("未找到用户信息", 404); @@ -100,108 +100,52 @@ public class AuthController(IUserService userService, IConfigService configServi [HttpGet("github/login")] public IActionResult GitHubLogin() { - string githubClientId = configService["Authentication:GitHubClientId"]; - string githubCallback = configService["Authentication:GitHubCallbackUrl"]; - string githubAuthorizeUrl = - $"https://github.com/login/oauth/authorize?client_id={Uri.EscapeDataString(githubClientId)}&redirect_uri={Uri.EscapeDataString(githubCallback)}"; + string githubAuthorizeUrl = authService.GetGitHubLoginUrl(); return Redirect(githubAuthorizeUrl); } [HttpGet("github/callback")] public async Task>> GitHubCallback(string code) { - if (string.IsNullOrEmpty(code)) + var (success, message, token) = await authService.ProcessGitHubCallbackAsync(code); + + if (!success || token == null) { - return Error("GitHub授权码无效"); + return Redirect($"/login?error=github_auth_failed&message={Uri.EscapeDataString(message)}"); } - - string githubClientId = configService["Authentication:GitHubClientId"]; - string githubClientSecret = configService["Authentication:GitHubClientSecret"]; - string githubTokenUrl = "https://github.com/login/oauth/access_token"; - string githubUserApiUrl = "https://api.github.com/user"; - - using var httpClient = new HttpClient(); - httpClient.DefaultRequestHeaders.Add("User-Agent", "Foxel"); - httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); - var tokenRequestUrl = - $"{githubTokenUrl}?client_id={Uri.EscapeDataString(githubClientId)}&client_secret={Uri.EscapeDataString(githubClientSecret)}&code={Uri.EscapeDataString(code)}"; - var tokenResponse = await httpClient.PostAsync(tokenRequestUrl, null); - - if (!tokenResponse.IsSuccessStatusCode) - { - var errorContent = await tokenResponse.Content.ReadAsStringAsync(); - Console.WriteLine($"获取GitHub访问令牌失败: {tokenResponse.StatusCode}, {errorContent}"); - return Error($"获取GitHub访问令牌失败: {errorContent}", (int)tokenResponse.StatusCode); - } - - var tokenResponseContent = await tokenResponse.Content.ReadAsStringAsync(); - var tokenJson = System.Text.Json.JsonDocument.Parse(tokenResponseContent); - - if (!tokenJson.RootElement.TryGetProperty("access_token", out var accessTokenElement) || - accessTokenElement.GetString() == null) - { - Console.WriteLine($"GitHub响应中未找到access_token: {tokenResponseContent}"); - return Error("获取GitHub访问令牌失败,响应中未包含令牌。"); - } - - var accessToken = accessTokenElement.GetString(); - - httpClient.DefaultRequestHeaders.Authorization = - new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); - - var userResponse = await httpClient.GetAsync(githubUserApiUrl); - if (!userResponse.IsSuccessStatusCode) - { - var errorContent = await userResponse.Content.ReadAsStringAsync(); - Console.WriteLine($"获取GitHub用户信息失败: {userResponse.StatusCode}, {errorContent}"); - return Error($"获取GitHub用户信息失败: {errorContent}", (int)userResponse.StatusCode); - } - - var userContent = await userResponse.Content.ReadAsStringAsync(); - var userJson = System.Text.Json.JsonDocument.Parse(userContent); - - string? githubUserId = null; - string? email = null; - string? name = null; - string? loginName = null; - - if (userJson.RootElement.TryGetProperty("id", out var idElement)) - { - githubUserId = idElement.GetInt64().ToString(); - } - - if (userJson.RootElement.TryGetProperty("email", out var emailElement)) - { - email = emailElement.GetString(); - } - - if (userJson.RootElement.TryGetProperty("name", out var nameElement)) - { - name = nameElement.GetString(); - } - - if (userJson.RootElement.TryGetProperty("login", out var loginElement)) - { - loginName = loginElement.GetString(); - } - - if (string.IsNullOrEmpty(githubUserId)) - { - return Error("无法从GitHub获取用户ID"); - } - - - var (isSuccess, message, user) = - await userService.FindOrCreateGitHubUserAsync(githubUserId, name ?? loginName, email); - - if (!isSuccess || user == null) - { - Console.WriteLine($"创建或查找GitHub用户失败: {message}"); - return Redirect( - $"/login?error=github_user_creation_failed&message={Uri.EscapeDataString(message)}"); - } - - var token = await userService.GenerateJwtTokenAsync(user); + return Redirect($"/login?token={Uri.EscapeDataString(token)}"); } + + [HttpPut("update")] + [Authorize] + public async Task>> UpdateUserInfo([FromBody] UpdateUserRequest request) + { + if (!ModelState.IsValid) + { + return Error("请求数据无效"); + } + + var userId = GetCurrentUserId(); + if (userId == null) + { + return Error("用户ID未找到"); + } + + var (success, message, user) = await authService.UpdateUserInfoAsync(userId.Value, request); + if (!success || user == null) + { + return Error(message); + } + + var profile = new UserProfile + { + Id = user.Id, + Email = user.Email, + UserName = user.UserName, + RoleName = user.Role?.Name + }; + + return Success(profile, "用户信息更新成功"); + } } \ No newline at end of file diff --git a/Extensions/ServiceCollectionExtensions.cs b/Extensions/ServiceCollectionExtensions.cs index 417eb58..8e34997 100644 --- a/Extensions/ServiceCollectionExtensions.cs +++ b/Extensions/ServiceCollectionExtensions.cs @@ -16,7 +16,7 @@ public static class ServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/Services/AuthService.cs b/Services/AuthService.cs new file mode 100644 index 0000000..8803cd3 --- /dev/null +++ b/Services/AuthService.cs @@ -0,0 +1,290 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Foxel.Models.DataBase; +using Foxel.Services.Interface; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Foxel.Models.Request.Auth; +using static Foxel.Utils.AuthHelper; + +namespace Foxel.Services; + +public class AuthService(IDbContextFactory dbContextFactory, IConfigService configuration) + : IAuthService +{ + public async Task<(bool success, string message, User? user)> RegisterUserAsync(RegisterRequest request) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var existingUser = await context.Users.FirstOrDefaultAsync(u => u.Email == request.Email); + if (existingUser != null) + { + return (false, "该邮箱已被注册", null); + } + + existingUser = await context.Users.FirstOrDefaultAsync(u => u.UserName == request.UserName); + if (existingUser != null) + { + return (false, "该用户名已被使用", null); + } + + var user = new User + { + UserName = request.UserName, + Email = request.Email, + PasswordHash = HashPassword(request.Password), + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + context.Users.Add(user); + await context.SaveChangesAsync(); + return (true, "用户注册成功", user); + } + + public async Task<(bool success, string message, User? user)> AuthenticateUserAsync(LoginRequest request) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var user = await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Email == request.Email); + + if (user == null) + { + return (false, "用户不存在", null); + } + + if (!VerifyPassword(request.Password, user.PasswordHash)) + { + return (false, "密码错误", null); + } + + return (true, "登录成功", user); + } + + public Task GenerateJwtTokenAsync(User user) + { + var claims = new List + { + new(ClaimTypes.NameIdentifier, user.Id.ToString()), + new(ClaimTypes.Email, user.Email), + new(ClaimTypes.Name, user.UserName) + }; + if (user.Role != null) + { + claims.Add(new Claim(ClaimTypes.Role, user.Role.Name)); + } + + var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"] ?? + throw new InvalidOperationException( + "JWT Secret key not found"))); + var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); + var expires = DateTime.UtcNow.AddYears(1); + var token = new JwtSecurityToken( + issuer: configuration["Jwt:Issuer"], + audience: configuration["Jwt:Audience"], + claims: claims, + expires: expires, + signingCredentials: creds + ); + + var tokenString = new JwtSecurityTokenHandler().WriteToken(token); + return Task.FromResult(tokenString); + } + + public async Task GetUserByIdAsync(int userId) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + return await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Id == userId); + } + + public async Task<(bool success, string message, User? user)> FindOrCreateGitHubUserAsync( + string githubId, string? githubName, string? email) + { + if (string.IsNullOrEmpty(email)) + { + return (false, "GitHub账号未提供邮箱地址", null); + } + + await using var context = await dbContextFactory.CreateDbContextAsync(); + + var user = await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Email == email); + + if (user == null) + { + user = new User + { + UserName = $"{githubName}", + Email = email, + PasswordHash = HashPassword(Guid.NewGuid().ToString()), + GithubId = githubId, + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + context.Users.Add(user); + await context.SaveChangesAsync(); + return (true, "GitHub用户注册成功", user); + } + + if (string.IsNullOrEmpty(user.GithubId)) + { + user.GithubId = githubId; + user.UpdatedAt = DateTime.UtcNow; + await context.SaveChangesAsync(); + } + + return (true, "GitHub用户登录成功", user); + } + + public async Task<(bool success, string message, User? user)> UpdateUserInfoAsync(int userId, UpdateUserRequest request) + { + await using var context = await dbContextFactory.CreateDbContextAsync(); + var user = await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Id == userId); + + if (user == null) + { + return (false, "用户不存在", null); + } + + // 检查用户名是否已存在 + if (!string.IsNullOrEmpty(request.UserName) && request.UserName != user.UserName) + { + var existingUserName = await context.Users.AnyAsync(u => u.UserName == request.UserName); + if (existingUserName) + { + return (false, "该用户名已被使用", null); + } + user.UserName = request.UserName; + } + + // 检查邮箱是否已存在 + if (!string.IsNullOrEmpty(request.Email) && request.Email != user.Email) + { + var existingEmail = await context.Users.AnyAsync(u => u.Email == request.Email); + if (existingEmail) + { + return (false, "该邮箱已被注册", null); + } + user.Email = request.Email; + } + + // 如果要修改密码,验证当前密码 + if (!string.IsNullOrEmpty(request.NewPassword)) + { + if (string.IsNullOrEmpty(request.CurrentPassword)) + { + return (false, "需要提供当前密码", null); + } + + if (!VerifyPassword(request.CurrentPassword, user.PasswordHash)) + { + return (false, "当前密码不正确", null); + } + + user.PasswordHash = HashPassword(request.NewPassword); + } + + user.UpdatedAt = DateTime.UtcNow; + await context.SaveChangesAsync(); + + return (true, "用户信息更新成功", user); + } + + public string GetGitHubLoginUrl() + { + string githubClientId = configuration["Authentication:GitHubClientId"]; + string githubCallback = configuration["Authentication:GitHubCallbackUrl"]; + return $"https://github.com/login/oauth/authorize?client_id={Uri.EscapeDataString(githubClientId)}&redirect_uri={Uri.EscapeDataString(githubCallback)}"; + } + + public async Task<(bool success, string message, string? token)> ProcessGitHubCallbackAsync(string code) + { + if (string.IsNullOrEmpty(code)) + { + return (false, "GitHub授权码无效", null); + } + + string githubClientId = configuration["Authentication:GitHubClientId"]; + string githubClientSecret = configuration["Authentication:GitHubClientSecret"]; + string githubTokenUrl = "https://github.com/login/oauth/access_token"; + string githubUserApiUrl = "https://api.github.com/user"; + + using var httpClient = new HttpClient(); + httpClient.DefaultRequestHeaders.Add("User-Agent", "Foxel"); + httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); + var tokenRequestUrl = + $"{githubTokenUrl}?client_id={Uri.EscapeDataString(githubClientId)}&client_secret={Uri.EscapeDataString(githubClientSecret)}&code={Uri.EscapeDataString(code)}"; + var tokenResponse = await httpClient.PostAsync(tokenRequestUrl, null); + + if (!tokenResponse.IsSuccessStatusCode) + { + var errorContent = await tokenResponse.Content.ReadAsStringAsync(); + Console.WriteLine($"获取GitHub访问令牌失败: {tokenResponse.StatusCode}, {errorContent}"); + return (false, $"获取GitHub访问令牌失败: {errorContent}", null); + } + + var tokenResponseContent = await tokenResponse.Content.ReadAsStringAsync(); + var tokenJson = System.Text.Json.JsonDocument.Parse(tokenResponseContent); + + if (!tokenJson.RootElement.TryGetProperty("access_token", out var accessTokenElement) || + accessTokenElement.GetString() == null) + { + Console.WriteLine($"GitHub响应中未找到access_token: {tokenResponseContent}"); + return (false, "获取GitHub访问令牌失败,响应中未包含令牌。", null); + } + + var accessToken = accessTokenElement.GetString(); + + httpClient.DefaultRequestHeaders.Authorization = + new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); + + var userResponse = await httpClient.GetAsync(githubUserApiUrl); + if (!userResponse.IsSuccessStatusCode) + { + var errorContent = await userResponse.Content.ReadAsStringAsync(); + Console.WriteLine($"获取GitHub用户信息失败: {userResponse.StatusCode}, {errorContent}"); + return (false, $"获取GitHub用户信息失败: {errorContent}", null); + } + + var userContent = await userResponse.Content.ReadAsStringAsync(); + var userJson = System.Text.Json.JsonDocument.Parse(userContent); + + string? githubUserId = null; + string? email = null; + string? name = null; + string? loginName = null; + + if (userJson.RootElement.TryGetProperty("id", out var idElement)) + { + githubUserId = idElement.GetInt64().ToString(); + } + + if (userJson.RootElement.TryGetProperty("email", out var emailElement)) + { + email = emailElement.GetString(); + } + + if (userJson.RootElement.TryGetProperty("name", out var nameElement)) + { + name = nameElement.GetString(); + } + + if (userJson.RootElement.TryGetProperty("login", out var loginElement)) + { + loginName = loginElement.GetString(); + } + + if (string.IsNullOrEmpty(githubUserId)) + { + return (false, "无法从GitHub获取用户ID", null); + } + + var (isSuccess, message, user) = await FindOrCreateGitHubUserAsync(githubUserId, name ?? loginName, email); + + if (!isSuccess || user == null) + { + Console.WriteLine($"创建或查找GitHub用户失败: {message}"); + return (false, message, null); + } + + var jwtToken = await GenerateJwtTokenAsync(user); + return (true, "GitHub授权成功", jwtToken); + } +} \ No newline at end of file diff --git a/Services/Interface/IUserService.cs b/Services/Interface/IAuthService.cs similarity index 67% rename from Services/Interface/IUserService.cs rename to Services/Interface/IAuthService.cs index 07483cf..e30b5e4 100644 --- a/Services/Interface/IUserService.cs +++ b/Services/Interface/IAuthService.cs @@ -4,7 +4,7 @@ using Foxel.Models.Request.Auth; namespace Foxel.Services.Interface; -public interface IUserService +public interface IAuthService { Task<(bool success, string message, User? user)> RegisterUserAsync(RegisterRequest request); Task<(bool success, string message, User? user)> AuthenticateUserAsync(LoginRequest request); @@ -12,4 +12,7 @@ public interface IUserService Task GetUserByIdAsync(int userId); Task<(bool success, string message, User? user)> FindOrCreateGitHubUserAsync( string githubId, string? githubName, string? email); + Task<(bool success, string message, User? user)> UpdateUserInfoAsync(int userId, UpdateUserRequest request); + string GetGitHubLoginUrl(); + Task<(bool success, string message, string? token)> ProcessGitHubCallbackAsync(string code); } diff --git a/Services/UserService.cs b/Services/UserService.cs deleted file mode 100644 index f3102ad..0000000 --- a/Services/UserService.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Text; -using Foxel.Models.DataBase; -using Foxel.Services.Interface; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Foxel.Models.Request; -using Foxel.Models.Request.Auth; -using static Foxel.Utils.AuthHelper; - -namespace Foxel.Services; - -public class UserService(IDbContextFactory dbContextFactory, IConfigService configuration) - : IUserService -{ - public async Task<(bool success, string message, User? user)> RegisterUserAsync(RegisterRequest request) - { - await using var context = await dbContextFactory.CreateDbContextAsync(); - var existingUser = await context.Users.FirstOrDefaultAsync(u => u.Email == request.Email); - if (existingUser != null) - { - return (false, "该邮箱已被注册", null); - } - - existingUser = await context.Users.FirstOrDefaultAsync(u => u.UserName == request.UserName); - if (existingUser != null) - { - return (false, "该用户名已被使用", null); - } - - var user = new User - { - UserName = request.UserName, - Email = request.Email, - PasswordHash = HashPassword(request.Password), - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - context.Users.Add(user); - await context.SaveChangesAsync(); - return (true, "用户注册成功", user); - } - - public async Task<(bool success, string message, User? user)> AuthenticateUserAsync(LoginRequest request) - { - await using var context = await dbContextFactory.CreateDbContextAsync(); - var user = await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Email == request.Email); - - if (user == null) - { - return (false, "用户不存在", null); - } - - if (!VerifyPassword(request.Password, user.PasswordHash)) - { - return (false, "密码错误", null); - } - - return (true, "登录成功", user); - } - - public Task GenerateJwtTokenAsync(User user) - { - var claims = new List - { - new(ClaimTypes.NameIdentifier, user.Id.ToString()), - new(ClaimTypes.Email, user.Email), - new(ClaimTypes.Name, user.UserName) - }; - if (user.Role != null) - { - claims.Add(new Claim(ClaimTypes.Role, user.Role.Name)); - } - - var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:SecretKey"] ?? - throw new InvalidOperationException( - "JWT Secret key not found"))); - var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); - var expires = DateTime.UtcNow.AddYears(1); - var token = new JwtSecurityToken( - issuer: configuration["Jwt:Issuer"], - audience: configuration["Jwt:Audience"], - claims: claims, - expires: expires, - signingCredentials: creds - ); - - var tokenString = new JwtSecurityTokenHandler().WriteToken(token); - return Task.FromResult(tokenString); - } - - public async Task GetUserByIdAsync(int userId) - { - await using var context = await dbContextFactory.CreateDbContextAsync(); - return await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Id == userId); - } - - public async Task<(bool success, string message, User? user)> FindOrCreateGitHubUserAsync( - string githubId, string? githubName, string? email) - { - if (string.IsNullOrEmpty(email)) - { - return (false, "GitHub账号未提供邮箱地址", null); - } - - await using var context = await dbContextFactory.CreateDbContextAsync(); - - var user = await context.Users.Include(x => x.Role).FirstOrDefaultAsync(u => u.Email == email); - - if (user == null) - { - user = new User - { - UserName = $"{githubName}", - Email = email, - PasswordHash = HashPassword(Guid.NewGuid().ToString()), - GithubId = githubId, - CreatedAt = DateTime.UtcNow, - UpdatedAt = DateTime.UtcNow - }; - context.Users.Add(user); - await context.SaveChangesAsync(); - return (true, "GitHub用户注册成功", user); - } - - if (string.IsNullOrEmpty(user.GithubId)) - { - user.GithubId = githubId; - user.UpdatedAt = DateTime.UtcNow; - await context.SaveChangesAsync(); - } - - return (true, "GitHub用户登录成功", user); - } -} \ No newline at end of file diff --git a/View/src/api/authApi.ts b/View/src/api/authApi.ts index 0f45ddd..727aa44 100644 --- a/View/src/api/authApi.ts +++ b/View/src/api/authApi.ts @@ -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> { } } +// 更新用户信息 +export async function updateUserInfo(data: UpdateUserRequest): Promise> { + try { + const response = await fetchApi('/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); diff --git a/View/src/api/index.ts b/View/src/api/index.ts index c5ac312..73ed660 100644 --- a/View/src/api/index.ts +++ b/View/src/api/index.ts @@ -10,6 +10,7 @@ export { register, login, getCurrentUser, + updateUserInfo, // 添加导出更新用户信息函数 saveAuthData, clearAuthData, isAuthenticated, diff --git a/View/src/api/types.ts b/View/src/api/types.ts index b5ab430..e602ded 100644 --- a/View/src/api/types.ts +++ b/View/src/api/types.ts @@ -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; +} diff --git a/View/src/pages/settings/UserProfile.tsx b/View/src/pages/settings/UserProfile.tsx index 5eff076..5f4661a 100644 --- a/View/src/pages/settings/UserProfile.tsx +++ b/View/src/pages/settings/UserProfile.tsx @@ -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 ( {
- + @@ -48,19 +115,57 @@ const UserProfile: React.FC = () => { - - + + - + + + + + ({ + validator(_, value) { + if (!value || getFieldValue('newPassword') === value) { + return Promise.resolve(); + } + return Promise.reject(new Error('两次输入的密码不一致')); + }, + }), + ]} + >