29 changed files with 1836 additions and 4 deletions
@ -0,0 +1,15 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore.DataSeeder |
|||
{ |
|||
public interface IProjectNameDataSeeder |
|||
{ |
|||
/// <summary>
|
|||
/// 初始化数据
|
|||
/// </summary>
|
|||
/// <param name="context">数据种子上下文</param>
|
|||
/// <returns>任务</returns>
|
|||
Task SeedAsync(DataSeedContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,503 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.Guids; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Uow; |
|||
using IdentityRole = Volo.Abp.Identity.IdentityRole; |
|||
using IdentityUser = Volo.Abp.Identity.IdentityUser; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore.DataSeeder |
|||
{ |
|||
public class ProjectNameDataSeederDataSeeder : IProjectNameDataSeeder, ITransientDependency |
|||
{ |
|||
private readonly ICurrentTenant _currentTenant; |
|||
private readonly IGuidGenerator _guidGenerator; |
|||
private readonly ILogger<ProjectNameDataSeeder> _logger; |
|||
private readonly IRepository<Org, Guid> _orgRepository; |
|||
private readonly IRepository<WorkUnit, Guid> _workUnitRepository; |
|||
private readonly IRepository<User, Guid> _userRepository; |
|||
private readonly IdentityUserManager _identityUserManager; |
|||
private readonly IdentityRoleManager _identityRoleManager; |
|||
private readonly IUnitOfWorkManager _unitOfWorkManager; |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
public ProjectNameDataSeeder( |
|||
ICurrentTenant currentTenant, |
|||
IGuidGenerator guidGenerator, |
|||
ILogger<ProjectNameDataSeeder> logger, |
|||
IRepository<Org, Guid> orgRepository, |
|||
IRepository<WorkUnit, Guid> workUnitRepository, |
|||
IRepository<User, Guid> userRepository, |
|||
IdentityUserManager identityUserManager, |
|||
IdentityRoleManager identityRoleManager, |
|||
IUnitOfWorkManager unitOfWorkManager) |
|||
{ |
|||
_currentTenant = currentTenant; |
|||
_guidGenerator = guidGenerator; |
|||
_logger = logger; |
|||
_orgRepository = orgRepository; |
|||
_workUnitRepository = workUnitRepository; |
|||
_userRepository = userRepository; |
|||
_identityUserManager = identityUserManager; |
|||
_identityRoleManager = identityRoleManager; |
|||
_unitOfWorkManager = unitOfWorkManager; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化数据
|
|||
/// </summary>
|
|||
/// <param name="context">数据种子上下文</param>
|
|||
/// <returns>任务</returns>
|
|||
public async Task SeedAsync(DataSeedContext context) |
|||
{ |
|||
using (_currentTenant.Change(context.TenantId)) |
|||
{ |
|||
_logger.LogInformation("开始初始化巡检数据..."); |
|||
|
|||
// 初始化角色
|
|||
using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) |
|||
{ |
|||
await SeedRolesAsync(); |
|||
await uow.CompleteAsync(); |
|||
} |
|||
|
|||
// 初始化单位数据
|
|||
using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) |
|||
{ |
|||
await SeedWorkUnitsAsync(); |
|||
await uow.CompleteAsync(); |
|||
} |
|||
|
|||
// 初始化组织数据
|
|||
using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) |
|||
{ |
|||
await SeedOrgsAsync(); |
|||
await uow.CompleteAsync(); |
|||
} |
|||
|
|||
// 初始化用户数据
|
|||
using (var uow = _unitOfWorkManager.Begin(requiresNew: true)) |
|||
{ |
|||
await SeedUsersAsync(); |
|||
await uow.CompleteAsync(); |
|||
} |
|||
|
|||
_logger.LogInformation("巡检数据初始化完成"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化角色数据
|
|||
/// </summary>
|
|||
private async Task SeedRolesAsync() |
|||
{ |
|||
// 超级管理员
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"超级管理员", |
|||
"系统超级管理员,拥有所有权限"); |
|||
|
|||
// 区委办公室-督查室管理员
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"区委办公室-督查室管理员", |
|||
"区委办公室督查室管理员"); |
|||
|
|||
// 责任领导秘书
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"责任领导秘书", |
|||
"负责协助责任领导进行工作"); |
|||
|
|||
// 责任单位管理员
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"责任单位管理员", |
|||
"负责管理责任单位的信息"); |
|||
|
|||
// 责任单位落实人员
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"责任单位落实人员", |
|||
"负责执行责任单位的任务"); |
|||
|
|||
// 责任单位分管领导
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"责任单位分管领导", |
|||
"负责管理责任单位的部分工作"); |
|||
|
|||
// 责任单位党组书记
|
|||
await CreateRoleIfNotExistsAsync( |
|||
"责任单位党组书记", |
|||
"负责责任单位的党组工作"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建角色(如果不存在)
|
|||
/// </summary>
|
|||
private async Task CreateRoleIfNotExistsAsync(string roleName, string description) |
|||
{ |
|||
if (await _identityRoleManager.FindByNameAsync(roleName) == null) |
|||
{ |
|||
var role = new IdentityRole( |
|||
_guidGenerator.Create(), |
|||
roleName, |
|||
_currentTenant.Id) |
|||
{ |
|||
IsStatic = true, |
|||
IsPublic = true |
|||
}; |
|||
|
|||
await _identityRoleManager.CreateAsync(role); |
|||
|
|||
_logger.LogInformation($"创建角色:{roleName}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化单位数据
|
|||
/// </summary>
|
|||
private async Task SeedWorkUnitsAsync() |
|||
{ |
|||
// 创建永川区
|
|||
var yongchuanDistrict = await CreateWorkUnitIfNotExistsAsync( |
|||
"永川区", |
|||
"001", |
|||
"001", |
|||
"永川区"); |
|||
|
|||
// 创建区政府
|
|||
var districtGovernment = await CreateWorkUnitIfNotExistsAsync( |
|||
"区政府", |
|||
"002", |
|||
"001.002", |
|||
"永川区政府", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区委办公室
|
|||
var districtCommitteeOffice = await CreateWorkUnitIfNotExistsAsync( |
|||
"区委办公室", |
|||
"003", |
|||
"001.003", |
|||
"永川区委办公室", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建督查室
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"督查室", |
|||
"004", |
|||
"001.003.004", |
|||
"区委办公室督查室", |
|||
districtCommitteeOffice.Id); |
|||
|
|||
// 创建区委扫黑办
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区委扫黑办", |
|||
"005", |
|||
"001.005", |
|||
"永川区委扫黑办", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区体育局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区体育局", |
|||
"006", |
|||
"001.006", |
|||
"永川区体育局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区统计局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区统计局", |
|||
"007", |
|||
"001.007", |
|||
"永川区统计局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区信访办
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区信访办", |
|||
"008", |
|||
"001.008", |
|||
"永川区信访办", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区医保局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区医保局", |
|||
"009", |
|||
"001.009", |
|||
"永川区医保局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区大数据发展局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区大数据发展局", |
|||
"010", |
|||
"001.010", |
|||
"永川区大数据发展局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区机关事务局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区机关事务局", |
|||
"011", |
|||
"001.011", |
|||
"永川区机关事务局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区广播电视局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区广播电视局", |
|||
"012", |
|||
"001.012", |
|||
"永川区广播电视局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建区中新项目管理局
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"区中新项目管理局", |
|||
"013", |
|||
"001.013", |
|||
"永川区中新项目管理局", |
|||
yongchuanDistrict.Id); |
|||
|
|||
// 创建镇街
|
|||
await CreateWorkUnitIfNotExistsAsync( |
|||
"镇街", |
|||
"014", |
|||
"001.014", |
|||
"永川区镇街", |
|||
yongchuanDistrict.Id); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建单位(如果不存在)
|
|||
/// </summary>
|
|||
private async Task<WorkUnit> CreateWorkUnitIfNotExistsAsync( |
|||
string name, |
|||
string code, |
|||
string treeCode, |
|||
string description, |
|||
Guid? parentId = null) |
|||
{ |
|||
var workUnit = await _workUnitRepository.FindAsync(w => w.Name == name); |
|||
|
|||
if (workUnit == null) |
|||
{ |
|||
workUnit = new WorkUnit( |
|||
_guidGenerator.Create(), |
|||
code, |
|||
treeCode, |
|||
name, |
|||
description) |
|||
{ |
|||
ParentId = parentId |
|||
}; |
|||
|
|||
await _workUnitRepository.InsertAsync(workUnit); |
|||
|
|||
_logger.LogInformation($"创建单位:{name}"); |
|||
} |
|||
|
|||
return workUnit; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化组织数据
|
|||
/// </summary>
|
|||
private async Task SeedOrgsAsync() |
|||
{ |
|||
// 创建区委办公室-督查室
|
|||
var supervisionOffice = await CreateOrgIfNotExistsAsync( |
|||
"区委办公室-督查室", |
|||
"001", |
|||
"001", |
|||
"区委办公室督查室"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建组织(如果不存在)
|
|||
/// </summary>
|
|||
private async Task<Org> CreateOrgIfNotExistsAsync( |
|||
string name, |
|||
string code, |
|||
string treeCode, |
|||
string description, |
|||
Guid? parentId = null) |
|||
{ |
|||
var org = await _orgRepository.FindAsync(o => o.Name == name); |
|||
|
|||
if (org == null) |
|||
{ |
|||
org = new Org( |
|||
_guidGenerator.Create(), |
|||
code, |
|||
treeCode, |
|||
name, |
|||
description) |
|||
{ |
|||
ParentId = parentId |
|||
}; |
|||
|
|||
await _orgRepository.InsertAsync(org); |
|||
|
|||
_logger.LogInformation($"创建组织:{name}"); |
|||
} |
|||
|
|||
return org; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 初始化用户数据
|
|||
/// </summary>
|
|||
private async Task SeedUsersAsync() |
|||
{ |
|||
// 获取所需单位
|
|||
var supervisionOffice = await _workUnitRepository.FindAsync(w => w.Name == "督查室"); |
|||
if (supervisionOffice == null) |
|||
{ |
|||
_logger.LogError("未找到督查室单位,无法创建用户"); |
|||
return; |
|||
} |
|||
|
|||
// 获取所需组织
|
|||
var supervisionOrg = await _orgRepository.FindAsync(o => o.Name == "区委办公室-督查室"); |
|||
if (supervisionOrg == null) |
|||
{ |
|||
_logger.LogError("未找到区委办公室-督查室组织,无法创建用户"); |
|||
return; |
|||
} |
|||
|
|||
// 查找超级管理员角色
|
|||
var superAdminRole = await _identityRoleManager.FindByNameAsync("超级管理员"); |
|||
if (superAdminRole == null) |
|||
{ |
|||
_logger.LogError("未找到超级管理员角色,无法为用户分配角色"); |
|||
return; |
|||
} |
|||
|
|||
// 创建用户数据(使用固定用户名避免生成问题)
|
|||
await CreateUserIfNotExistsAsync("李达康", "lidk001", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
await CreateUserIfNotExistsAsync("高育良", "gyl002", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
await CreateUserIfNotExistsAsync("祁同伟", "qtw003", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
await CreateUserIfNotExistsAsync("侯亮平", "hlp004", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
await CreateUserIfNotExistsAsync("赵瑞龙", "zrl005", GenderType.Female, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
await CreateUserIfNotExistsAsync("宋梦平", "smp006", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员, 部门领导"); |
|||
await CreateUserIfNotExistsAsync("李太亮", "ltl007", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员, 部门领导"); |
|||
await CreateUserIfNotExistsAsync("高峰", "gf008", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员, 部门领导"); |
|||
await CreateUserIfNotExistsAsync("朱丽平", "zlp009", GenderType.Female, supervisionOffice.Id, supervisionOrg.Id, "超级管理员, 部门领导"); |
|||
await CreateUserIfNotExistsAsync("安欣", "ax010", GenderType.Male, supervisionOffice.Id, supervisionOrg.Id, "超级管理员"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建用户(如果不存在)
|
|||
/// </summary>
|
|||
private async Task CreateUserIfNotExistsAsync( |
|||
string name, |
|||
string userName, |
|||
GenderType gender, |
|||
Guid workUnitId, |
|||
Guid orgId, |
|||
string roles) |
|||
{ |
|||
// 检查用户是否已存在
|
|||
var existingUser = await _userRepository.FindAsync(u => u.NickName == name); |
|||
if (existingUser != null) |
|||
{ |
|||
_logger.LogInformation($"用户[{name}]已存在,跳过创建"); |
|||
return; |
|||
} |
|||
|
|||
var identityUser = await _identityUserManager.FindByNameAsync(userName); |
|||
if (identityUser == null) |
|||
{ |
|||
// 创建Identity用户
|
|||
identityUser = new IdentityUser( |
|||
_guidGenerator.Create(), |
|||
userName, |
|||
$"{userName}@example.com", |
|||
_currentTenant.Id) |
|||
{ |
|||
Name = name, |
|||
Surname = "" |
|||
}; |
|||
|
|||
// 设置默认密码 123456
|
|||
var identityResult = await _identityUserManager.CreateAsync(identityUser, "123456"); |
|||
if (!identityResult.Succeeded) |
|||
{ |
|||
_logger.LogError($"创建Identity用户[{name}]失败: {string.Join(", ", identityResult.Errors.Select(e => e.Description))}"); |
|||
return; |
|||
} |
|||
|
|||
// 分配角色
|
|||
if (!string.IsNullOrWhiteSpace(roles)) |
|||
{ |
|||
var roleNames = roles.Split(',', StringSplitOptions.RemoveEmptyEntries); |
|||
foreach (var roleName in roleNames) |
|||
{ |
|||
var trimmedRoleName = roleName.Trim(); |
|||
var role = await _identityRoleManager.FindByNameAsync(trimmedRoleName); |
|||
if (role != null) |
|||
{ |
|||
var roleResult = await _identityUserManager.AddToRoleAsync(identityUser, trimmedRoleName); |
|||
if (!roleResult.Succeeded) |
|||
{ |
|||
_logger.LogWarning($"为用户[{name}]分配角色[{trimmedRoleName}]失败: {string.Join(", ", roleResult.Errors.Select(e => e.Description))}"); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
_logger.LogWarning($"角色[{trimmedRoleName}]不存在,无法为用户[{name}]分配"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 创建系统用户
|
|||
var user = new User( |
|||
_guidGenerator.Create(), |
|||
name, |
|||
workUnitId, |
|||
identityUser.Id, |
|||
gender) |
|||
{ |
|||
OrgId = orgId |
|||
}; |
|||
|
|||
// 保存用户
|
|||
await _userRepository.InsertAsync(user); |
|||
|
|||
_logger.LogInformation($"创建用户:{name},用户名:{userName}"); |
|||
} |
|||
else |
|||
{ |
|||
_logger.LogInformation($"Identity用户[{userName}]已存在,检查是否需要创建业务用户"); |
|||
|
|||
// 检查是否需要创建业务用户
|
|||
var businessUser = await _userRepository.FindAsync(u => u.IdentityUserId == identityUser.Id); |
|||
if (businessUser == null) |
|||
{ |
|||
// 创建系统用户
|
|||
var user = new User( |
|||
_guidGenerator.Create(), |
|||
name, |
|||
workUnitId, |
|||
identityUser.Id, |
|||
gender) |
|||
{ |
|||
OrgId = orgId |
|||
}; |
|||
|
|||
// 保存用户
|
|||
await _userRepository.InsertAsync(user); |
|||
|
|||
_logger.LogInformation($"为已存在的Identity用户创建业务用户:{name}"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users.Dtos |
|||
{ |
|||
[Serializable] |
|||
public class CreateUpdateUserDto |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名称
|
|||
/// </summary>
|
|||
[Required(ErrorMessage = "用户名称不能为空")] |
|||
[StringLength(50, ErrorMessage = "用户名称长度不能超过50个字符")] |
|||
public string NickName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 密码
|
|||
/// </summary>
|
|||
[StringLength(20, MinimumLength = 6, ErrorMessage = "密码长度必须在6-20个字符之间")] |
|||
public string Password { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 联系方式
|
|||
/// </summary>
|
|||
public string ContactInfo { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 职位
|
|||
/// </summary>
|
|||
public string Position { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool IsActive { get; set; } = true; |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users.Dtos |
|||
{ |
|||
[Serializable] |
|||
public class UserDto : FullAuditedEntityDto<Guid> |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名称
|
|||
/// </summary>
|
|||
public string NickName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Identity用户Id
|
|||
/// </summary>
|
|||
public Guid IdentityUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 用户状态
|
|||
/// </summary>
|
|||
public bool IsActive { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 联系方式
|
|||
/// </summary>
|
|||
public string ContactInfo { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 职位
|
|||
/// </summary>
|
|||
public string Position { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 角色名称
|
|||
/// </summary>
|
|||
public string RoleNames { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users.Dtos |
|||
{ |
|||
[Serializable] |
|||
public class UserItemDto : FullAuditedEntityDto<Guid> |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名称
|
|||
/// </summary>
|
|||
public string NickName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Identity用户Id
|
|||
/// </summary>
|
|||
public Guid IdentityUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 用户状态
|
|||
/// </summary>
|
|||
public bool IsActive { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 联系方式
|
|||
/// </summary>
|
|||
public string ContactInfo { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 职位
|
|||
/// </summary>
|
|||
public string Position { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 角色名称
|
|||
/// </summary>
|
|||
public string RoleNames { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users.Dtos |
|||
{ |
|||
[Serializable] |
|||
public class UserPagedAndSortedResultRequestDto : PagedAndSortedResultRequestDto |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名称
|
|||
/// </summary>
|
|||
public string NickName { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
using PackageName.CompanyName.ProjectName.Users.Dtos; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户应用服务接口
|
|||
/// </summary>
|
|||
public interface IUserAppService : |
|||
IApplicationService |
|||
{ |
|||
/// <summary>
|
|||
/// 创建用户
|
|||
/// </summary>
|
|||
Task<UserDto> CreateAsync(CreateUpdateUserDto input); |
|||
|
|||
/// <summary>
|
|||
/// 更新用户
|
|||
/// </summary>
|
|||
Task<UserDto> UpdateAsync(Guid id, CreateUpdateUserDto input); |
|||
|
|||
/// <summary>
|
|||
/// 删除用户
|
|||
/// </summary>
|
|||
Task DeleteAsync(Guid id); |
|||
|
|||
/// <summary>
|
|||
/// 获取用户
|
|||
/// </summary>
|
|||
Task<UserDto> GetAsync(Guid id); |
|||
|
|||
/// <summary>
|
|||
/// 获取用户列表
|
|||
/// </summary>
|
|||
Task<PagedResultDto<UserItemDto>> GetListAsync(UserPagedAndSortedResultRequestDto input); |
|||
|
|||
/// <summary>
|
|||
/// 修改用户密码
|
|||
/// </summary>
|
|||
Task ChangePasswordAsync(Guid id, string currentPassword, string newPassword); |
|||
|
|||
/// <summary>
|
|||
/// 重置用户密码(管理员操作)
|
|||
/// </summary>
|
|||
Task ResetPasswordAsync(Guid id, string newPassword); |
|||
|
|||
/// <summary>
|
|||
/// 启用或禁用用户
|
|||
/// </summary>
|
|||
Task SetUserActiveStatusAsync(Guid id, bool isActive); |
|||
} |
|||
} |
|||
@ -0,0 +1,198 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using PackageName.CompanyName.ProjectName.Permissions; |
|||
using PackageName.CompanyName.ProjectName.Users.Dtos; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Dynamic.Core; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户
|
|||
/// </summary>
|
|||
public class UserAppService : ApplicationService, IUserAppService |
|||
{ |
|||
private readonly IUserRepository _userRepository; |
|||
private readonly IUserManager _userManager; |
|||
private readonly IdentityUserManager _identityUserManager; |
|||
|
|||
public UserAppService( |
|||
IUserRepository userRepository, |
|||
IUserManager userManager, |
|||
IdentityUserManager identityUserManager) |
|||
{ |
|||
_userRepository = userRepository; |
|||
_userManager = userManager; |
|||
_identityUserManager = identityUserManager; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建用户
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Create)] |
|||
public async Task<UserDto> CreateAsync(CreateUpdateUserDto input) |
|||
{ |
|||
// 参数检查和验证逻辑可以在这里添加
|
|||
if (string.IsNullOrEmpty(input.NickName)) |
|||
{ |
|||
throw new UserFriendlyException("昵称不能为空"); |
|||
} |
|||
if (string.IsNullOrEmpty(input.Password)) |
|||
{ |
|||
throw new UserFriendlyException("密码不能为空"); |
|||
} |
|||
|
|||
// 使用UserManager创建用户
|
|||
var user = await _userManager.CreateAsync( |
|||
input.NickName, |
|||
input.Password, |
|||
input.ContactInfo, |
|||
input.Position, |
|||
input.IsActive); |
|||
|
|||
// 返回DTO对象
|
|||
return await MapToUserDtoAsync(user); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 更新用户
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Update)] |
|||
public async Task<UserDto> UpdateAsync(Guid id, CreateUpdateUserDto input) |
|||
{ |
|||
// 使用UserManager更新用户基本信息
|
|||
var user = await _userManager.UpdateAsync( |
|||
id, |
|||
input.NickName, |
|||
input.Password, |
|||
input.ContactInfo, |
|||
input.Position, |
|||
input.IsActive); |
|||
|
|||
// 返回DTO对象
|
|||
return await MapToUserDtoAsync(user); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 删除用户
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Delete)] |
|||
public Task DeleteAsync(Guid id) |
|||
{ |
|||
return _userManager.DeleteAsync(id); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取用户
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Default)] |
|||
public async Task<UserDto> GetAsync(Guid id) |
|||
{ |
|||
var user = await _userManager.GetAsync(id); |
|||
return await MapToUserDtoAsync(user); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取用户列表
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Default)] |
|||
public async Task<PagedResultDto<UserItemDto>> GetListAsync(UserPagedAndSortedResultRequestDto input) |
|||
{ |
|||
// 创建查询
|
|||
var query = await CreateFilteredQueryAsync(input); |
|||
|
|||
// 获取总记录数
|
|||
var totalCount = await AsyncExecuter.CountAsync(query); |
|||
|
|||
// 获取已排序和分页的查询结果
|
|||
var users = await AsyncExecuter.ToListAsync( |
|||
query.OrderBy(input.Sorting ?? nameof(User.NickName)) |
|||
.Skip(input.SkipCount) |
|||
.Take(input.MaxResultCount)); |
|||
|
|||
// 转换为DTO并返回
|
|||
var userDtos = new List<UserItemDto>(); |
|||
foreach (var user in users) |
|||
{ |
|||
var userDto = ObjectMapper.Map<User, UserItemDto>(user); |
|||
|
|||
// 填充角色信息
|
|||
if (user.IdentityUser != null) |
|||
{ |
|||
var roles = await _identityUserManager.GetRolesAsync(user.IdentityUser); |
|||
userDto.RoleNames = string.Join("、", roles); |
|||
userDto.IsActive = user.IdentityUser.LockoutEnd == null || user.IdentityUser.LockoutEnd < DateTimeOffset.Now; |
|||
} |
|||
|
|||
userDtos.Add(userDto); |
|||
} |
|||
|
|||
return new PagedResultDto<UserItemDto>(totalCount, userDtos); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 修改用户密码
|
|||
/// </summary>
|
|||
[Authorize] |
|||
public async Task ChangePasswordAsync(Guid id, string currentPassword, string newPassword) |
|||
{ |
|||
await _userManager.ChangePasswordAsync(id, currentPassword, newPassword); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置用户密码(管理员操作)
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Update)] |
|||
public async Task ResetPasswordAsync(Guid id, string newPassword) |
|||
{ |
|||
await _userManager.ResetPasswordAsync(id, newPassword); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 启用或禁用用户
|
|||
/// </summary>
|
|||
[Authorize(ProjectNamePermissions.User.Update)] |
|||
public async Task SetUserActiveStatusAsync(Guid id, bool isActive) |
|||
{ |
|||
await _userManager.SetUserActiveStatusAsync(id, isActive); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建基础查询,应用过滤条件
|
|||
/// </summary>
|
|||
protected async virtual Task<IQueryable<User>> CreateFilteredQueryAsync( |
|||
UserPagedAndSortedResultRequestDto input) |
|||
{ |
|||
// 获取基础查询,并加载相关实体
|
|||
var query = await _userRepository.WithDetailsAsync( |
|||
x => x.IdentityUser); |
|||
|
|||
// 应用过滤条件
|
|||
return query |
|||
.WhereIf(!string.IsNullOrWhiteSpace(input.NickName), |
|||
x => x.NickName.Contains(input.NickName)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 将User实体映射为UserDto,并填充权限信息
|
|||
/// </summary>
|
|||
private Task<UserDto> MapToUserDtoAsync(User user) |
|||
{ |
|||
var userDto = ObjectMapper.Map<User, UserDto>(user); |
|||
|
|||
// 设置用户状态
|
|||
if (user.IdentityUser != null) |
|||
{ |
|||
userDto.IsActive = user.IdentityUser.LockoutEnd == null || user.IdentityUser.LockoutEnd < DateTimeOffset.Now; |
|||
} |
|||
|
|||
return Task.FromResult(userDto); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using Volo.Abp.Auditing; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.TreeCodes |
|||
{ |
|||
/// <summary>
|
|||
/// 定义具有树形编码的实体接口
|
|||
/// </summary>
|
|||
public interface IHaveTreeCode : IHasCreationTime |
|||
{ |
|||
/// <summary>
|
|||
/// 树形编码
|
|||
/// </summary>
|
|||
string TreeCode { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 父级Id
|
|||
/// </summary>
|
|||
Guid? ParentId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.TreeCodes |
|||
{ |
|||
/// <summary>
|
|||
/// 树形编码生成器接口
|
|||
/// </summary>
|
|||
public interface ITreeCodeGenerator |
|||
{ |
|||
/// <summary>
|
|||
/// 生成树形编码
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">实体类型</typeparam>
|
|||
/// <param name="repository">仓储</param>
|
|||
/// <param name="parentId">父级Id</param>
|
|||
/// <returns>生成的树形编码</returns>
|
|||
Task<string> GenerateAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository, |
|||
Guid? parentId) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode; |
|||
|
|||
/// <summary>
|
|||
/// 更新节点及其所有子节点的TreeCode
|
|||
/// </summary>
|
|||
Task UpdateTreeCodesAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository, |
|||
Guid entityId) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode; |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.TreeCodes |
|||
{ |
|||
/// <summary>
|
|||
/// 树形编码生成器
|
|||
/// </summary>
|
|||
public class TreeCodeGenerator : ITreeCodeGenerator, ISingletonDependency |
|||
{ |
|||
/// <summary>
|
|||
/// 生成树形编码
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">实体类型</typeparam>
|
|||
/// <param name="repository">仓储</param>
|
|||
/// <param name="parentId">父级Id</param>
|
|||
/// <returns>生成的树形编码</returns>
|
|||
public async virtual Task<string> GenerateAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository, |
|||
Guid? parentId) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode |
|||
{ |
|||
if (!parentId.HasValue) |
|||
{ |
|||
// 生成根节点编码
|
|||
return await GenerateRootCodeAsync(repository); |
|||
} |
|||
else |
|||
{ |
|||
// 生成子节点编码
|
|||
return await GenerateChildCodeAsync(repository, parentId.Value); |
|||
} |
|||
} |
|||
|
|||
private async Task<string> GenerateRootCodeAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode |
|||
{ |
|||
var query = await repository.GetQueryableAsync(); |
|||
query = query.Where(e => e.ParentId == null).OrderByDescending(e => e.CreationTime); |
|||
var maxCodeEntity = await repository.AsyncExecuter.FirstOrDefaultAsync(query); |
|||
|
|||
if (maxCodeEntity == null) |
|||
{ |
|||
return "0001"; |
|||
} |
|||
|
|||
int maxCode = int.Parse(maxCodeEntity.TreeCode.Split('.').LastOrDefault("0")); |
|||
return (maxCode + 1).ToString("D4"); |
|||
} |
|||
|
|||
private async Task<string> GenerateChildCodeAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository, |
|||
Guid parentId) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode |
|||
{ |
|||
var parent = await repository.GetAsync(parentId); |
|||
if (parent == null) |
|||
{ |
|||
throw new EntityNotFoundException(typeof(TEntity), parentId); |
|||
} |
|||
|
|||
var query = await repository.GetQueryableAsync(); |
|||
query = query.Where(e => e.ParentId == parentId).OrderByDescending(e => e.CreationTime); |
|||
var maxCodeEntity = await repository.AsyncExecuter.FirstOrDefaultAsync(query); |
|||
|
|||
string newCode; |
|||
if (maxCodeEntity == null) |
|||
{ |
|||
newCode = "0001"; |
|||
} |
|||
else |
|||
{ |
|||
int maxCode = int.Parse(maxCodeEntity.TreeCode.Split('.').Last()); |
|||
newCode = (maxCode + 1).ToString("D4"); |
|||
} |
|||
|
|||
// 构建完整的TreeCode: 父TreeCode.新编码
|
|||
return $"{parent.TreeCode}.{newCode}"; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 更新节点及其所有子节点的TreeCode
|
|||
/// </summary>
|
|||
public async virtual Task UpdateTreeCodesAsync<TEntity>( |
|||
IRepository<TEntity, Guid> repository, |
|||
Guid entityId) |
|||
where TEntity : class, IEntity<Guid>, IHaveTreeCode |
|||
{ |
|||
var entity = await repository.GetAsync(entityId); |
|||
var query = await repository.GetQueryableAsync(); |
|||
var children = await repository.AsyncExecuter.ToListAsync( |
|||
query.Where(e => e.ParentId == entityId)); |
|||
|
|||
foreach (var child in children) |
|||
{ |
|||
// 获取子节点编码(TreeCode最后一部分)或生成新编码
|
|||
string childCode = child.TreeCode.Contains('.') |
|||
? child.TreeCode.Split('.').Last() |
|||
: child.TreeCode; |
|||
|
|||
child.TreeCode = $"{entity.TreeCode}.{childCode}"; |
|||
await repository.UpdateAsync(child); |
|||
|
|||
// 递归更新子节点
|
|||
await UpdateTreeCodesAsync(repository, child.Id); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Services; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户管理服务接口
|
|||
/// </summary>
|
|||
public interface IUserManager : IDomainService |
|||
{ |
|||
/// <summary>
|
|||
/// 创建新用户
|
|||
/// </summary>
|
|||
Task<User> CreateAsync( |
|||
string nickName, |
|||
string password, |
|||
string contactInfo = null, |
|||
string position = null, |
|||
bool isActive = true |
|||
); |
|||
|
|||
/// <summary>
|
|||
/// 更新用户信息
|
|||
/// </summary>
|
|||
Task<User> UpdateAsync( |
|||
Guid id, |
|||
string nickName, |
|||
string password, |
|||
string contactInfo = null, |
|||
string position = null, |
|||
bool isActive = true); |
|||
|
|||
/// <summary>
|
|||
/// 删除用户
|
|||
/// </summary>
|
|||
Task DeleteAsync(Guid id); |
|||
|
|||
/// <summary>
|
|||
/// 修改用户密码
|
|||
/// </summary>
|
|||
Task ChangePasswordAsync(Guid id, string currentPassword, string newPassword); |
|||
|
|||
/// <summary>
|
|||
/// 重置用户密码
|
|||
/// </summary>
|
|||
Task ResetPasswordAsync(Guid id, string newPassword); |
|||
|
|||
/// <summary>
|
|||
/// 获取用户信息
|
|||
/// </summary>
|
|||
Task<User> GetAsync(Guid id); |
|||
|
|||
/// <summary>
|
|||
/// 根据Identity用户ID获取用户
|
|||
/// </summary>
|
|||
Task<User> FindByIdentityUserIdAsync(Guid identityUserId); |
|||
|
|||
/// <summary>
|
|||
/// 根据用户昵称查找用户
|
|||
/// </summary>
|
|||
Task<User> FindByNickNameAsync(string nickName); |
|||
|
|||
/// <summary>
|
|||
/// 禁用或启用用户
|
|||
/// </summary>
|
|||
Task SetUserActiveStatusAsync(Guid id, bool isActive); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
public interface IUserRepository : IRepository<User, Guid> |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户实体
|
|||
/// </summary>
|
|||
public class User : FullAuditedEntity<Guid> |
|||
{ |
|||
/// <summary>
|
|||
/// 用户名称
|
|||
/// </summary>
|
|||
[MaxLength(50)] |
|||
public string NickName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Identity用户Id
|
|||
/// </summary>
|
|||
public Guid IdentityUserId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Identity用户
|
|||
/// </summary>
|
|||
public virtual IdentityUser IdentityUser { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 联系方式
|
|||
/// </summary>
|
|||
[MaxLength(50)] |
|||
public string ContactInfo { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 职位
|
|||
/// </summary>
|
|||
[MaxLength(50)] |
|||
public string Position { get; set; } |
|||
|
|||
protected User() |
|||
{ |
|||
} |
|||
|
|||
public User( |
|||
Guid id, |
|||
string nickName, |
|||
Guid identityUserId, |
|||
string contactInfo = null, |
|||
string position = null |
|||
) : base(id) |
|||
{ |
|||
NickName = nickName; |
|||
IdentityUserId = identityUserId; |
|||
ContactInfo = contactInfo; |
|||
Position = position; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,406 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Services; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户管理服务,用于处理用户的CRUD操作
|
|||
/// </summary>
|
|||
public class UserManager : DomainService, IUserManager |
|||
{ |
|||
private readonly IUserRepository _userRepository; |
|||
private readonly IdentityUserManager _identityUserManager; |
|||
private readonly ILogger<UserManager> _logger; |
|||
|
|||
public UserManager( |
|||
IUserRepository userRepository, |
|||
IdentityUserManager identityUserManager, |
|||
ILogger<UserManager> logger) |
|||
{ |
|||
_userRepository = userRepository; |
|||
_identityUserManager = identityUserManager; |
|||
_logger = logger; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建新用户
|
|||
/// </summary>
|
|||
/// <param name="nickName">用户昵称</param>
|
|||
/// <param name="password">用户密码</param>
|
|||
/// <param name="contactInfo">联系方式</param>
|
|||
/// <param name="position">职位</param>
|
|||
/// <param name="isActive">是否启用</param>
|
|||
/// <returns>创建的用户实体</returns>
|
|||
public async Task<User> CreateAsync( |
|||
string nickName, |
|||
string password, |
|||
string contactInfo = null, |
|||
string position = null, |
|||
bool isActive = true) |
|||
{ |
|||
// 参数验证
|
|||
if (string.IsNullOrWhiteSpace(nickName)) |
|||
{ |
|||
throw new UserFriendlyException("用户名不能为空"); |
|||
} |
|||
|
|||
// 密码校验
|
|||
if (string.IsNullOrWhiteSpace(password) || password.Length < 6) |
|||
{ |
|||
throw new UserFriendlyException("密码不能为空且长度不能少于6位"); |
|||
} |
|||
|
|||
// 检查用户昵称是否已存在
|
|||
var existingUser = await _userRepository.FindAsync(u => u.NickName == nickName); |
|||
if (existingUser != null) |
|||
{ |
|||
throw new UserFriendlyException($"昵称为 '{nickName}' 的用户已存在"); |
|||
} |
|||
|
|||
// 创建Identity用户
|
|||
var identityUser = new IdentityUser(GuidGenerator.Create(), nickName, $"{nickName}@inspection.com"); |
|||
var identityResult = await _identityUserManager.CreateAsync(identityUser, password); |
|||
if (!identityResult.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("创建用户失败: " + |
|||
string.Join(", ", identityResult.Errors.Select(x => x.Description))); |
|||
} |
|||
|
|||
// 设置用户状态
|
|||
if (!isActive) |
|||
{ |
|||
var lockoutResult = await _identityUserManager.SetLockoutEndDateAsync(identityUser, DateTimeOffset.MaxValue); |
|||
if (!lockoutResult.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("设置用户状态失败: " + |
|||
string.Join(", ", lockoutResult.Errors.Select(e => e.Description))); |
|||
} |
|||
} |
|||
|
|||
// 创建业务用户
|
|||
var user = new User( |
|||
GuidGenerator.Create(), |
|||
nickName, |
|||
identityUser.Id, |
|||
contactInfo, |
|||
position |
|||
); |
|||
|
|||
// 保存用户
|
|||
await _userRepository.InsertAsync(user, true); |
|||
|
|||
_logger.LogInformation($"创建了新用户:{nickName},ID:{user.Id}"); |
|||
|
|||
return user; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 更新用户信息
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <param name="nickName">用户昵称</param>
|
|||
/// <param name="password">用户密码(可选,如不修改则传入null)</param>
|
|||
/// <param name="contactInfo">联系方式</param>
|
|||
/// <param name="position">职位</param>
|
|||
/// <param name="isActive">是否启用</param>
|
|||
/// <returns>更新后的用户实体</returns>
|
|||
public async Task<User> UpdateAsync( |
|||
Guid id, |
|||
string nickName, |
|||
string password, |
|||
string contactInfo = null, |
|||
string position = null, |
|||
bool isActive = true) |
|||
{ |
|||
// 最大重试次数
|
|||
const int maxRetries = 3; |
|||
int retryCount = 0; |
|||
|
|||
while (true) |
|||
{ |
|||
try |
|||
{ |
|||
// 每次尝试时重新获取最新的用户数据
|
|||
var user = await _userRepository.GetAsync(id, false); |
|||
if (user == null) |
|||
{ |
|||
throw new UserFriendlyException("用户不存在"); |
|||
} |
|||
|
|||
// 检查用户昵称是否已被其他用户使用
|
|||
var existingUser = await _userRepository.FindAsync(u => u.NickName == nickName && u.Id != id); |
|||
if (existingUser != null) |
|||
{ |
|||
throw new UserFriendlyException($"昵称为 '{nickName}' 的用户已存在"); |
|||
} |
|||
|
|||
// 更新Identity用户
|
|||
var identityUser = await _identityUserManager.FindByIdAsync(user.IdentityUserId.ToString()); |
|||
if (identityUser == null) |
|||
{ |
|||
throw new UserFriendlyException("Identity用户不存在"); |
|||
} |
|||
|
|||
// 更新用户名
|
|||
var usernameResult = await _identityUserManager.SetUserNameAsync(identityUser, nickName); |
|||
if (!usernameResult.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("更新用户名失败: " + |
|||
string.Join(", ", usernameResult.Errors.Select(e => e.Description))); |
|||
} |
|||
|
|||
// 更新电子邮件
|
|||
var emailResult = await _identityUserManager.SetEmailAsync(identityUser, $"{nickName}@inspection.com"); |
|||
if (!emailResult.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("更新电子邮件失败: " + |
|||
string.Join(", ", emailResult.Errors.Select(e => e.Description))); |
|||
} |
|||
|
|||
// 如果提供了新密码,则更新密码
|
|||
if (!string.IsNullOrEmpty(password)) |
|||
{ |
|||
// 移除当前密码
|
|||
await _identityUserManager.RemovePasswordAsync(identityUser); |
|||
// 设置新密码
|
|||
var passwordResult = await _identityUserManager.AddPasswordAsync(identityUser, password); |
|||
if (!passwordResult.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("更新密码失败: " + |
|||
string.Join(", ", passwordResult.Errors.Select(e => e.Description))); |
|||
} |
|||
} |
|||
|
|||
// 设置用户状态
|
|||
await SetUserActiveStatusAsync(id, isActive); |
|||
|
|||
// 更新用户信息
|
|||
user.NickName = nickName; |
|||
user.ContactInfo = contactInfo; |
|||
user.Position = position; |
|||
|
|||
// 保存更新
|
|||
await _userRepository.UpdateAsync(user, true); |
|||
|
|||
_logger.LogInformation($"更新了用户信息:{nickName},ID:{user.Id}"); |
|||
|
|||
return user; |
|||
} |
|||
catch (Volo.Abp.Data.AbpDbConcurrencyException ex) |
|||
{ |
|||
// 增加重试计数
|
|||
retryCount++; |
|||
|
|||
// 如果达到最大重试次数,则抛出用户友好的异常
|
|||
if (retryCount >= maxRetries) |
|||
{ |
|||
throw new UserFriendlyException( |
|||
"更新用户信息失败:数据已被其他用户修改。请刷新页面后重试。", |
|||
"409", ex.Message, |
|||
ex); |
|||
} |
|||
|
|||
// 短暂延迟后重试
|
|||
await Task.Delay(100 * retryCount); // 逐步增加延迟时间
|
|||
|
|||
// 记录重试信息
|
|||
_logger.LogWarning($"检测到用户[{id}]更新时发生并发冲突,正在进行第{retryCount}次重试..."); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 删除用户
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <returns>操作任务</returns>
|
|||
public async Task DeleteAsync(Guid id) |
|||
{ |
|||
// 获取用户
|
|||
var user = await _userRepository.GetAsync(id); |
|||
if (user == null) |
|||
{ |
|||
throw new UserFriendlyException("用户不存在"); |
|||
} |
|||
|
|||
// 删除Identity用户
|
|||
var identityUser = await _identityUserManager.FindByIdAsync(user.IdentityUserId.ToString()); |
|||
if (identityUser != null) |
|||
{ |
|||
var result = await _identityUserManager.DeleteAsync(identityUser); |
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("删除Identity用户失败: " + |
|||
string.Join(", ", result.Errors.Select(e => e.Description))); |
|||
} |
|||
} |
|||
|
|||
// 删除用户
|
|||
await _userRepository.DeleteAsync(user); |
|||
|
|||
_logger.LogInformation($"删除了用户,ID:{id}"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 修改用户密码
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <param name="currentPassword">当前密码</param>
|
|||
/// <param name="newPassword">新密码</param>
|
|||
/// <returns>操作结果</returns>
|
|||
public async Task ChangePasswordAsync(Guid id, string currentPassword, string newPassword) |
|||
{ |
|||
if (string.IsNullOrEmpty(newPassword) || newPassword.Length < 6) |
|||
{ |
|||
throw new UserFriendlyException("新密码不能为空且长度不能少于6位"); |
|||
} |
|||
|
|||
// 获取用户
|
|||
var user = await _userRepository.GetAsync(id); |
|||
if (user == null) |
|||
{ |
|||
throw new UserFriendlyException("用户不存在"); |
|||
} |
|||
|
|||
// 获取Identity用户
|
|||
var identityUser = await _identityUserManager.FindByIdAsync(user.IdentityUserId.ToString()); |
|||
if (identityUser == null) |
|||
{ |
|||
throw new UserFriendlyException("Identity用户不存在"); |
|||
} |
|||
|
|||
// 修改密码
|
|||
var result = await _identityUserManager.ChangePasswordAsync(identityUser, currentPassword, newPassword); |
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("修改密码失败: " + |
|||
string.Join(", ", result.Errors.Select(e => e.Description))); |
|||
} |
|||
|
|||
_logger.LogInformation($"用户[{user.NickName}]成功修改了密码"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置用户密码(管理员操作)
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <param name="newPassword">新密码</param>
|
|||
/// <returns>操作结果</returns>
|
|||
public async Task ResetPasswordAsync(Guid id, string newPassword) |
|||
{ |
|||
if (string.IsNullOrEmpty(newPassword) || newPassword.Length < 6) |
|||
{ |
|||
throw new UserFriendlyException("新密码不能为空且长度不能少于6位"); |
|||
} |
|||
|
|||
// 获取用户
|
|||
var user = await _userRepository.GetAsync(id); |
|||
if (user == null) |
|||
{ |
|||
throw new UserFriendlyException("用户不存在"); |
|||
} |
|||
|
|||
// 获取Identity用户
|
|||
var identityUser = await _identityUserManager.FindByIdAsync(user.IdentityUserId.ToString()); |
|||
if (identityUser == null) |
|||
{ |
|||
throw new UserFriendlyException("Identity用户不存在"); |
|||
} |
|||
|
|||
// 生成重置令牌
|
|||
var token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityUser); |
|||
|
|||
// 重置密码
|
|||
var result = await _identityUserManager.ResetPasswordAsync(identityUser, token, newPassword); |
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException("重置密码失败: " + |
|||
string.Join(", ", result.Errors.Select(e => e.Description))); |
|||
} |
|||
|
|||
_logger.LogInformation($"管理员重置了用户[{user.NickName}]的密码"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取用户信息
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <returns>用户实体</returns>
|
|||
public async Task<User> GetAsync(Guid id) |
|||
{ |
|||
return await _userRepository.GetAsync(id); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 根据Identity用户ID获取用户
|
|||
/// </summary>
|
|||
/// <param name="identityUserId">Identity用户ID</param>
|
|||
/// <returns>用户实体,如果不存在则返回null</returns>
|
|||
public async Task<User> FindByIdentityUserIdAsync(Guid identityUserId) |
|||
{ |
|||
return await _userRepository.FindAsync(u => u.IdentityUserId == identityUserId); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 根据用户昵称查找用户
|
|||
/// </summary>
|
|||
/// <param name="nickName">用户昵称</param>
|
|||
/// <returns>用户实体,如果不存在则返回null</returns>
|
|||
public async Task<User> FindByNickNameAsync(string nickName) |
|||
{ |
|||
return await _userRepository.FindAsync(u => u.NickName == nickName); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 禁用或启用用户
|
|||
/// </summary>
|
|||
/// <param name="id">用户ID</param>
|
|||
/// <param name="isActive">是否启用</param>
|
|||
/// <returns>操作任务</returns>
|
|||
public async Task SetUserActiveStatusAsync(Guid id, bool isActive) |
|||
{ |
|||
// 获取用户
|
|||
var user = await _userRepository.GetAsync(id); |
|||
if (user == null) |
|||
{ |
|||
throw new UserFriendlyException("用户不存在"); |
|||
} |
|||
|
|||
// 获取Identity用户
|
|||
var identityUser = await _identityUserManager.FindByIdAsync(user.IdentityUserId.ToString()); |
|||
if (identityUser == null) |
|||
{ |
|||
throw new UserFriendlyException("Identity用户不存在"); |
|||
} |
|||
|
|||
// 设置用户状态
|
|||
if (isActive) |
|||
{ |
|||
// 启用用户
|
|||
var result = await _identityUserManager.SetLockoutEndDateAsync(identityUser, null); |
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException($"启用用户失败: " + |
|||
string.Join(", ", result.Errors.Select(e => e.Description))); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// 禁用用户(设置永久锁定)
|
|||
var result = await _identityUserManager.SetLockoutEndDateAsync(identityUser, DateTimeOffset.MaxValue); |
|||
if (!result.Succeeded) |
|||
{ |
|||
throw new UserFriendlyException($"禁用用户失败: " + |
|||
string.Join(", ", result.Errors.Select(e => e.Description))); |
|||
} |
|||
} |
|||
|
|||
_logger.LogInformation($"已{(isActive ? "启用" : "禁用")}用户[{user.NickName}]"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using PackageName.CompanyName.ProjectName.EntityFrameworkCore; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
public class UserRepository : EfCoreRepository<ProjectNameDbContext, User, Guid>, IUserRepository |
|||
{ |
|||
public UserRepository(IDbContextProvider<ProjectNameDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public override async Task<IQueryable<User>> WithDetailsAsync() |
|||
{ |
|||
return (await GetDbSetAsync()).Include(x => x.IdentityUser); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using PackageName.CompanyName.ProjectName.Users.Dtos; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Application.Dtos; |
|||
|
|||
namespace PackageName.CompanyName.ProjectName.Users |
|||
{ |
|||
/// <summary>
|
|||
/// 用户管理控制器
|
|||
/// </summary>
|
|||
[RemoteService] |
|||
[Route("api/app/user")] |
|||
public class UserController : ProjectNameControllerBase |
|||
{ |
|||
private readonly IUserAppService _userAppService; |
|||
|
|||
public UserController(IUserAppService userAppService) |
|||
{ |
|||
_userAppService = userAppService; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 创建用户
|
|||
/// </summary>
|
|||
[HttpPost] |
|||
public async Task<UserDto> CreateAsync(CreateUpdateUserDto input) |
|||
{ |
|||
return await _userAppService.CreateAsync(input); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 更新用户
|
|||
/// </summary>
|
|||
[HttpPut("{id}")] |
|||
public async Task<UserDto> UpdateAsync(Guid id, CreateUpdateUserDto input) |
|||
{ |
|||
return await _userAppService.UpdateAsync(id, input); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 删除用户
|
|||
/// </summary>
|
|||
[HttpDelete("{id}")] |
|||
public async Task DeleteAsync(Guid id) |
|||
{ |
|||
await _userAppService.DeleteAsync(id); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取用户
|
|||
/// </summary>
|
|||
[HttpGet("{id}")] |
|||
public async Task<UserDto> GetAsync(Guid id) |
|||
{ |
|||
return await _userAppService.GetAsync(id); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取用户列表
|
|||
/// </summary>
|
|||
[HttpGet] |
|||
public async Task<PagedResultDto<UserItemDto>> GetListAsync(UserPagedAndSortedResultRequestDto input) |
|||
{ |
|||
return await _userAppService.GetListAsync(input); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 修改用户密码
|
|||
/// </summary>
|
|||
[HttpPost("{id}/change-password")] |
|||
public async Task ChangePasswordAsync(Guid id, [FromBody] ChangePasswordRequest request) |
|||
{ |
|||
await _userAppService.ChangePasswordAsync(id, request.CurrentPassword, request.NewPassword); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置用户密码(管理员操作)
|
|||
/// </summary>
|
|||
[HttpPost("{id}/reset-password")] |
|||
public async Task ResetPasswordAsync(Guid id, [FromBody] ResetPasswordRequest request) |
|||
{ |
|||
await _userAppService.ResetPasswordAsync(id, request.NewPassword); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 启用或禁用用户
|
|||
/// </summary>
|
|||
[HttpPost("{id}/set-active")] |
|||
public async Task SetUserActiveStatusAsync(Guid id, [FromBody] SetUserActiveRequest request) |
|||
{ |
|||
await _userAppService.SetUserActiveStatusAsync(id, request.IsActive); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 修改密码请求
|
|||
/// </summary>
|
|||
public class ChangePasswordRequest |
|||
{ |
|||
/// <summary>
|
|||
/// 当前密码
|
|||
/// </summary>
|
|||
public string CurrentPassword { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 新密码
|
|||
/// </summary>
|
|||
public string NewPassword { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置密码请求
|
|||
/// </summary>
|
|||
public class ResetPasswordRequest |
|||
{ |
|||
/// <summary>
|
|||
/// 新密码
|
|||
/// </summary>
|
|||
public string NewPassword { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 设置用户状态请求
|
|||
/// </summary>
|
|||
public class SetUserActiveRequest |
|||
{ |
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool IsActive { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue