马梓彭 2c972df6d5 删除MiniExcel统一采用NPOI
对接完善打分系统工作台
2026-09-04 17:15:03 +08:00

465 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YD_Event.Application.Auth;
using YD_Event.Application.Menu;
using YD_Event.Application.User.Dtos;
using YD_Event.Core.Options;
using YD_Event.Core.Shared;
using Microsoft.Extensions.Options;
namespace YD_Event.Application.User;
/// <summary>
/// 系统用户管理
/// </summary>
public class SysUserService : BaseService<SysUser>, ITransient
{
private readonly ISqlSugarRepository<SysUser> _repository;
private readonly ISqlSugarRepository<SysUserRole> _userRoleRepository;
private readonly ISqlSugarRepository<SysRole> _roleRepository;
private readonly ISqlSugarRepository<SysOrganization> _orgRepository;
private readonly SysMenuService _sysMenuService;
private readonly AuthManager _authManager;
private readonly IEasyCachingProvider _easyCachingProvider;
private readonly IIdGenerator _idGenerator;
private readonly IOptionsMonitor<RoleOptions> _roleOptionsMonitor;
public SysUserService(ISqlSugarRepository<SysUser> repository,
ISqlSugarRepository<SysUserRole> userRoleRepository,
ISqlSugarRepository<SysRole> roleRepository,
ISqlSugarRepository<SysOrganization> orgRepository,
SysMenuService sysMenuService,
AuthManager authManager,
IEasyCachingProvider easyCachingProvider,
IIdGenerator idGenerator,
IOptionsMonitor<RoleOptions> roleOptionsMonitor) : base(repository)
{
_repository = repository;
_userRoleRepository = userRoleRepository;
_roleRepository = roleRepository;
_orgRepository = orgRepository;
_sysMenuService = sysMenuService;
_authManager = authManager;
_easyCachingProvider = easyCachingProvider;
_idGenerator = idGenerator;
_roleOptionsMonitor = roleOptionsMonitor;
}
/// <summary>
/// 检查当前登录用户是否是管理员
/// </summary>
/// <returns></returns>
private async Task<bool> IsCurrentUserAdminAsync()
{
var userId = _authManager.UserId;
// 首先检查是否是超级管理员(用户ID为1)
if (_authManager.IsSuperAdmin)
{
return true;
}
// 检查用户是否拥有管理员角色
return await _userRoleRepository.IsAnyAsync(x => x.UserId == userId && x.RoleId == _roleOptionsMonitor.CurrentValue.AdminRoleId);
}
/// <summary>
/// 系统用户分页查询
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("系统用户分页查询")]
[HttpGet("page")]
public async Task<PageResult<SysUserPageOutput>> Page([FromQuery] QuerySysUserInput dto)
{
var isAdmin = await IsCurrentUserAdminAsync();
// 构造基本查询
var query = _repository.AsQueryable()
.Where(x => x.Id > 1) // 排除超级管理员或特定ID
// 权限管理中的“报名平台”只管理后台账号;单位/打分账号由对应平台页签管理。
.Where(x => x.UnitPlatform == UnitAccountPlatform.EventSystem)
.WhereIF(!string.IsNullOrWhiteSpace(dto.Name), x => x.Name.Contains(dto.Name))
.WhereIF(!string.IsNullOrWhiteSpace(dto.Account), x => x.Account.Contains(dto.Account))
.WhereIF(dto.StartTime.HasValue, x => x.CreatedTime >= dto.StartTime.Value)
.WhereIF(dto.EndTime.HasValue, x => x.CreatedTime <= dto.EndTime.Value);
// 如果需要按角色筛选
if (dto.RoleId.HasValue)
{
query = query.InnerJoin<SysUserRole>((u, ur) => u.Id == ur.UserId && ur.RoleId == dto.RoleId.Value);
}
else if (!isAdmin)
{
// 非管理员用户,排除掉拥有管理员和单位用户角色的用户
var excludedRoleIds = new List<long> { _roleOptionsMonitor.CurrentValue.AdminRoleId, _roleOptionsMonitor.CurrentValue.UnitUserRoleId };
// 使用子查询来获取那些拥有被排除角色的用户ID
var excludedUserIds = await _userRoleRepository.AsQueryable()
.Where(x => excludedRoleIds.Contains(x.RoleId))
.Select(x => x.UserId)
.Distinct()
.ToListAsync();
// 排除这些用户
query = query.Where(x => !excludedUserIds.Contains(x.Id));
}
var entityList = await query.ToPagedListAsync(dto);
// 转换并填充角色名称
var resultList = new List<SysUserPageOutput>();
// 批量获取角色信息优化性能
var userIds = entityList.Rows.Select(x => x.Id).ToList();
var userRoles = await _userRoleRepository.AsQueryable()
.InnerJoin<SysRole>((ur, r) => ur.RoleId == r.Id)
.Where((ur, r) => userIds.Contains(ur.UserId))
.Select((ur, r) => new { ur.UserId,r.Id, RoleName = r.Name })
.ToListAsync();
foreach (var user in entityList.Rows)
{
var output = user.Adapt<SysUserPageOutput>();
var roles = userRoles.Where(x => x.UserId == user.Id).Select(x => x.RoleName).ToList();
output.RoleNames = string.Join(",", roles);
var roleIds = userRoles.Where(x => x.UserId == user.Id).Select(x => x.Id).ToList();
output.RoleIds = string.Join(",", roleIds);
resultList.Add(output);
}
return new PageResult<SysUserPageOutput>
{
PageNo = entityList.PageNo,
PageSize = entityList.PageSize,
Total = entityList.Total,
Rows = resultList,
Pages = entityList.Pages
};
}
/// <summary>
/// 添加系统用户
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[UnitOfWork, HttpPost("user")]
[DisplayName("添加系统用户")]
public async Task AddUser(AddSysUserInput dto)
{
// 规范化文本输入,避免首尾空格导致账号查重与登录不一致
dto.Account = dto.Account.Trim();
dto.Name = dto.Name.Trim();
// 校验账号是否已存在
if (await _repository.IsAnyAsync(x => x.Account == dto.Account))
throw new InvalidOperationException($"账号 {dto.Account} 已存在");
// 验证角色是否存在
if (dto.Roles != null && dto.Roles.Any())
{
var validRoleCount = await _roleRepository.AsQueryable()
.Where(x => dto.Roles.Contains(x.Id) && x.Status == AvailabilityStatus.Enable)
.CountAsync();
if (validRoleCount != dto.Roles.Count)
{
throw new InvalidOperationException("部分或全部角色不存在或已被禁用");
}
}
var user = dto.Adapt<SysUser>();
user.Id = _idGenerator.NextId();
string encode = _idGenerator.Encode(user.Id);
user.Password = MD5Encryption.Encrypt(encode + dto.Password);
// 权限管理-账号管理只创建报名平台后台账号
user.UnitPlatform = UnitAccountPlatform.EventSystem;
user.CreatedTime = DateTime.Now; // 确保设置创建时间
// 处理角色关联
var roles = new List<SysUserRole>();
if (dto.Roles != null && dto.Roles.Any())
{
roles = dto.Roles.Select(x => new SysUserRole()
{
RoleId = x,
UserId = user.Id
}).ToList();
}
await _repository.InsertAsync(user);
if (roles.Any())
{
await _userRoleRepository.InsertRangeAsync(roles);
}
}
/// <summary>
/// 更新系统用户信息
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("更新系统用户信息")]
[UnitOfWork, HttpPut("user")]
public async Task UpdateUser(UpdateSysUserInput dto)
{
var user = await GetEventSystemUserAsync(dto.Id);
// 规范化文本输入,避免首尾空格导致账号查重与登录不一致
dto.Account = dto.Account.Trim();
dto.Name = dto.Name.Trim();
// 校验账号是否重复(排除自己)
if (await _repository.IsAnyAsync(x => x.Account == dto.Account && x.Id != dto.Id))
throw new InvalidOperationException($"账号 {dto.Account} 已被使用");
// 验证角色是否存在
if (dto.Roles != null && dto.Roles.Any())
{
var validRoleCount = await _roleRepository.AsQueryable()
.Where(x => dto.Roles.Contains(x.Id) && x.Status == AvailabilityStatus.Enable)
.CountAsync();
if (validRoleCount != dto.Roles.Count)
{
throw new InvalidOperationException("部分或全部角色不存在或已被禁用");
}
}
// 先更新除密码外的其他字段
user.Name = dto.Name;
user.Account = dto.Account;
user.Status = dto.Status;
// 只有密码不为空时才更新密码
if (!string.IsNullOrWhiteSpace(dto.Password))
{
string encode = _idGenerator.Encode(user.Id);
user.Password = MD5Encryption.Encrypt(encode + dto.Password);
}
// 处理角色关联:先删后加
var roles = new List<SysUserRole>();
if (dto.Roles != null && dto.Roles.Any())
{
roles = dto.Roles.Select(x => new SysUserRole()
{
RoleId = x,
UserId = user.Id
}).ToList();
}
await _repository.UpdateAsync(user);
await _userRoleRepository.SoftDeleteAsync(x => x.UserId == user.Id);
if (roles.Any())
{
await _userRoleRepository.InsertRangeAsync(roles);
}
await _easyCachingProvider.RemoveByPrefixAsync(CacheConst.PermissionKey);
}
/// <summary>
/// 删除系统用户
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("删除系统用户")]
[HttpDelete]
public override async Task Delete(KeyDto dto)
{
await GetEventSystemUserAsync(dto.Id);
await base.Delete(dto);
await _easyCachingProvider.RemoveByPrefixAsync(CacheConst.PermissionKey);
}
[DisplayName("关联角色")]
[HttpPost("grantRole")]
public async Task GrantRole(GrantRoleInput input)
{
var user = await _repository.GetByIdAsync(input.UserId);
if (user == null) throw new InvalidOperationException("用户不存在");
var roles = input.RoleIds.Select(x => new SysUserRole()
{
RoleId = x,
UserId = input.UserId
}).ToList();
await _userRoleRepository.SoftDeleteAsync(x => x.UserId == input.UserId);
if (roles.Any())
{
await _userRoleRepository.InsertRangeAsync(roles);
}
await _easyCachingProvider.RemoveByPrefixAsync(CacheConst.PermissionKey);
}
/// <summary>
/// 系统用户详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[DisplayName("系统用户详情")]
[HttpGet("detail")]
public async Task<UpdateSysUserInput> Detail([FromQuery] long id)
{
await GetEventSystemUserAsync(id);
return await _repository.AsQueryable().Where(x => x.Id == id)
.Select(x => new UpdateSysUserInput()
{
Id = x.Id,
Name = x.Name,
Status = x.Status,
Account = x.Account,
Roles = SqlFunc.Subqueryable<SysUserRole>().Where(s => s.UserId == x.Id).ToList(s => s.RoleId)
}).FirstAsync();
}
/// <summary>
/// 重置系统用户密码
/// </summary>
/// <returns></returns>
[DisplayName("重置系统用户密码")]
[HttpPost("reset")]
public async Task Reset(SysUserResetPasswordInput dto)
{
await GetEventSystemUserAsync(dto.Id);
string encrypt = MD5Encryption.Encrypt(_idGenerator.Encode(dto.Id) + dto.Password);
await _repository.UpdateAsync(x => new SysUser()
{
Password = encrypt
}, x => x.Id == dto.Id);
}
/// <summary>
/// 修改报名平台后台账号状态。
/// </summary>
[DisplayName("修改报名平台账号状态")]
[HttpPost("setStatus")]
public override async Task SetStatus(AvailabilityDto dto)
{
await GetEventSystemUserAsync(dto.Id);
await base.SetStatus(dto);
await _easyCachingProvider.RemoveByPrefixAsync(CacheConst.PermissionKey);
}
/// <summary>
/// 校验目标账号为报名平台后台账号,拦截超级管理员及其他平台账号,防止跨平台误操作
/// </summary>
private async Task<SysUser> GetEventSystemUserAsync(long id)
{
if (id <= 1) throw Oops.Bah("超级管理员账号不允许在此操作");
var user = await _repository.GetByIdAsync(id);
if (user == null) throw Oops.Bah("报名平台账号不存在");
if (user.UnitPlatform != UnitAccountPlatform.EventSystem)
throw Oops.Bah("该账号不属于报名平台,请切换到对应平台管理");
return user;
}
/// <summary>
/// 获取当前登录用户的信息
/// </summary>
/// <returns></returns>
[DisplayName("获取登录用户的信息")]
[HttpGet("currentUserInfo")]
public async Task<SysUserInfoOutput> CurrentUserInfo()
{
var userId = _authManager.UserId;
return await _repository.AsQueryable().Where(x => x.Id == userId)
.Select(x => new SysUserInfoOutput
{
Name = x.Name,
Account = x.Account,
Avatar = x.Avatar,
Birthday = x.Birthday,
Email = x.Email,
Gender = x.Gender,
NickName = x.NickName,
Remark = x.Remark,
LastLoginIp = x.LastLoginIp,
LastLoginAddress = x.LastLoginAddress,
Mobile = x.Mobile,
OrgId = x.OrgId,
OrgName = SqlFunc.Subqueryable<SysOrganization>().Where(o => o.Id == x.OrgId).Select(o => o.Name)
})
.Mapper(dto =>
{
if (_authManager.IsSuperAdmin)
{
dto.AuthBtnList = _repository.AsSugarClient().Queryable<SysMenu>()
.Where(x => x.Type == MenuType.Button || x.Type == MenuType.DataScope)
.Select(x => x.Code)
.ToList()
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct()
.ToList();
}
else
{
var list = _sysMenuService.GetAuthButtonCodeList(userId).GetAwaiter().GetResult();
dto.AuthBtnList = list
.Where(x => x.Access && !string.IsNullOrWhiteSpace(x.Code))
.Select(x => x.Code)
.Distinct()
.ToList();
}
})
.FirstAsync();
}
/// <summary>
/// 用户修改账户密码
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[DisplayName("用户修改账户密码")]
[HttpPost("changePassword")]
public async Task ChangePassword(ChangePasswordOutput dto)
{
var userId = _authManager.UserId;
string encode = _idGenerator.Encode(userId);
string pwd = MD5Encryption.Encrypt($"{encode}{dto.OriginalPwd}");
if (!await _repository.IsAnyAsync(x => x.Id == userId && x.Password == pwd))
{
throw Oops.Bah("原密码错误");
}
pwd = MD5Encryption.Encrypt($"{encode}{dto.Password}");
await _repository.AsSugarClient().Updateable<SysUser>()
.SetColumns(x => new SysUser()
{
Password = pwd
}, appendColumnsByDataFilter: true)
.Where(x => x.Id == userId)
.ExecuteCommandHasChangeAsync();
}
/// <summary>
/// 用户修改头像
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
[DisplayName("用户修改头像")]
[HttpPost("uploadAvatar")]
public async Task UploadAvatar([FromBody] string url)
{
long userId = _authManager.UserId;
await _repository.UpdateAsync(x => new SysUser()
{
Avatar = url
}, x => x.Id == userId);
}
/// <summary>
/// 系统用户修改自己的信息
/// </summary>
/// <returns></returns>
[DisplayName("系统用户修改个人信息")]
[HttpPost("updateCurrentUser")]
public async Task UpdateCurrentUser(UpdateCurrentUserInput dto)
{
long userId = _authManager.UserId;
await _repository.UpdateAsync(x => new SysUser()
{
Name = dto.Name,
Birthday = dto.Birthday,
Email = dto.Email,
Gender = dto.Gender,
Mobile = dto.Mobile,
NickName = dto.NickName
}, x => x.Id == userId);
}
}