using MediatR; using TakeoutSaaS.Application.App.Orders.Dto; using TakeoutSaaS.Application.App.Orders.Queries; using TakeoutSaaS.Domain.Orders.Entities; using TakeoutSaaS.Domain.Orders.Enums; using TakeoutSaaS.Domain.Orders.Repositories; using TakeoutSaaS.Shared.Abstractions.Results; using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Orders.Handlers; /// /// 全部订单列表查询处理器。 /// public sealed class SearchOrderAllListQueryHandler( IOrderRepository orderRepository, ITenantProvider tenantProvider) : IRequestHandler> { /// public async Task> Handle(SearchOrderAllListQuery request, CancellationToken cancellationToken) { var tenantId = tenantProvider.GetCurrentTenantId(); var page = Math.Max(1, request.Page); var pageSize = Math.Clamp(request.PageSize, 1, 200); var (pagedOrders, totalCount) = await orderRepository.SearchAllOrdersPageAsync( tenantId, request.StoreId, request.StartAt, request.EndAt, request.Status, request.RefundedOnly, request.DeliveryType, request.PaymentMethod, request.Keyword, request.SortBy, request.SortDescending, page, pageSize, cancellationToken); var refundedSet = await LoadRefundedOrderIdsAsync( pagedOrders.Select(order => order.Id).ToList(), tenantId, cancellationToken); var itemsLookup = await orderRepository.GetItemsByOrderIdsAsync( pagedOrders.Select(order => order.Id).ToList(), tenantId, cancellationToken); var rows = pagedOrders .Select(order => { var isRefunded = refundedSet.Contains(order.Id); return new OrderAllListItemDto { OrderId = order.Id, OrderNo = order.OrderNo, OrderedAt = order.CreatedAt, DeliveryType = order.DeliveryType, Status = order.Status, CustomerName = string.IsNullOrWhiteSpace(order.CustomerName) ? "--" : order.CustomerName, ItemsSummary = BuildItemSummary(order.Id, itemsLookup), Amount = ResolveDisplayAmount(order), IsRefunded = isRefunded, IsDimmed = order.Status == OrderStatus.Cancelled || isRefunded }; }) .ToList(); return new PagedResult(rows, page, pageSize, totalCount); } private async Task> LoadRefundedOrderIdsAsync( IReadOnlyCollection orderIds, long tenantId, CancellationToken cancellationToken) { if (orderIds.Count == 0) { return []; } var refunded = await orderRepository.GetRefundedOrderIdsAsync(orderIds, tenantId, cancellationToken); return refunded.ToHashSet(); } private static decimal ResolveDisplayAmount(Order order) { return order.PaidAmount > 0 ? order.PaidAmount : order.PayableAmount; } private static string BuildItemSummary( long orderId, IReadOnlyDictionary> itemsLookup) { if (!itemsLookup.TryGetValue(orderId, out var items) || items.Count == 0) { return "--"; } var first = string.IsNullOrWhiteSpace(items[0].ProductName) ? "商品" : items[0].ProductName.Trim(); var totalQuantity = items.Sum(item => Math.Max(0, item.Quantity)); if (totalQuantity <= 0) { totalQuantity = items.Count; } return $"{first}等{totalQuantity}件"; } }