From 502f80473eb2857346eb71218175bad7e1d81628 Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Fri, 27 Feb 2026 10:32:21 +0800 Subject: [PATCH] fix(order): move all-orders list to database pagination --- .../SearchOrderAllListQueryHandler.cs | 53 ++--- .../Orders/Repositories/IOrderRepository.cs | 34 +++ .../App/Repositories/EfOrderRepository.cs | 199 ++++++++++++++---- 3 files changed, 201 insertions(+), 85 deletions(-) diff --git a/src/Application/TakeoutSaaS.Application/App/Orders/Handlers/SearchOrderAllListQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Orders/Handlers/SearchOrderAllListQueryHandler.cs index 6eda490..9767688 100644 --- a/src/Application/TakeoutSaaS.Application/App/Orders/Handlers/SearchOrderAllListQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Orders/Handlers/SearchOrderAllListQueryHandler.cs @@ -21,34 +21,29 @@ public sealed class SearchOrderAllListQueryHandler( 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 orders = await orderRepository.SearchAllOrdersAsync( + 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 filteredOrders = orders.ToList(); - var refundedSet = await LoadRefundedOrderIdsAsync(filteredOrders, tenantId, cancellationToken); - if (request.RefundedOnly) - { - filteredOrders = filteredOrders - .Where(order => refundedSet.Contains(order.Id)) - .ToList(); - } - - var sorted = ApplySorting(filteredOrders, request.SortBy, request.SortDescending); - var page = Math.Max(1, request.Page); - var pageSize = Math.Clamp(request.PageSize, 1, 200); - var pagedOrders = sorted - .Skip((page - 1) * pageSize) - .Take(pageSize) - .ToList(); + var refundedSet = await LoadRefundedOrderIdsAsync( + pagedOrders.Select(order => order.Id).ToList(), + tenantId, + cancellationToken); var itemsLookup = await orderRepository.GetItemsByOrderIdsAsync( pagedOrders.Select(order => order.Id).ToList(), @@ -75,15 +70,14 @@ public sealed class SearchOrderAllListQueryHandler( }) .ToList(); - return new PagedResult(rows, page, pageSize, filteredOrders.Count); + return new PagedResult(rows, page, pageSize, totalCount); } private async Task> LoadRefundedOrderIdsAsync( - IReadOnlyCollection orders, + IReadOnlyCollection orderIds, long tenantId, CancellationToken cancellationToken) { - var orderIds = orders.Select(order => order.Id).ToList(); if (orderIds.Count == 0) { return []; @@ -116,23 +110,4 @@ public sealed class SearchOrderAllListQueryHandler( return $"{first}等{totalQuantity}件"; } - - private static IEnumerable ApplySorting( - IReadOnlyCollection orders, - string? sortBy, - bool sortDescending) - { - return sortBy?.Trim().ToLowerInvariant() switch - { - "amount" => sortDescending - ? orders.OrderByDescending(ResolveDisplayAmount).ThenByDescending(order => order.CreatedAt) - : orders.OrderBy(ResolveDisplayAmount).ThenBy(order => order.CreatedAt), - "status" => sortDescending - ? orders.OrderByDescending(order => order.Status).ThenByDescending(order => order.CreatedAt) - : orders.OrderBy(order => order.Status).ThenBy(order => order.CreatedAt), - _ => sortDescending - ? orders.OrderByDescending(order => order.CreatedAt) - : orders.OrderBy(order => order.CreatedAt) - }; - } } diff --git a/src/Domain/TakeoutSaaS.Domain/Orders/Repositories/IOrderRepository.cs b/src/Domain/TakeoutSaaS.Domain/Orders/Repositories/IOrderRepository.cs index 6e6510e..8b0c5e8 100644 --- a/src/Domain/TakeoutSaaS.Domain/Orders/Repositories/IOrderRepository.cs +++ b/src/Domain/TakeoutSaaS.Domain/Orders/Repositories/IOrderRepository.cs @@ -63,6 +63,40 @@ public interface IOrderRepository string? keyword, CancellationToken cancellationToken = default); + /// + /// 全部订单分页筛选查询。 + /// + /// 租户 ID。 + /// 门店 ID。 + /// 开始时间(含)。 + /// 结束时间(不含)。 + /// 订单状态。 + /// 是否仅退款。 + /// 履约方式。 + /// 支付方式。 + /// 关键词(订单号/手机号)。 + /// 排序字段。 + /// 是否倒序。 + /// 页码。 + /// 每页条数。 + /// 取消标记。 + /// 分页订单与总数。 + Task<(IReadOnlyList Items, int TotalCount)> SearchAllOrdersPageAsync( + long tenantId, + long? storeId, + DateTime? startAt, + DateTime? endAt, + OrderStatus? status, + bool refundedOnly, + DeliveryType? deliveryType, + PaymentMethod? paymentMethod, + string? keyword, + string? sortBy, + bool sortDescending, + int page, + int pageSize, + CancellationToken cancellationToken = default); + /// /// 获取订单明细行。 /// diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfOrderRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfOrderRepository.cs index 57af3df..ad79ac1 100644 --- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfOrderRepository.cs +++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfOrderRepository.cs @@ -71,52 +71,16 @@ public sealed class EfOrderRepository(TakeoutAppDbContext context) : IOrderRepos string? keyword, CancellationToken cancellationToken = default) { - var query = context.Orders - .AsNoTracking() - .Where(x => x.TenantId == tenantId); - - if (storeId.HasValue) - { - query = query.Where(x => x.StoreId == storeId.Value); - } - - if (startAt.HasValue) - { - query = query.Where(x => x.CreatedAt >= startAt.Value); - } - - if (endAt.HasValue) - { - query = query.Where(x => x.CreatedAt < endAt.Value); - } - - if (status.HasValue) - { - query = query.Where(x => x.Status == status.Value); - } - - if (deliveryType.HasValue) - { - query = query.Where(x => x.DeliveryType == deliveryType.Value); - } - - if (paymentMethod.HasValue) - { - query = query.Where(x => - context.PaymentRecords.Any(record => - record.TenantId == tenantId && - record.OrderId == x.Id && - record.Method == paymentMethod.Value && - (record.Status == PaymentStatus.Paid || record.Status == PaymentStatus.Refunded))); - } - - if (!string.IsNullOrWhiteSpace(keyword)) - { - var normalized = keyword.Trim(); - query = query.Where(x => - x.OrderNo.Contains(normalized) || - (x.CustomerPhone != null && x.CustomerPhone.Contains(normalized))); - } + var query = BuildSearchAllOrdersQuery( + tenantId, + storeId, + startAt, + endAt, + status, + false, + deliveryType, + paymentMethod, + keyword); return await query .OrderByDescending(x => x.CreatedAt) @@ -124,6 +88,48 @@ public sealed class EfOrderRepository(TakeoutAppDbContext context) : IOrderRepos .ToListAsync(cancellationToken); } + /// + public async Task<(IReadOnlyList Items, int TotalCount)> SearchAllOrdersPageAsync( + long tenantId, + long? storeId, + DateTime? startAt, + DateTime? endAt, + OrderStatus? status, + bool refundedOnly, + DeliveryType? deliveryType, + PaymentMethod? paymentMethod, + string? keyword, + string? sortBy, + bool sortDescending, + int page, + int pageSize, + CancellationToken cancellationToken = default) + { + var normalizedPage = Math.Max(1, page); + var normalizedPageSize = Math.Clamp(pageSize, 1, 200); + + var query = BuildSearchAllOrdersQuery( + tenantId, + storeId, + startAt, + endAt, + status, + refundedOnly, + deliveryType, + paymentMethod, + keyword); + + var total = await query.CountAsync(cancellationToken); + var sorted = ApplyOrderSorting(query, sortBy, sortDescending); + + var items = await sorted + .Skip((normalizedPage - 1) * normalizedPageSize) + .Take(normalizedPageSize) + .ToListAsync(cancellationToken); + + return (items, total); + } + /// public async Task> GetItemsAsync(long orderId, long tenantId, CancellationToken cancellationToken = default) { @@ -306,4 +312,105 @@ public sealed class EfOrderRepository(TakeoutAppDbContext context) : IOrderRepos context.Orders.Remove(existing); } + + private IQueryable BuildSearchAllOrdersQuery( + long tenantId, + long? storeId, + DateTime? startAt, + DateTime? endAt, + OrderStatus? status, + bool refundedOnly, + DeliveryType? deliveryType, + PaymentMethod? paymentMethod, + string? keyword) + { + var query = context.Orders + .AsNoTracking() + .Where(x => x.TenantId == tenantId); + + if (storeId.HasValue) + { + query = query.Where(x => x.StoreId == storeId.Value); + } + + if (startAt.HasValue) + { + query = query.Where(x => x.CreatedAt >= startAt.Value); + } + + if (endAt.HasValue) + { + query = query.Where(x => x.CreatedAt < endAt.Value); + } + + if (status.HasValue) + { + query = query.Where(x => x.Status == status.Value); + } + + if (deliveryType.HasValue) + { + query = query.Where(x => x.DeliveryType == deliveryType.Value); + } + + if (paymentMethod.HasValue) + { + query = query.Where(x => + context.PaymentRecords.Any(record => + record.TenantId == tenantId && + record.OrderId == x.Id && + record.Method == paymentMethod.Value && + (record.Status == PaymentStatus.Paid || record.Status == PaymentStatus.Refunded))); + } + + if (refundedOnly) + { + query = query.Where(x => + context.RefundRequests.Any(refund => + refund.TenantId == tenantId && + refund.OrderId == x.Id && + refund.Status == RefundStatus.Refunded)); + } + + if (!string.IsNullOrWhiteSpace(keyword)) + { + var normalized = keyword.Trim(); + query = query.Where(x => + x.OrderNo.Contains(normalized) || + (x.CustomerPhone != null && x.CustomerPhone.Contains(normalized))); + } + + return query; + } + + private static IOrderedQueryable ApplyOrderSorting( + IQueryable query, + string? sortBy, + bool sortDescending) + { + return sortBy?.Trim().ToLowerInvariant() switch + { + "amount" => sortDescending + ? query + .OrderByDescending(order => order.PaidAmount > 0 ? order.PaidAmount : order.PayableAmount) + .ThenByDescending(order => order.CreatedAt) + .ThenByDescending(order => order.Id) + : query + .OrderBy(order => order.PaidAmount > 0 ? order.PaidAmount : order.PayableAmount) + .ThenBy(order => order.CreatedAt) + .ThenBy(order => order.Id), + "status" => sortDescending + ? query + .OrderByDescending(order => order.Status) + .ThenByDescending(order => order.CreatedAt) + .ThenByDescending(order => order.Id) + : query + .OrderBy(order => order.Status) + .ThenBy(order => order.CreatedAt) + .ThenBy(order => order.Id), + _ => sortDescending + ? query.OrderByDescending(order => order.CreatedAt).ThenByDescending(order => order.Id) + : query.OrderBy(order => order.CreatedAt).ThenBy(order => order.Id) + }; + } }