fix(order): move all-orders list to database pagination
All checks were successful
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Successful in 1m50s

This commit is contained in:
2026-02-27 10:32:21 +08:00
parent b1c51c7712
commit 502f80473e
3 changed files with 201 additions and 85 deletions

View File

@@ -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);
}
/// <inheritdoc />
public async Task<(IReadOnlyList<Order> 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);
}
/// <inheritdoc />
public async Task<IReadOnlyList<OrderItem>> 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<Order> 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<Order> ApplyOrderSorting(
IQueryable<Order> 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)
};
}
}