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;
///
/// 分页查询个人操作记录处理器。
///
public sealed class SearchPersonalOperationsQueryHandler(
PersonalContextService personalContextService,
PersonalDateRangeValidator personalDateRangeValidator,
IOperationLogRepository operationLogRepository)
: IRequestHandler>
{
///
/// 处理查询。
///
/// 查询请求。
/// 取消标记。
/// 操作记录分页结果。
public async Task> 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(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;
}
}