All checks were successful
Build and Deploy / deploy (push) Successful in 1m41s
272 lines
9.3 KiB
C#
272 lines
9.3 KiB
C#
using Fake.Application;
|
|
using Fake.Domain.Exceptions;
|
|
using Fake.Rbac.Application.Dtos.Common;
|
|
using Fake.Rbac.Application.Dtos.Role;
|
|
using Fake.Rbac.Application.Dtos.User;
|
|
using Fake.Rbac.Application.Services;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Oms.Application.Dtos.Rbac;
|
|
using Oms.Application.Rbac;
|
|
using Oms.Application.Storage;
|
|
using Oms.Domain.SystemAggregate.Entities;
|
|
using Oms.Domain.SystemAggregate.Enums;
|
|
using Oms.Domain.SystemAggregate.Repositories;
|
|
|
|
namespace Oms.Application.Services.Rbac;
|
|
|
|
/// <summary>
|
|
/// 接管 RBAC 用户接口,扩展电话、工号、微信号、微信二维码字段。
|
|
/// </summary>
|
|
[Authorize]
|
|
[ApiExplorerSettings(GroupName = "RBAC-User")]
|
|
public class OmsUserService(
|
|
UserService userService,
|
|
UserProfileRepository profileRepository,
|
|
IEmployeeRepository employeeRepository,
|
|
IFileStorage fileStorage) : ApplicationService
|
|
{
|
|
/// <summary>
|
|
/// 获取用户详情(含扩展资料)。
|
|
/// </summary>
|
|
[HttpGet("/rbac/user/get")]
|
|
public async Task<OmsUserDetailDto> GetAsync([FromQuery] Guid id, CancellationToken cancellationToken = default)
|
|
{
|
|
var user = await userService.GetAsync(id, cancellationToken);
|
|
var profile = await profileRepository.GetAsync(id, cancellationToken);
|
|
return MapUserDetail(user, profile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 分页查询用户列表(含扩展资料)。
|
|
/// </summary>
|
|
[HttpGet("/rbac/user/get-list")]
|
|
public async Task<PagedResultDto<OmsUserDetailDto>> GetListAsync(
|
|
[FromQuery] UserPagedRequestDto input,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var result = await userService.GetListAsync(input, cancellationToken);
|
|
if (result.Items.Count == 0)
|
|
{
|
|
return new PagedResultDto<OmsUserDetailDto>
|
|
{
|
|
Total = result.Total,
|
|
Items = [],
|
|
};
|
|
}
|
|
|
|
var userIds = result.Items
|
|
.Select(x => x.Id)
|
|
.Where(x => x != Guid.Empty)
|
|
.Distinct()
|
|
.ToList();
|
|
var profileMap = await profileRepository.GetManyAsync(userIds, cancellationToken);
|
|
return new PagedResultDto<OmsUserDetailDto>
|
|
{
|
|
Total = result.Total,
|
|
Items = result.Items
|
|
.Select(user =>
|
|
{
|
|
profileMap.TryGetValue(user.Id, out var profile);
|
|
return MapUserDetail(user, profile);
|
|
})
|
|
.ToList(),
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按角色查询用户简要列表。
|
|
/// </summary>
|
|
[HttpGet("/rbac/user/get-users-by-role")]
|
|
public Task<List<UserSimpleDto>> GetUsersByRoleAsync(
|
|
[FromQuery] Guid roleId,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.GetUsersByRoleAsync(roleId, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 创建用户并保存扩展资料。
|
|
/// </summary>
|
|
[HttpPost("/rbac/user/create")]
|
|
public async Task<OmsUserDetailDto> CreateAsync(
|
|
[FromBody] OmsUserCreateInput input,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var employeeNo = await ResolveEmployeeNoForCreateAsync(input.EmployeeNo, cancellationToken);
|
|
var user = await userService.CreateAsync(new UserCreateDto
|
|
{
|
|
Name = input.Name,
|
|
Account = input.Account,
|
|
Password = input.Password,
|
|
Email = input.Email,
|
|
Avatar = fileStorage.ToStorageKey(input.Avatar),
|
|
OrganizationId = input.OrganizationId,
|
|
RoleIds = input.RoleIds,
|
|
}, cancellationToken);
|
|
|
|
await profileRepository.SaveAsync(
|
|
user.Id,
|
|
new UserProfileData
|
|
{
|
|
Phone = input.Phone,
|
|
EmployeeNo = employeeNo,
|
|
WechatId = input.WechatId,
|
|
WechatQrCode = input.WechatQrCode,
|
|
WecomKfUrl = input.WecomKfUrl,
|
|
},
|
|
cancellationToken);
|
|
|
|
await EnsureEmployeeProfileAsync(user.Id, input, cancellationToken);
|
|
|
|
var profile = await profileRepository.GetAsync(user.Id, cancellationToken);
|
|
return MapUserDetail(user, profile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新用户及扩展资料。
|
|
/// </summary>
|
|
[HttpPut("/rbac/user/update")]
|
|
public async Task<OmsUserDetailDto> UpdateAsync(
|
|
[FromQuery] Guid id,
|
|
[FromBody] OmsUserUpdateInput input,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var user = await userService.UpdateAsync(
|
|
id,
|
|
new UserUpdateDto
|
|
{
|
|
Name = input.Name,
|
|
Email = input.Email,
|
|
Avatar = fileStorage.ToStorageKey(input.Avatar),
|
|
OrganizationId = input.OrganizationId,
|
|
},
|
|
cancellationToken);
|
|
|
|
await profileRepository.UpdateContactAsync(
|
|
id,
|
|
new UserProfileData
|
|
{
|
|
Phone = input.Phone,
|
|
WechatId = input.WechatId,
|
|
WechatQrCode = input.WechatQrCode,
|
|
WecomKfUrl = input.WecomKfUrl,
|
|
},
|
|
cancellationToken);
|
|
|
|
var profile = await profileRepository.GetAsync(id, cancellationToken);
|
|
return MapUserDetail(user, profile);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 修改用户密码。
|
|
/// </summary>
|
|
[HttpPut("/rbac/user/update-password")]
|
|
public Task UpdatePasswordAsync(
|
|
[FromQuery] Guid id,
|
|
[FromBody] UpdatePasswordDto input,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.UpdatePasswordAsync(id, input, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 更新用户头像。
|
|
/// </summary>
|
|
[HttpPut("/rbac/user/update-avatar")]
|
|
public Task UpdateAvatarAsync(
|
|
[FromQuery] Guid id,
|
|
[FromQuery] string avatarUrl,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.UpdateAvatarAsync(id, fileStorage.ToStorageKey(avatarUrl) ?? avatarUrl, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 删除用户。
|
|
/// </summary>
|
|
[HttpDelete("/rbac/user/delete")]
|
|
public Task DeleteAsync([FromQuery] Guid id, CancellationToken cancellationToken = default) =>
|
|
userService.DeleteAsync(id, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 批量删除用户。
|
|
/// </summary>
|
|
[HttpDelete("/rbac/user/delete-batch")]
|
|
public Task DeleteBatchAsync([FromQuery] List<Guid> ids, CancellationToken cancellationToken = default) =>
|
|
userService.DeleteBatchAsync(ids, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 为用户分配角色。
|
|
/// </summary>
|
|
[HttpPost("/rbac/user/assign-roles")]
|
|
public Task AssignRolesAsync(
|
|
[FromQuery] Guid userId,
|
|
[FromBody] List<Guid> roleIds,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.AssignRolesAsync(userId, roleIds, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 获取用户已分配角色。
|
|
/// </summary>
|
|
[HttpGet("/rbac/user/get-user-roles")]
|
|
public Task<List<RoleDto>> GetUserRolesAsync(
|
|
[FromQuery] Guid userId,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.GetUserRolesAsync(userId, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 获取用户权限码列表。
|
|
/// </summary>
|
|
[HttpGet("/rbac/user/get-user-permissions")]
|
|
public Task<List<string>> GetUserPermissionsAsync(
|
|
[FromQuery] Guid userId,
|
|
CancellationToken cancellationToken = default) =>
|
|
userService.GetUserPermissionsAsync(userId, cancellationToken);
|
|
|
|
private async Task<string> ResolveEmployeeNoForCreateAsync(
|
|
string? requestedEmployeeNo,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var employeeNo = string.IsNullOrWhiteSpace(requestedEmployeeNo)
|
|
? await profileRepository.GenerateNextEmployeeNoAsync(cancellationToken)
|
|
: requestedEmployeeNo.Trim().ToUpperInvariant();
|
|
|
|
if (!UserProfileRepository.IsValidEmployeeNo(employeeNo))
|
|
{
|
|
throw new BusinessException("工号格式无效,应为 IDE + 至少 3 位数字,如 IDE001");
|
|
}
|
|
|
|
if (await profileRepository.IsEmployeeNoTakenAsync(employeeNo, null, cancellationToken))
|
|
{
|
|
throw new BusinessException($"工号已存在:{employeeNo}");
|
|
}
|
|
|
|
return employeeNo;
|
|
}
|
|
|
|
private async Task EnsureEmployeeProfileAsync(
|
|
Guid userId,
|
|
OmsUserCreateInput input,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var userIdText = userId.ToString();
|
|
if (await employeeRepository.ExistsByUserIdAsync(userIdText, null, cancellationToken))
|
|
{
|
|
return;
|
|
}
|
|
|
|
await employeeRepository.InsertAsync(
|
|
new Employee
|
|
{
|
|
UserId = userIdText,
|
|
RealName = string.IsNullOrWhiteSpace(input.Name) ? string.Empty : input.Name.Trim(),
|
|
HireDate = DateTime.Today,
|
|
EmploymentStatus = EmploymentStatus.Probation,
|
|
EmploymentType = EmploymentType.FullTime,
|
|
},
|
|
cancellationToken);
|
|
}
|
|
|
|
private OmsUserDetailDto MapUserDetail(UserDto user, UserProfileData? profile)
|
|
{
|
|
var detail = OmsUserProfileMapper.ToDetailDto(user, profile);
|
|
detail.Avatar = fileStorage.GetPublicUrl(detail.Avatar);
|
|
return detail;
|
|
}
|
|
}
|