feat: resolve createBy/updateBy to RBAC user display names
Add OmsRbacUserDisplayNameResolver and use it in customer, order, warehouse, and channel APIs so audit fields return names instead of mapIds. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e875f0c012
commit
07fc7fffe7
@ -102,8 +102,18 @@ public class CustomerPaginatedOutput
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建人(展示名称)。
|
||||
/// </summary>
|
||||
public string? CreateBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间。
|
||||
/// </summary>
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新人(展示名称)。
|
||||
/// </summary>
|
||||
public string? UpdateBy { get; set; }
|
||||
}
|
||||
|
||||
@ -74,6 +74,9 @@ public partial class SalesProductService
|
||||
.GroupBy(x => x.PriceId)
|
||||
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList());
|
||||
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
prices.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
||||
|
||||
return prices.Select(price => new SalesProductPriceListOutput
|
||||
{
|
||||
Id = price.Id,
|
||||
@ -88,9 +91,9 @@ public partial class SalesProductService
|
||||
Factors = factorMap.TryGetValue(price.Id, out var factors) ? factors.Select(MapPriceFactorOutput).ToList() : [],
|
||||
Details = detailMap.TryGetValue(price.Id, out var details) ? details.Select(MapPriceDetailOutput).ToList() : [],
|
||||
CreateTime = price.CreateTime,
|
||||
CreateBy = price.CreateUserId <= 0 ? null : price.CreateUserId.ToString(),
|
||||
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.CreateUserId, auditUserNameMap),
|
||||
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime),
|
||||
UpdateBy = price.UpdateUserId <= 0 ? null : price.UpdateUserId.ToString()
|
||||
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.UpdateUserId, auditUserNameMap)
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
@ -342,7 +345,9 @@ public partial class SalesProductService
|
||||
};
|
||||
}
|
||||
|
||||
private static SalesProductDetailOutput MapDetailOutput(SalesProduct entity)
|
||||
private static SalesProductDetailOutput MapDetailOutput(
|
||||
SalesProduct entity,
|
||||
IReadOnlyDictionary<int, string> auditUserNameMap)
|
||||
{
|
||||
return new SalesProductDetailOutput
|
||||
{
|
||||
@ -363,9 +368,9 @@ public partial class SalesProductService
|
||||
IsActive = (byte)entity.IsActive,
|
||||
Scheme = entity.Scheme,
|
||||
CreateTime = entity.CreateTime,
|
||||
CreateBy = entity.CreateUserId <= 0 ? null : entity.CreateUserId.ToString(),
|
||||
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap),
|
||||
UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime),
|
||||
UpdateBy = entity.UpdateUserId <= 0 ? null : entity.UpdateUserId.ToString()
|
||||
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -25,6 +25,8 @@ public partial class SalesProductService : ApplicationService
|
||||
private IWeightRoundingRepository WeightRoundingRepository => LazyServiceProvider.GetRequiredService<IWeightRoundingRepository>();
|
||||
private AllocationProviderSnapshotEnricher AllocationProviderSnapshotEnricher =>
|
||||
LazyServiceProvider.GetRequiredService<AllocationProviderSnapshotEnricher>();
|
||||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询销售产品列表。
|
||||
@ -71,7 +73,9 @@ public partial class SalesProductService : ApplicationService
|
||||
public async Task<SalesProductDetailOutput> GetDetailAsync([FromQuery] int id)
|
||||
{
|
||||
var entity = await GetProductOrThrowAsync(id);
|
||||
return MapDetailOutput(entity);
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
[entity.CreateUserId, entity.UpdateUserId]);
|
||||
return MapDetailOutput(entity, auditUserNameMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -329,7 +329,10 @@ public partial class ServiceChannelService
|
||||
};
|
||||
}
|
||||
|
||||
private static ServiceChannelDetailOutput MapDetailOutput(ServiceChannel entity, IReadOnlyDictionary<int, string> groupMap)
|
||||
private static ServiceChannelDetailOutput MapDetailOutput(
|
||||
ServiceChannel entity,
|
||||
IReadOnlyDictionary<int, string> groupMap,
|
||||
IReadOnlyDictionary<int, string> auditUserNameMap)
|
||||
{
|
||||
return new ServiceChannelDetailOutput
|
||||
{
|
||||
@ -346,9 +349,9 @@ public partial class ServiceChannelService
|
||||
PreScript = entity.PreScript,
|
||||
IsActive = (byte)entity.IsActive,
|
||||
CreateTime = entity.CreateTime,
|
||||
CreateBy = entity.CreateUserId <= 0 ? null : entity.CreateUserId.ToString(),
|
||||
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap),
|
||||
UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime),
|
||||
UpdateBy = entity.UpdateUserId <= 0 ? null : entity.UpdateUserId.ToString()
|
||||
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,8 @@ public partial class ServiceChannelService : ApplicationService
|
||||
|
||||
private IServiceChannelRepository ServiceChannelRepository => LazyServiceProvider.GetRequiredService<IServiceChannelRepository>();
|
||||
private IServiceChannelGroupRepository ServiceChannelGroupRepository => LazyServiceProvider.GetRequiredService<IServiceChannelGroupRepository>();
|
||||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询服务渠道列表。
|
||||
@ -67,7 +69,9 @@ public partial class ServiceChannelService : ApplicationService
|
||||
public async Task<ServiceChannelDetailOutput> GetDetailAsync([FromQuery] int id)
|
||||
{
|
||||
var entity = await GetEntityOrThrowAsync(id);
|
||||
return MapDetailOutput(entity, await GetGroupMapAsync());
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
[entity.CreateUserId, entity.UpdateUserId]);
|
||||
return MapDetailOutput(entity, await GetGroupMapAsync(), auditUserNameMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -32,6 +32,9 @@ public class CustomerService : ApplicationService
|
||||
|
||||
private FakeRbacDbContext RbacDbContext => LazyServiceProvider.GetRequiredService<FakeRbacDbContext>();
|
||||
|
||||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询客户列表。
|
||||
/// </summary>
|
||||
@ -57,7 +60,16 @@ public class CustomerService : ApplicationService
|
||||
new Dictionary<string, bool> { [nameof(Customer.UpdateTime)] = false, [nameof(Customer.Id)] = false });
|
||||
|
||||
var totalCount = await CustomerRepository.CountAsync(predicate);
|
||||
var items = entities.Select(entity => ObjectMapper.Map<Customer, CustomerPaginatedOutput>(entity)).ToList();
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
entities.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
||||
var items = entities.Select(entity =>
|
||||
{
|
||||
var output = ObjectMapper.Map<Customer, CustomerPaginatedOutput>(entity);
|
||||
output.CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap);
|
||||
output.UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap);
|
||||
output.UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime);
|
||||
return output;
|
||||
}).ToList();
|
||||
|
||||
return new OmsPageResult<CustomerPaginatedOutput>
|
||||
{
|
||||
@ -82,8 +94,10 @@ public class CustomerService : ApplicationService
|
||||
{
|
||||
var entity = await GetCustomerOrThrowAsync(id);
|
||||
var output = ObjectMapper.Map<Customer, CustomerOutput>(entity);
|
||||
output.CreateBy = entity.CreateUserId <= 0 ? null : entity.CreateUserId.ToString();
|
||||
output.UpdateBy = entity.UpdateUserId <= 0 ? null : entity.UpdateUserId.ToString();
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
[entity.CreateUserId, entity.UpdateUserId]);
|
||||
output.CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap);
|
||||
output.UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap);
|
||||
output.UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime);
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ public partial class OrderService
|
||||
: await CountryRepository.GetListAsync(x => countryCodes.Contains(x.CountryCode));
|
||||
var countryMap = countries.ToDictionary(x => x.CountryCode, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
orders.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
||||
|
||||
return orders.Select(order =>
|
||||
{
|
||||
senderMap.TryGetValue(order.Id, out var sender);
|
||||
@ -127,9 +130,9 @@ public partial class OrderService
|
||||
IsIntercept = order.IsIntercept > 0,
|
||||
IsRemote = order.IsRemote > 0,
|
||||
CreateTime = order.CreateTime,
|
||||
CreateBy = order.CreateUserId <= 0 ? null : order.CreateUserId.ToString(),
|
||||
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.CreateUserId, auditUserNameMap),
|
||||
UpdateTime = OmsDocHelper.NullIfDefault(order.UpdateTime),
|
||||
UpdateBy = order.UpdateUserId <= 0 ? null : order.UpdateUserId.ToString(),
|
||||
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.UpdateUserId, auditUserNameMap),
|
||||
Sender = MapSender(sender),
|
||||
Receiver = MapReceiver(recipient),
|
||||
Items = (items ?? []).Select(MapDeclaration).ToList(),
|
||||
|
||||
@ -28,6 +28,8 @@ public partial class OrderService : ApplicationService
|
||||
private IWarehouseAddressRepository WarehouseAddressRepository => LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
|
||||
private ISalesProductRepository SalesProductRepository => LazyServiceProvider.GetRequiredService<ISalesProductRepository>();
|
||||
private IWebHostEnvironment WebHostEnvironment => LazyServiceProvider.GetRequiredService<IWebHostEnvironment>();
|
||||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询订单列表。
|
||||
|
||||
@ -18,6 +18,9 @@ public class WarehouseService : ApplicationService
|
||||
{
|
||||
private IWarehouseAddressRepository WarehouseAddressRepository => LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
|
||||
|
||||
private OmsRbacUserDisplayNameResolver UserDisplayNameResolver =>
|
||||
LazyServiceProvider.GetRequiredService<OmsRbacUserDisplayNameResolver>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询仓库列表。
|
||||
/// </summary>
|
||||
@ -74,8 +77,10 @@ public class WarehouseService : ApplicationService
|
||||
{
|
||||
var entity = await GetWarehouseOrThrowAsync(id);
|
||||
var output = ObjectMapper.Map<WarehouseAddress, WarehouseOutput>(entity);
|
||||
output.CreateBy = entity.CreateUserId <= 0 ? null : entity.CreateUserId.ToString();
|
||||
output.UpdateBy = entity.UpdateUserId <= 0 ? null : entity.UpdateUserId.ToString();
|
||||
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
||||
[entity.CreateUserId, entity.UpdateUserId]);
|
||||
output.CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap);
|
||||
output.UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap);
|
||||
output.UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime);
|
||||
return output;
|
||||
}
|
||||
|
||||
80
src/Oms.Application/Shared/OmsRbacUserDisplayNameResolver.cs
Normal file
80
src/Oms.Application/Shared/OmsRbacUserDisplayNameResolver.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using Fake.DependencyInjection;
|
||||
using Fake.Rbac.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Oms.Application.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// 将 OMS 审计字段中的 RBAC mapId(user.userid)解析为展示名称。
|
||||
/// </summary>
|
||||
public class OmsRbacUserDisplayNameResolver : IScopedDependency
|
||||
{
|
||||
private readonly FakeRbacDbContext _rbacDbContext;
|
||||
|
||||
public OmsRbacUserDisplayNameResolver(FakeRbacDbContext rbacDbContext)
|
||||
{
|
||||
_rbacDbContext = rbacDbContext;
|
||||
}
|
||||
|
||||
public async Task<string?> ResolveAsync(int userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (userId <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var map = await ResolveManyAsync([userId], cancellationToken);
|
||||
return FormatUserId(userId, map);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyDictionary<int, string>> ResolveManyAsync(
|
||||
IEnumerable<int> userIds,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var ids = userIds.Where(x => x > 0).Distinct().ToList();
|
||||
if (ids.Count == 0)
|
||||
{
|
||||
return new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
var sql =
|
||||
$"SELECT `userid` AS `{nameof(RbacUserNameRow.UserId)}`, `Name` AS `{nameof(RbacUserNameRow.DisplayName)}` FROM `user` WHERE `IsDeleted` = 0 AND `userid` IN ({string.Join(",", ids)})";
|
||||
var rows = await _rbacDbContext.Database
|
||||
.SqlQueryRaw<RbacUserNameRow>(sql)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return rows.ToDictionary(
|
||||
x => x.UserId,
|
||||
x => NormalizeDisplayName(x.DisplayName, x.UserId));
|
||||
}
|
||||
|
||||
public static string? FormatUserId(int userId, IReadOnlyDictionary<int, string>? nameMap)
|
||||
{
|
||||
if (userId <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (nameMap != null &&
|
||||
nameMap.TryGetValue(userId, out var name) &&
|
||||
!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return userId.ToString();
|
||||
}
|
||||
|
||||
private static string NormalizeDisplayName(string? name, int userId)
|
||||
{
|
||||
var trimmed = name?.Trim();
|
||||
return string.IsNullOrWhiteSpace(trimmed) ? userId.ToString() : trimmed;
|
||||
}
|
||||
|
||||
private sealed class RbacUserNameRow
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
|
||||
public string? DisplayName { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user