UserController.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. using Hotline.Application.Contracts.Configurations;
  2. using Hotline.Caches;
  3. using Hotline.CallCenter.Tels;
  4. using Hotline.Permissions;
  5. using Hotline.Share.Dtos.CallCenter;
  6. using Hotline.Share.Dtos.User;
  7. using Hotline.Users;
  8. using Identity.Admin.HttpClient;
  9. using Identity.Shared.Dtos;
  10. using Identity.Shared.Dtos.Account;
  11. using Identity.Shared.Dtos.Identity;
  12. using Identity.Shared.Dtos.Role;
  13. using MapsterMapper;
  14. using Microsoft.AspNetCore.Mvc;
  15. using XF.Domain.Authentications;
  16. using XF.Domain.Exceptions;
  17. using Microsoft.Extensions.Options;
  18. using XF.Utility.AppIdentityModel;
  19. using XF.Utility.UnifyResponse;
  20. namespace Hotline.Api.Controllers;
  21. /// <summary>
  22. /// 用户管理相关接口
  23. /// </summary>
  24. public class UserController : BaseController
  25. {
  26. private readonly ISessionContext _sessionContext;
  27. private readonly IUserDomainService _userDomainService;
  28. private readonly ITelRepository _telRepository;
  29. private readonly IUserRepository _userRepository;
  30. private readonly ITelCacheManager _telCacheManager;
  31. private readonly IUserCacheManager _userCacheManager;
  32. private readonly IIdentityClient _identityClient;
  33. private readonly IOptionsSnapshot<IdentityConfigs> _identityConfigs;
  34. private readonly IMapper _mapper;
  35. public UserController(
  36. ISessionContext sessionContext,
  37. IUserDomainService userDomainService,
  38. ITelRepository telRepository,
  39. IUserRepository userRepository,
  40. ITelCacheManager telCacheManager,
  41. IUserCacheManager userCacheManager,
  42. IIdentityClient identityClient,
  43. IOptionsSnapshot<IdentityConfigs> identityConfigs,
  44. IMapper mapper)
  45. {
  46. _sessionContext = sessionContext;
  47. _userDomainService = userDomainService;
  48. _telRepository = telRepository;
  49. _userRepository = userRepository;
  50. _telCacheManager = telCacheManager;
  51. _userCacheManager = userCacheManager;
  52. _identityClient = identityClient;
  53. _identityConfigs = identityConfigs;
  54. _mapper = mapper;
  55. }
  56. /// <summary>
  57. /// 上班
  58. /// </summary>
  59. [Permission(EPermission.OnDuty)]
  60. [HttpPost("on-duty/{telNo}")]
  61. public async Task OnDuty([FromRoute] string? telNo)
  62. {
  63. if (string.IsNullOrEmpty(telNo))
  64. {
  65. var user = await _userRepository.GetAsync(d => !d.IsDeleted && d.Id == _sessionContext.RequiredUserId,
  66. HttpContext.RequestAborted);
  67. if (user == null)
  68. throw UserFriendlyException.SameMessage("无效用户编号");
  69. if (string.IsNullOrEmpty(user.DefaultTelNo))
  70. throw UserFriendlyException.SameMessage("未设置默认分机号");
  71. telNo = user.DefaultTelNo;
  72. }
  73. var tel = _telCacheManager.GetTel(telNo);
  74. await _userDomainService.OnDutyAsync(_sessionContext.RequiredUserId, tel, HttpContext.RequestAborted);
  75. }
  76. /// <summary>
  77. /// 下班
  78. /// </summary>
  79. [Permission(EPermission.OffDuty)]
  80. [HttpPost("off-duty")]
  81. public Task<WorkDto?> OffDuty()
  82. {
  83. return _userDomainService.OffDutyAsync(_sessionContext.RequiredUserId, HttpContext.RequestAborted);
  84. }
  85. /// <summary>
  86. /// 分页查询用户
  87. /// </summary>
  88. /// <returns></returns>
  89. [Permission(EPermission.QueryPagedUser)]
  90. [HttpGet("paged")]
  91. public async Task<PagedDto<UserDto>> QueryPaged([FromQuery] UserPagedDto dto)
  92. {
  93. var (total, items) = await _userRepository.QueryPagedAsync(
  94. d => !d.IsDeleted,
  95. d => d.OrderByDescending(x => x.CreationTime),
  96. dto.PageIndex,
  97. dto.PageSize,
  98. (!string.IsNullOrEmpty(dto.PhoneNo), d => d.PhoneNo.Contains(dto.PhoneNo!)),
  99. (!string.IsNullOrEmpty(dto.DisplayName), d => !string.IsNullOrEmpty(d.Name) && d.Name.Contains(dto.DisplayName!)));
  100. return new PagedDto<UserDto>(total, _mapper.Map<IReadOnlyList<UserDto>>(items));
  101. }
  102. /// <summary>
  103. /// 更新用户
  104. /// </summary>
  105. /// <param name="userDto"></param>
  106. /// <returns></returns>
  107. [Permission(EPermission.UpdateUser)]
  108. [HttpPut]
  109. public async Task Update([FromBody] UpdateUserDto userDto)
  110. {
  111. var user = await _userRepository.GetAsync(userDto.Id, HttpContext.RequestAborted);
  112. if (user is null || user.IsDeleted)
  113. throw UserFriendlyException.SameMessage("无效用户编号");
  114. if (await IsAccountLock(user.Id))
  115. throw UserFriendlyException.SameMessage("该账号已被锁定");
  116. _mapper.Map(userDto, user);
  117. await _userRepository.UpdateAsync(user, HttpContext.RequestAborted);
  118. }
  119. /// <summary>
  120. /// 新增用户
  121. /// </summary>
  122. /// <param name="userDto"></param>
  123. /// <returns></returns>
  124. [Permission(EPermission.AddUser)]
  125. [HttpPost]
  126. public async Task<string> Add([FromBody] AddUserDto userDto)
  127. {
  128. var getAccountRsp = await _identityClient.GetUserAsync(userDto.UserName, HttpContext.RequestAborted);
  129. CheckHttpRequestSuccess(getAccountRsp, "GetUserAsync");
  130. var account = getAccountRsp.Result;
  131. if (account is null)
  132. {
  133. var identityConfigs = _identityConfigs.Value;
  134. var addAccountRsp = await _identityClient.AddUserAsync(new IdentityUserDto
  135. {
  136. ClientId = identityConfigs.ClientId,
  137. UserName = userDto.UserName,
  138. Email = $"{userDto.UserName}@fw.com",
  139. DislayName = userDto.Name ?? userDto.UserName
  140. }, HttpContext.RequestAborted);
  141. if (addAccountRsp is null || !addAccountRsp.IsSuccess)
  142. throw new UserFriendlyException("identity service insert fail: AddUserAsync", "新增用户失败!");
  143. var user = _mapper.Map<User>(userDto);
  144. user.Id = addAccountRsp.Result;
  145. return await _userRepository.AddAsync(user, HttpContext.RequestAborted);
  146. }
  147. else
  148. {
  149. if (await IsAccountLock(account.Id))
  150. throw UserFriendlyException.SameMessage("该账号已被锁定,请联系管理员");
  151. var user = await _userRepository.GetAsync(account.Id, HttpContext.RequestAborted);
  152. if (user is null)
  153. {
  154. user = _mapper.Map<User>(userDto);
  155. user.Id = account.Id;
  156. return await _userRepository.AddAsync(user, HttpContext.RequestAborted);
  157. }
  158. if (user.IsDeleted)
  159. {
  160. user.Recover();
  161. await _userRepository.UpdateAsync(user);
  162. return user.Id;
  163. }
  164. throw UserFriendlyException.SameMessage("该用户已存在");
  165. }
  166. }
  167. /// <summary>
  168. /// 删除用户
  169. /// </summary>
  170. /// <param name="id"></param>
  171. /// <returns></returns>
  172. [Permission(EPermission.RemoveUser)]
  173. [HttpDelete("{id}")]
  174. public async Task Remove(string id)
  175. {
  176. var work = _userCacheManager.GetWorkByUser(id);
  177. if (work is not null)
  178. throw UserFriendlyException.SameMessage("该用户正在工作中,请下班以后再删除");
  179. var response = await _identityClient.LockUserAsync(new UserLockDto(id), HttpContext.RequestAborted);
  180. CheckHttpRequestSuccess(response, "LockUserAsync");
  181. await _userRepository.RemoveAsync(id, true, HttpContext.RequestAborted);
  182. }
  183. /// <summary>
  184. /// 查询用户当前状态
  185. /// </summary>
  186. /// <returns></returns>
  187. //[AllowAnonymous]
  188. [HttpGet("state")]
  189. public async Task<UserStateDto> GetUserState()
  190. {
  191. var userId = _sessionContext.RequiredUserId;
  192. var isOnDuty = await _userCacheManager.IsWorkingByUserAsync(userId, HttpContext.RequestAborted);
  193. var isResting = false;
  194. var telNo = string.Empty;
  195. if (isOnDuty)
  196. {
  197. var work = _userCacheManager.GetWorkByUser(userId);
  198. isResting = await _telRepository.IsRestingAsync(work.TelNo, HttpContext.RequestAborted);
  199. telNo = work.TelNo;
  200. }
  201. return new UserStateDto(isOnDuty, isResting, telNo);
  202. }
  203. /// <summary>
  204. /// 分页查询用户角色
  205. /// </summary>
  206. /// <returns></returns>
  207. [Permission(EPermission.GetUserRoles)]
  208. [HttpGet("roles")]
  209. public async Task<PagedDto<IdentityRoleDto>> GetUserRoles([FromQuery] UserRolesPagedDto dto)
  210. {
  211. var pageDto = _mapper.Map<PageDto>(dto);
  212. var getUserRolesRsp = await _identityClient.GetUserRolesAsync(dto.UserId, pageDto, HttpContext.RequestAborted);
  213. CheckHttpRequestSuccess(getUserRolesRsp, "GetUserRolesAsync");
  214. var result = getUserRolesRsp.Result;
  215. return new PagedDto<IdentityRoleDto>(result.TotalCount, result.Roles);
  216. }
  217. /// <summary>
  218. /// 设置用户角色
  219. /// </summary>
  220. /// <returns></returns>
  221. [Permission(EPermission.SetUserRoles)]
  222. [HttpPost("roles")]
  223. public async Task SetUserRoles([FromBody] SetUserRolesDto dto)
  224. {
  225. var setUserRolesRsp = await _identityClient.SetUserRolesAsync(dto, HttpContext.RequestAborted);
  226. CheckHttpRequestSuccess(setUserRolesRsp, "SetUserRolesAsync");
  227. }
  228. /// <summary>
  229. /// 查询密码更改状态
  230. /// </summary>
  231. /// <returns></returns>
  232. /// <exception cref="UserFriendlyException"></exception>
  233. [Permission(EPermission.GetPasswordChangeStatus)]
  234. [HttpGet("pwd-changed")]
  235. public Task<bool> GetPasswordChangeStatus()
  236. {
  237. var claim = User.Claims.FirstOrDefault(d => d.Type == AppClaimTypes.UserPasswordChanged);
  238. if (claim is null)
  239. throw UserFriendlyException.SameMessage("无密码更改信息");
  240. return Task.FromResult(Convert.ToBoolean(claim.Value));
  241. }
  242. /// <summary>
  243. /// 修改密码
  244. /// </summary>
  245. /// <param name="dto"></param>
  246. /// <returns></returns>
  247. [HttpPost("change-pwd")]
  248. public async Task ChangePassword([FromBody] ChangePasswordDto dto)
  249. {
  250. var changepwdDto = _mapper.Map<UserChangePasswordDto>(dto);
  251. changepwdDto.UserId = _sessionContext.RequiredUserId;
  252. var changepwdRsp = await _identityClient.ChangePasswordAsync(changepwdDto, HttpContext.RequestAborted);
  253. CheckHttpRequestSuccess(changepwdRsp, "ChangePasswordAsync");
  254. }
  255. /// <summary>
  256. /// 重置密码
  257. /// </summary>
  258. /// <returns></returns>
  259. [HttpPost("initial-pwd/{userId}")]
  260. public async Task InitialPassword(string userId)
  261. {
  262. var initpwdRsp = await _identityClient.InitialPasswordAsync(userId, HttpContext.RequestAborted);
  263. CheckHttpRequestSuccess(initpwdRsp, "InitialPasswordAsync");
  264. }
  265. #region private
  266. private async Task<bool> IsAccountLock(string userId)
  267. {
  268. var response = await _identityClient.IsAccountLockAsync(userId, HttpContext.RequestAborted);
  269. if (response is null || !response.IsSuccess)
  270. throw new UserFriendlyException("identity service request fail: IsAccountLockAsync");
  271. return response.Result;
  272. }
  273. private void CheckHttpRequestSuccess(ApiResponse response, string msg)
  274. {
  275. if (response == null || !response.IsSuccess)
  276. throw new UserFriendlyException($"identity service request failed: {msg}");
  277. }
  278. #endregion
  279. }