103 lines
3.6 KiB
C#
103 lines
3.6 KiB
C#
using MediatR;
|
||
using System.Text.Json;
|
||
using TakeoutSaaS.Application.App.Personal.Dto;
|
||
using TakeoutSaaS.Application.App.Personal.Queries;
|
||
using TakeoutSaaS.Application.App.Personal.Services;
|
||
using TakeoutSaaS.Application.App.Personal.Validators;
|
||
using TakeoutSaaS.Domain.Tenants.Repositories;
|
||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||
|
||
namespace TakeoutSaaS.Application.App.Personal.Handlers;
|
||
|
||
/// <summary>
|
||
/// 分页查询个人操作记录处理器。
|
||
/// </summary>
|
||
public sealed class SearchPersonalOperationsQueryHandler(
|
||
PersonalContextService personalContextService,
|
||
PersonalDateRangeValidator personalDateRangeValidator,
|
||
IOperationLogRepository operationLogRepository)
|
||
: IRequestHandler<SearchPersonalOperationsQuery, PagedResult<PersonalOperationLogDto>>
|
||
{
|
||
/// <summary>
|
||
/// 处理查询。
|
||
/// </summary>
|
||
/// <param name="request">查询请求。</param>
|
||
/// <param name="cancellationToken">取消标记。</param>
|
||
/// <returns>操作记录分页结果。</returns>
|
||
public async Task<PagedResult<PersonalOperationLogDto>> Handle(SearchPersonalOperationsQuery request, CancellationToken cancellationToken)
|
||
{
|
||
// 1. 获取上下文并解析时间窗
|
||
var context = personalContextService.GetRequiredContext();
|
||
var dateRange = personalDateRangeValidator.Resolve(request.From, request.To);
|
||
|
||
// 2. 解析分页参数(默认 50,上限 50)
|
||
var page = request.Page <= 0 ? 1 : request.Page;
|
||
var pageSize = request.PageSize <= 0 ? 50 : Math.Min(request.PageSize, 50);
|
||
|
||
// 3. 查询并映射
|
||
var paged = await operationLogRepository.SearchByOperatorPagedAsync(
|
||
context.TenantId,
|
||
context.UserId.ToString(),
|
||
dateRange.From,
|
||
dateRange.To,
|
||
page,
|
||
pageSize,
|
||
cancellationToken);
|
||
var items = paged.Items.Select(log => new PersonalOperationLogDto
|
||
{
|
||
OperationId = log.Id,
|
||
OperatorUserId = ParseOperatorUserId(log.OperatorId, context.UserId),
|
||
ActionType = log.OperationType,
|
||
TargetType = log.TargetType,
|
||
TargetId = ResolveTargetId(log.TargetIds),
|
||
IsSuccess = log.Success,
|
||
OccurredAt = log.CreatedAt
|
||
}).ToList();
|
||
|
||
// 4. 返回分页结果
|
||
return new PagedResult<PersonalOperationLogDto>(items, page, pageSize, paged.Total);
|
||
}
|
||
|
||
private static long ParseOperatorUserId(string? operatorId, long fallbackUserId)
|
||
{
|
||
// 1. 尝试从字符串解析用户 ID
|
||
if (long.TryParse(operatorId, out var parsed) && parsed > 0)
|
||
{
|
||
return parsed;
|
||
}
|
||
|
||
// 2. 解析失败时回退当前用户
|
||
return fallbackUserId;
|
||
}
|
||
|
||
private static string? ResolveTargetId(string? targetIds)
|
||
{
|
||
// 1. 空值直接返回
|
||
if (string.IsNullOrWhiteSpace(targetIds))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// 2. 尝试解析 JSON 数组并提取首个元素
|
||
var normalized = targetIds.Trim();
|
||
if (normalized.StartsWith("[", StringComparison.Ordinal))
|
||
{
|
||
try
|
||
{
|
||
using var doc = JsonDocument.Parse(normalized);
|
||
if (doc.RootElement.ValueKind == JsonValueKind.Array && doc.RootElement.GetArrayLength() > 0)
|
||
{
|
||
return doc.RootElement[0].ToString();
|
||
}
|
||
}
|
||
catch (JsonException)
|
||
{
|
||
// 3. JSON 解析失败时按原始字符串返回
|
||
}
|
||
}
|
||
|
||
// 4. 非数组场景直接返回原值
|
||
return normalized;
|
||
}
|
||
}
|