diff --git a/backend/BackOffice/BackOffice.Api/BackOffice.Web.csproj b/backend/BackOffice/BackOffice.Api/BackOffice.Web.csproj index 06bc7aac23ccee7ac107c763041280c4fd6d944e..f5c472bf4091b42856ebf84ceebea48100bd5885 100644 --- a/backend/BackOffice/BackOffice.Api/BackOffice.Web.csproj +++ b/backend/BackOffice/BackOffice.Api/BackOffice.Web.csproj @@ -7,6 +7,7 @@ + diff --git a/backend/BackOffice/BackOffice.Application/BackOffice.Application.csproj b/backend/BackOffice/BackOffice.Application/BackOffice.Application.csproj index b932aafdc85d8d152f10cf0863c0e3f3d6a55c67..e1d31a28b1cd824462dc4e00b7825d3245ceb371 100644 --- a/backend/BackOffice/BackOffice.Application/BackOffice.Application.csproj +++ b/backend/BackOffice/BackOffice.Application/BackOffice.Application.csproj @@ -4,6 +4,11 @@ + + + + + net8.0 enable diff --git a/backend/BackOffice/BackOffice.Application/Handlers/RegisterUserCommandHandler.cs b/backend/BackOffice/BackOffice.Application/Handlers/RegisterUserCommandHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..6534b74fb06e854a3566eee746d6337c0c8ad2d3 --- /dev/null +++ b/backend/BackOffice/BackOffice.Application/Handlers/RegisterUserCommandHandler.cs @@ -0,0 +1,98 @@ +//用户注册命令处理器 + +using System; +using System.Threading; +using System.Threading.Tasks; +using BackOffice.Application.Commands.Users; +using MediatR; + +namespace BackOffice.Application.Handlers.Users +{ + /// + /// 用户注册命令处理器 + /// + public class RegisterUserCommandHandler : IRequestHandler + { + // 模拟用户存储(可以替换为数据库上下文或其他存储机制) + private readonly IUserRepository _userRepository; + + /// + /// 构造函数 + /// + /// 用户存储仓库 + public RegisterUserCommandHandler(IUserRepository userRepository) + { + _userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository)); + } + + /// + /// 处理用户注册命令 + /// + /// 用户注册命令 + /// 取消令牌 + /// 用户注册结果 + public async Task Handle(RegisterUserCommand request, CancellationToken cancellationToken) + { + // 检查用户名或邮箱是否已存在 + if (await _userRepository.ExistsByUsernameOrEmailAsync(request.Username, request.Email)) + { + throw new InvalidOperationException("用户名或电子邮箱已被占用"); + } + + // 创建新用户 + var user = new User + { + Username = request.Username, + Email = request.Email, + PasswordHash = HashPassword(request.Password), // 假设有一个密码哈希方法 + Phone = request.Phone, + CreatedAt = DateTime.UtcNow + }; + + // 保存用户到存储 + await _userRepository.AddAsync(user); + + // 返回注册结果 + return new RegisterUserResult + { + Id = user.Id, + Username = user.Username, + Email = user.Email, + CreatedAt = user.CreatedAt + }; + } + + /// + /// 哈希密码(示例方法) + /// + /// 明文密码 + /// 哈希后的密码 + private string HashPassword(string password) + { + // 使用实际的密码哈希算法(如 BCrypt 或 PBKDF2) + return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(password)); + } + } + + /// + /// 用户存储仓库接口 + /// + public interface IUserRepository + { + Task ExistsByUsernameOrEmailAsync(string username, string email); + Task AddAsync(User user); + } + + /// + /// 用户实体 + /// + public class User + { + public int Id { get; set; } + public required string Username { get; set; } + public required string Email { get; set; } + public string PasswordHash { get; set; } + public string Phone { get; set; } + public DateTime CreatedAt { get; set; } + } +} \ No newline at end of file diff --git a/backend/BackOffice/BackOffice.Application/Services/RegisterUserCommand.cs b/backend/BackOffice/BackOffice.Application/Services/RegisterUserCommand.cs new file mode 100644 index 0000000000000000000000000000000000000000..46a9943bd5454c997c4b477399fa4c8e784ddbac --- /dev/null +++ b/backend/BackOffice/BackOffice.Application/Services/RegisterUserCommand.cs @@ -0,0 +1,68 @@ +// 用户注册命令 + +namespace BackOffice.Application.Commands.Users +{ + using MediatR; + using System; + using System.ComponentModel.DataAnnotations; + + /// + /// 用户注册命令 + /// + public class RegisterUserCommand : IRequest + { + /// + /// 用户名 + /// + [Required(ErrorMessage = "用户名是必填项")] + [StringLength(50, ErrorMessage = "用户名长度不能超过50个字符")] + public required string Username { get; set; } + + /// + /// 电子邮箱 + /// + [Required(ErrorMessage = "电子邮箱是必填项")] + [EmailAddress(ErrorMessage = "电子邮箱格式不正确")] + public required string Email { get; set; } + + /// + /// 密码 + /// + [Required(ErrorMessage = "密码是必填项")] + [StringLength(100, MinimumLength = 6, ErrorMessage = "密码长度必须在6到100个字符之间")] + public required string Password { get; set; } + + /// + /// 手机号码 + /// + [Required(ErrorMessage = "手机号码是必填项")] + [Phone(ErrorMessage = "手机号码格式不正确")] + public required string Phone { get; set; } + } + + /// + /// 用户注册结果 + /// + public class RegisterUserResult + { + /// + /// 用户ID + /// + public int Id { get; set; } + + /// + /// 用户名 + /// + public required string Username { get; set; } + + /// + /// 电子邮箱 + /// + public required string Email { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreatedAt { get; set; } + } +} \ No newline at end of file diff --git a/backend/BackOffice/BackOffice.Infrastructure/Repositories/UserRepository.cs b/backend/BackOffice/BackOffice.Infrastructure/Repositories/UserRepository.cs new file mode 100644 index 0000000000000000000000000000000000000000..aa667063152d9031ea0c4819e2d533ef92441d51 --- /dev/null +++ b/backend/BackOffice/BackOffice.Infrastructure/Repositories/UserRepository.cs @@ -0,0 +1,64 @@ +//用户存储仓库的实现类 + +using System.Linq; +using System.Threading.Tasks; +using BackOffice.Application.Handlers.Users; +using Microsoft.EntityFrameworkCore; + +namespace BackOffice.Infrastructure.Repositories +{ + /// + /// 用户存储仓库实现 + /// + public class UserRepository : IUserRepository + { + private readonly BackOfficeDbContext _dbContext; + + /// + /// 构造函数 + /// + /// 数据库上下文 + public UserRepository(BackOfficeDbContext dbContext) + { + _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); + } + + /// + /// 检查用户名或电子邮箱是否已存在 + /// + /// 用户名 + /// 电子邮箱 + /// 是否存在 + public async Task ExistsByUsernameOrEmailAsync(string username, string email) + { + return await _dbContext.Users + .AnyAsync(u => u.Username == username || u.Email == email); + } + + /// + /// 添加新用户 + /// + /// 用户实体 + /// 任务 + public async Task AddAsync(User user) + { + await _dbContext.Users.AddAsync(user); + await _dbContext.SaveChangesAsync(); + } + } + + /// + /// 数据库上下文 + /// + public class BackOfficeDbContext : DbContext + { + public BackOfficeDbContext(DbContextOptions options) : base(options) + { + } + + /// + /// 用户表 + /// + public DbSet Users { get; set; } + } +} \ No newline at end of file diff --git a/frontend/BackOffice/mini-flow/src/main.js b/frontend/BackOffice/mini-flow/src/main.js index 8bb678b10bc784d0f83843663cf8694cd173925c..6ec5e448d74d02634b4be4deed71bfecc357b581 100644 --- a/frontend/BackOffice/mini-flow/src/main.js +++ b/frontend/BackOffice/mini-flow/src/main.js @@ -1,4 +1,4 @@ -import './assets/main.css' +// import './assets/main.css' import { createApp } from 'vue' import { createPinia } from 'pinia' diff --git a/frontend/BackOffice/mini-flow/src/router/index.js b/frontend/BackOffice/mini-flow/src/router/index.js index de261775a780bc5210e265b1da2ab2b22fbb8467..0ca5f28c007b559009715401fe895a7e0239a380 100644 --- a/frontend/BackOffice/mini-flow/src/router/index.js +++ b/frontend/BackOffice/mini-flow/src/router/index.js @@ -2,6 +2,8 @@ import { createRouter, createWebHistory } from 'vue-router' import LoginView from '../views/LoginView.vue' import Gotopassword from '../views/Gotopassword.vue' import Gotouser from '../views/Gotouser.vue' +import UserList from '../views/user/UserList.vue' +import UserDialog from '../views/user/UserDialog.vue' const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -21,6 +23,16 @@ const router = createRouter({ name: 'Gotouser', component: Gotouser, }, + { + path: '/UserList', + name: 'UserList', + component: UserList, + }, + { + path: '/UserDialog', + name: 'UserDialog', + component: UserDialog, + }, ], }) diff --git a/frontend/BackOffice/mini-flow/src/views/Gotopassword.vue b/frontend/BackOffice/mini-flow/src/views/Gotopassword.vue index fa399badc5a03be688be1443aad5a323de481128..a61dfada1211cdde0f832154a22762019ada9395 100644 --- a/frontend/BackOffice/mini-flow/src/views/Gotopassword.vue +++ b/frontend/BackOffice/mini-flow/src/views/Gotopassword.vue @@ -215,7 +215,7 @@ } .forgot-box { - width: 1200px; + width: 500px; padding: 350px; border-radius: 12px; } diff --git a/frontend/BackOffice/mini-flow/src/views/Gotouser.vue b/frontend/BackOffice/mini-flow/src/views/Gotouser.vue index d6ad491dcac12db04e5dfb22d81f057b4576c97e..3317253caf8a2d6685933ddb2f6820c2b305d0ec 100644 --- a/frontend/BackOffice/mini-flow/src/views/Gotouser.vue +++ b/frontend/BackOffice/mini-flow/src/views/Gotouser.vue @@ -193,7 +193,7 @@ } .register-box { - width: 1200px; + width: 500px; padding: 350px; border-radius: 12px; } diff --git a/frontend/BackOffice/mini-flow/src/views/LoginView.vue b/frontend/BackOffice/mini-flow/src/views/LoginView.vue index de103bd769024c01a027857925be2ed14c6ce1bb..4caeea877176609a4c91d7305554e7a9d0b7284a 100644 --- a/frontend/BackOffice/mini-flow/src/views/LoginView.vue +++ b/frontend/BackOffice/mini-flow/src/views/LoginView.vue @@ -251,7 +251,7 @@ const handleLogin = () => { setTimeout(() => { loading.value = false ElMessage.success('登录成功') - router.push('/') + router.push('/UserList') }, 1500) } diff --git a/frontend/BackOffice/mini-flow/src/views/user/UserDialog.vue b/frontend/BackOffice/mini-flow/src/views/user/UserDialog.vue new file mode 100644 index 0000000000000000000000000000000000000000..9aa26070b900c95c7a736f1e57f98ff6d98b7767 --- /dev/null +++ b/frontend/BackOffice/mini-flow/src/views/user/UserDialog.vue @@ -0,0 +1,30 @@ + + \ No newline at end of file diff --git a/frontend/BackOffice/mini-flow/src/views/user/UserList.vue b/frontend/BackOffice/mini-flow/src/views/user/UserList.vue new file mode 100644 index 0000000000000000000000000000000000000000..edb0fe81555c027c6f60f66895488f14e5e2b365 --- /dev/null +++ b/frontend/BackOffice/mini-flow/src/views/user/UserList.vue @@ -0,0 +1,337 @@ + + + + + \ No newline at end of file