using Hotline.CallCenter.Tels; using Hotline.Identity.Accounts; using Hotline.Identity.Roles; using Hotline.Permissions; using Hotline.Repository.SqlSugar.Extensions; using Hotline.Users; using MapsterMapper; using Microsoft.AspNetCore.Mvc; using XF.Domain.Authentications; using XF.Domain.Exceptions; using XF.Utility.AppIdentityModel; using Hotline.Share.Dtos; using Hotline.Share.Dtos.Users; using Hotline.Share.Enums.Order; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using SqlSugar; using XF.Domain.Options; using XF.Utility.EnumExtensions; using Hotline.Caching.Interfaces; namespace Hotline.Api.Controllers; /// /// 用户管理相关接口 /// public class UserController : BaseController { private readonly ISessionContext _sessionContext; private readonly IUserDomainService _userDomainService; private readonly ITelRepository _telRepository; private readonly IUserRepository _userRepository; private readonly IWorkRepository _workRepository; private readonly ITelCacheManager _telCacheManager; private readonly IUserCacheManager _userCacheManager; private readonly IMapper _mapper; private readonly IAccountRepository _accountRepository; private readonly IAccountDomainService _accountDomainService; private readonly IOptions _identityConfigurationAccessor; private readonly ITelRestRepository _telRestRepository; public UserController( ISessionContext sessionContext, IUserDomainService userDomainService, ITelRepository telRepository, IUserRepository userRepository, IWorkRepository workRepository, ITelCacheManager telCacheManager, IUserCacheManager userCacheManager, IMapper mapper, IAccountRepository accountRepository, IAccountDomainService accountDomainService, IOptions identityConfigurationAccessor, ITelRestRepository telRestRepository) { _sessionContext = sessionContext; _userDomainService = userDomainService; _telRepository = telRepository; _userRepository = userRepository; _workRepository = workRepository; _telCacheManager = telCacheManager; _userCacheManager = userCacheManager; _mapper = mapper; _accountRepository = accountRepository; _accountDomainService = accountDomainService; _identityConfigurationAccessor = identityConfigurationAccessor; _telRestRepository = telRestRepository; } #region 小休申请 /// /// 小休申请列表 /// /// /// [HttpGet("rest-apply-paged")] public async Task> RestApplyList([FromQuery] RestPagedDto dto) { var (total, items) = await _telRestRepository.Queryable(includeDeleted: false) .WhereIF(!string.IsNullOrEmpty(dto.KeyWords), d => d.UserName.Contains(dto.KeyWords) || d.StaffNo.Contains(dto.KeyWords)) .WhereIF(dto.BeginTime != null && dto.BeginTime != DateTime.MinValue, d => d.CreationTime >= dto.BeginTime) .WhereIF(dto.EndTime != null && dto.EndTime != DateTime.MinValue, d => d.CreationTime <= dto.EndTime) .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } #endregion /// /// 上班 /// [Permission(EPermission.OnDuty)] [HttpPost("on-duty/{telNo}")] public async Task OnDuty([FromRoute] string? telNo) { if (string.IsNullOrEmpty(telNo)) { var user = await _userRepository.GetAsync(d => d.Id == _sessionContext.RequiredUserId, HttpContext.RequestAborted); if (user == null) throw UserFriendlyException.SameMessage("无效用户编号"); if (string.IsNullOrEmpty(user.DefaultTelNo)) throw UserFriendlyException.SameMessage("未设置默认分机号"); telNo = user.DefaultTelNo; } var tel = _telCacheManager.GetTel(telNo); await _userDomainService.OnDutyAsync(_sessionContext.RequiredUserId, tel, HttpContext.RequestAborted); } /// /// 下班 /// [Permission(EPermission.OffDuty)] [HttpPost("off-duty")] public Task OffDuty() { return _userDomainService.OffDutyAsync(_sessionContext.RequiredUserId, HttpContext.RequestAborted); } /// /// 分页查询用户 /// /// [Permission(EPermission.QueryPagedUser)] [HttpGet("paged")] public async Task> QueryPaged([FromQuery] UserPagedDto dto) { var (total, items) = await _userRepository.Queryable(includeDeleted: true) .Includes(d => d.Account) .Includes(d => d.Roles) .Includes(d => d.Organization) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Name.Contains(dto.Keyword!) || d.PhoneNo.Contains(dto.Keyword!)) .WhereIF(!string.IsNullOrEmpty(dto.OrgCode), d => d.OrgCode == dto.OrgCode) .WhereIF(!string.IsNullOrEmpty(dto.Role), d => d.Roles.Any(x => x.Id == dto.Role)) .OrderBy(d => d.Account.Status) .OrderBy(d => d.Organization.OrgType) .OrderBy(d => d.Organization.OrgCode) .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 更新用户 /// /// /// [Permission(EPermission.UpdateUser)] [HttpPut] public async Task Update([FromBody] UpdateUserDto dto) { var account = await _accountRepository.GetAsync(dto.Id, HttpContext.RequestAborted); CheckAccountStatus(account); var user = await _userRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (user is null) throw UserFriendlyException.SameMessage("无效用户编号"); if (user.IsDeleted) throw UserFriendlyException.SameMessage("账号不存在"); _mapper.Map(dto, user); await _userRepository.UpdateAsync(user, HttpContext.RequestAborted); //set roles await _accountRepository.SetAccountRolesAsync(account.Id, dto.RoleIds, HttpContext.RequestAborted); } /// /// 新增用户 /// /// /// [Permission(EPermission.AddUser)] [HttpPost] public async Task Add([FromBody] AddUserDto dto) { var account = await _accountRepository.GetAsync(d => d.UserName == dto.UserName, HttpContext.RequestAborted); if (account is null) { account = _mapper.Map(dto); var jwtOptions = _identityConfigurationAccessor.Value.Jwt; if (string.IsNullOrEmpty(jwtOptions.Issuer)) throw new UserFriendlyException("jwt.Issuer未配置"); account.ClientId = jwtOptions.Issuer; await _accountRepository.AddAsync(account, HttpContext.RequestAborted); var user = _mapper.Map(dto); user.Id = account.Id; await _userRepository.AddAsync(user, HttpContext.RequestAborted); //initial pwd await _accountDomainService.InitialPasswordAsync(account, HttpContext.RequestAborted); //set roles await _accountRepository.SetAccountRolesAsync(account.Id, dto.RoleIds, HttpContext.RequestAborted); return account.Id; } else { //if (_accountDomainService.IsLockedOut(account)) // throw UserFriendlyException.SameMessage("该账号已被锁定,请联系管理员"); ////set roles //await _accountRepository.SetAccountRolesAsync(account.Id, dto.RoleIds, HttpContext.RequestAborted); //var user = await _userRepository.GetAsync(account.Id, HttpContext.RequestAborted); //if (user is null) //{ // user = _mapper.Map(dto); // user.Id = account.Id; // return await _userRepository.AddAsync(user, HttpContext.RequestAborted); //} //if (user.IsDeleted) //{ // user.Recover(); // _mapper.Map(dto, user); // await _userRepository.UpdateAsync(user); // return user.Id; //} throw UserFriendlyException.SameMessage("用户已存在"); } } /// /// 删除用户 /// /// /// [Permission(EPermission.RemoveUser)] [HttpDelete("{id}")] public async Task Remove(string id) { var work = await _workRepository.GetCurrentWorkByUserAsync(id, HttpContext.RequestAborted); if (work is not null) throw UserFriendlyException.SameMessage("用户正在工作中,请下班以后再删除"); var account = await _accountRepository.GetAsync(id, HttpContext.RequestAborted); if (account is not null) { await _accountDomainService.UnRegisterAsync(account, HttpContext.RequestAborted); await _userRepository.RemoveAsync(id, true, HttpContext.RequestAborted); } } /// /// 查询用户当前状态 /// /// [HttpGet("state")] public async Task GetUserState() { var userId = _sessionContext.RequiredUserId; var isOnDuty = await _userCacheManager.IsWorkingByUserAsync(userId, HttpContext.RequestAborted); var isResting = false; var telNo = string.Empty; if (isOnDuty) { var work = _userCacheManager.GetWorkByUser(userId); isResting = await _telRepository.IsRestingAsync(work.TelNo, HttpContext.RequestAborted); telNo = work.TelNo; } return new UserStateDto(isOnDuty, isResting, telNo); } /// /// 查询用户角色 /// /// [Permission(EPermission.GetUserRoles)] [HttpGet("{id}/roles")] public async Task> GetUserRoles(string id) { var account = await _accountRepository.Queryable() .Includes(d => d.Roles) .FirstAsync(d => d.Id == id); if (account == null) throw UserFriendlyException.SameMessage("无效账号编号"); return account.Roles; } /// /// 设置用户角色 /// /// [Permission(EPermission.SetUserRoles)] [HttpPost("roles")] public async Task SetUserRoles([FromBody] SetUserRolesDto dto) { await _accountRepository.SetAccountRolesAsync(dto.UserId, dto.RoleIds, HttpContext.RequestAborted); } /// /// 查询密码更改状态 /// /// /// [HttpGet("pwd-changed")] public Task GetPasswordChangeStatus() { var claim = User.Claims.FirstOrDefault(d => d.Type == AppClaimTypes.UserPasswordChanged); if (claim is null) throw UserFriendlyException.SameMessage("无密码更改信息"); return Task.FromResult(Convert.ToBoolean(claim.Value)); } /// /// 修改密码 /// /// /// [HttpPost("change-pwd")] public async Task ChangePassword([FromBody] ChangePasswordDto dto) { var account = await _accountRepository.GetAsync(_sessionContext.RequiredUserId, HttpContext.RequestAborted); CheckAccountStatus(account); var result = await _accountDomainService.ResetPasswordAsync(account, dto.CurrentPassword, dto.NewPassword, HttpContext.RequestAborted); if (!result.Succeeded) throw UserFriendlyException.SameMessage(string.Join(',', result.Errors.Select(d => d.Description).ToList())); account.PasswordChanged = true; await _accountRepository.UpdateAsync(account, HttpContext.RequestAborted); } /// /// 修改默认密码 /// /// /// [HttpPost("change-default-pwd")] public async Task ChangeDefaultPassword([FromBody] NewPasswordDto dto) { var account = await _accountRepository.GetAsync(_sessionContext.RequiredUserId, HttpContext.RequestAborted); CheckAccountStatus(account); var accountOptions = _identityConfigurationAccessor.Value.Account; var result = await _accountDomainService.ResetPasswordAsync(account, accountOptions.DefaultPassword, dto.NewPassword, HttpContext.RequestAborted); if (!result.Succeeded) throw UserFriendlyException.SameMessage(string.Join(',', result.Errors.Select(d => d.Description).ToList())); account.PasswordChanged = true; await _accountRepository.UpdateAsync(account, HttpContext.RequestAborted); } /// /// 重置密码 /// /// [HttpPost("initial-pwd/{userId}")] public async Task InitialPassword(string userId) { var account = await _accountRepository.GetAsync(userId, HttpContext.RequestAborted); CheckAccountStatus(account); await _accountDomainService.InitialPasswordAsync(account, HttpContext.RequestAborted); } /// /// 根据id批量查询用户 /// /// /// [HttpGet] public async Task> Query([FromQuery] IReadOnlyList ids) { var users = await _userRepository.Queryable() .Includes(d => d.Account, x => x.Roles) .Includes(d => d.Organization) .Where(d => ids.Contains(d.Id)) .OrderByDescending(d => d.CreationTime) .ToListAsync(); return _mapper.Map>(users); } /// /// 根据姓名模糊查询用户 /// /// /// [HttpGet("withorg")] public async Task> Query([FromQuery] string name) { var users = await _userRepository.Queryable() .Includes(d => d.Organization) .Where(d => d.Name.Contains(name)) .OrderByDescending(d => d.Name) .ToListAsync(); return _mapper.Map>(users); } [HttpGet("base-data")] public object BaseData() { return new { GenderOptions = EnumExts.GetDescriptions() }; } private void CheckAccountStatus(Account? account) { if (account == null) throw UserFriendlyException.SameMessage("无效账号编号"); if (_accountDomainService.IsLockedOut(account)) throw UserFriendlyException.SameMessage("账号已被锁定"); if (account.IsDeleted) throw UserFriendlyException.SameMessage("账号不存在"); } }