feat: 新增 /order/print/batch 同步批量返回面单地址
All checks were successful
Build and Deploy / deploy (push) Successful in 1m44s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m44s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
0fdc9e29f4
commit
61d1502148
@ -1,3 +1,5 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Oms.Application.Dtos.Orders;
|
namespace Oms.Application.Dtos.Orders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -20,3 +22,37 @@ public class OrderPrintOutput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? LabelGenerateError { get; set; }
|
public string? LabelGenerateError { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量获取面单打印地址入参。
|
||||||
|
/// </summary>
|
||||||
|
public class OrderPrintBatchInput
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[MinLength(1)]
|
||||||
|
public List<int> OrderIds { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量获取面单打印地址单条结果。
|
||||||
|
/// </summary>
|
||||||
|
public class OrderPrintBatchItemOutput
|
||||||
|
{
|
||||||
|
public int OrderId { get; set; }
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
public string PrintUrl { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string? LabelGenerateStatus { get; set; }
|
||||||
|
|
||||||
|
public string? Error { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量获取面单打印地址出参。
|
||||||
|
/// </summary>
|
||||||
|
public class OrderPrintBatchOutput
|
||||||
|
{
|
||||||
|
public List<OrderPrintBatchItemOutput> Items { get; set; } = [];
|
||||||
|
}
|
||||||
|
|||||||
@ -34,6 +34,37 @@ public sealed class OrderFileManager(
|
|||||||
return string.IsNullOrWhiteSpace(file?.FileUrl) ? null : fileStorage.GetPublicUrl(file.FileUrl.Trim());
|
return string.IsNullOrWhiteSpace(file?.FileUrl) ? null : fileStorage.GetPublicUrl(file.FileUrl.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量取系统面单公开地址(已存在才返回)。
|
||||||
|
/// </summary>
|
||||||
|
public async Task<Dictionary<int, string>> GetSystemLabelUrlsAsync(
|
||||||
|
IReadOnlyCollection<int> orderIds,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var result = new Dictionary<int, string>();
|
||||||
|
var ids = orderIds?.Where(x => x > 0).Distinct().ToList() ?? [];
|
||||||
|
if (ids.Count == 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = await orderFileRepository.GetByOrderIdsAndTypeAsync(
|
||||||
|
ids,
|
||||||
|
OrderFileTypeCodes.SystemLabel,
|
||||||
|
cancellationToken);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(file.FileUrl) || result.ContainsKey(file.OrderId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[file.OrderId] = fileStorage.GetPublicUrl(file.FileUrl.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<OrderFileGroupedOutput> GetGroupedAsync(
|
public async Task<OrderFileGroupedOutput> GetGroupedAsync(
|
||||||
int orderId,
|
int orderId,
|
||||||
bool customerView,
|
bool customerView,
|
||||||
|
|||||||
@ -317,6 +317,89 @@ public partial class OrderService : ApplicationService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量获取打印面单地址(同步返回,避免前端逐单请求)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">入参:订单 ID 列表。</param>
|
||||||
|
/// <returns>各订单打印结果。</returns>
|
||||||
|
[HttpPost("/order/print/batch")]
|
||||||
|
public async Task<OrderPrintBatchOutput> PrintBatchAsync([FromBody] OrderPrintBatchInput input)
|
||||||
|
{
|
||||||
|
var orderIds = (input.OrderIds ?? []).Where(x => x > 0).Distinct().ToList();
|
||||||
|
if (orderIds.Count == 0)
|
||||||
|
{
|
||||||
|
throw new BusinessException("请选择要打印的订单");
|
||||||
|
}
|
||||||
|
|
||||||
|
const int maxBatchSize = 100;
|
||||||
|
if (orderIds.Count > maxBatchSize)
|
||||||
|
{
|
||||||
|
throw new BusinessException($"单次最多获取 {maxBatchSize} 张面单");
|
||||||
|
}
|
||||||
|
|
||||||
|
var output = new OrderPrintBatchOutput
|
||||||
|
{
|
||||||
|
Items = new List<OrderPrintBatchItemOutput>(orderIds.Count)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 已有系统面单一律批量查出,避免 N 次附件查询
|
||||||
|
var existingUrls = await OrderFileManager.GetSystemLabelUrlsAsync(orderIds);
|
||||||
|
var pendingIds = new List<int>();
|
||||||
|
foreach (var orderId in orderIds)
|
||||||
|
{
|
||||||
|
if (existingUrls.TryGetValue(orderId, out var url) && !string.IsNullOrWhiteSpace(url))
|
||||||
|
{
|
||||||
|
output.Items.Add(new OrderPrintBatchItemOutput
|
||||||
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
Success = true,
|
||||||
|
PrintUrl = url,
|
||||||
|
LabelGenerateStatus = LabelGenerateStatusCodes.Ready
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pendingIds.Add(orderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未就绪的走单票打印逻辑(含即时补生成),单条失败不影响其它
|
||||||
|
foreach (var orderId in pendingIds)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var print = await PrintAsync(new OrderActionInput { Id = orderId });
|
||||||
|
var ok = !string.IsNullOrWhiteSpace(print.PrintUrl);
|
||||||
|
output.Items.Add(new OrderPrintBatchItemOutput
|
||||||
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
Success = ok,
|
||||||
|
PrintUrl = print.PrintUrl ?? string.Empty,
|
||||||
|
LabelGenerateStatus = print.LabelGenerateStatus,
|
||||||
|
Error = ok ? null : (print.LabelGenerateError ?? "未获取到打印文件")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
output.Items.Add(new OrderPrintBatchItemOutput
|
||||||
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
Success = false,
|
||||||
|
Error = ex is BusinessException be ? be.Message : ex.Message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保持与入参顺序一致
|
||||||
|
var byId = output.Items.ToDictionary(x => x.OrderId);
|
||||||
|
output.Items = orderIds
|
||||||
|
.Select(id => byId.TryGetValue(id, out var item)
|
||||||
|
? item
|
||||||
|
: new OrderPrintBatchItemOutput { OrderId = id, Success = false, Error = "未处理" })
|
||||||
|
.ToList();
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出订单。
|
/// 导出订单。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -17,6 +17,14 @@ public interface IOrderFileRepository : IRepository<OrderFile>
|
|||||||
string fileType,
|
string fileType,
|
||||||
CancellationToken cancellationToken = default);
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按订单 ID 集合 + 附件类型批量查询。
|
||||||
|
/// </summary>
|
||||||
|
Task<List<OrderFile>> GetByOrderIdsAndTypeAsync(
|
||||||
|
IReadOnlyCollection<int> orderIds,
|
||||||
|
string fileType,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task SoftDeleteByOrderAndTypeAsync(
|
Task SoftDeleteByOrderAndTypeAsync(
|
||||||
int orderId,
|
int orderId,
|
||||||
string fileType,
|
string fileType,
|
||||||
|
|||||||
@ -31,6 +31,22 @@ public class OrderFileRepository
|
|||||||
x => x.OrderId == orderId && x.FileType == fileType,
|
x => x.OrderId == orderId && x.FileType == fileType,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
public Task<List<OrderFile>> GetByOrderIdsAndTypeAsync(
|
||||||
|
IReadOnlyCollection<int> orderIds,
|
||||||
|
string fileType,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var ids = orderIds?.Where(x => x > 0).Distinct().ToList() ?? [];
|
||||||
|
if (ids.Count == 0)
|
||||||
|
{
|
||||||
|
return Task.FromResult(new List<OrderFile>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetListAsync(
|
||||||
|
x => ids.Contains(x.OrderId) && x.FileType == fileType,
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task SoftDeleteByOrderAndTypeAsync(
|
public async Task SoftDeleteByOrderAndTypeAsync(
|
||||||
int orderId,
|
int orderId,
|
||||||
string fileType,
|
string fileType,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user