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("账号不存在");
}
}