From ca114eb993958d591582b9c6952660a8f559e752 Mon Sep 17 00:00:00 2001 From: 李曜臣 Date: Tue, 31 Mar 2026 20:31:54 +0800 Subject: [PATCH] 打印日志接口实现 --- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogGetListInputVo.cs | 15 +++++++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/UsAppLabelReprintInputVo.cs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IUsAppLabelingAppService.cs | 11 +++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 项目相关文档/标签模块接口对接说明.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogGetListInputVo.cs create mode 100644 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs create mode 100644 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/UsAppLabelReprintInputVo.cs diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogGetListInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogGetListInputVo.cs new file mode 100644 index 0000000..f819a65 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogGetListInputVo.cs @@ -0,0 +1,15 @@ +using Volo.Abp.Application.Dtos; + +namespace FoodLabeling.Application.Contracts.Dtos.UsAppLabeling; + +/// +/// App 打印日志分页查询入参(仅当前登录账号 + 当前门店) +/// +public class PrintLogGetListInputVo : PagedAndSortedResultRequestDto +{ + /// + /// 当前门店 Id(location.Id,Guid 字符串) + /// + public string LocationId { get; set; } = string.Empty; +} + diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs new file mode 100644 index 0000000..920b592 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs @@ -0,0 +1,44 @@ +namespace FoodLabeling.Application.Contracts.Dtos.UsAppLabeling; + +/// +/// 打印日志列表项 +/// +public class PrintLogItemDto +{ + /// 任务Id(fl_label_print_task.Id) + public string TaskId { get; set; } = string.Empty; + + /// 批次Id(同一次点击 Print 共享) + public string? BatchId { get; set; } + + /// 第几份(从 1 开始) + public int CopyIndex { get; set; } + + /// 标签Id + public string LabelId { get; set; } = string.Empty; + + /// 标签编码 + public string LabelCode { get; set; } = string.Empty; + + /// 产品Id + public string? ProductId { get; set; } + + /// 产品名称 + public string ProductName { get; set; } = "无"; + + /// 标签类型名称(来自 fl_label_type.TypeName) + public string TypeName { get; set; } = string.Empty; + + /// 模板尺寸(来自 fl_label_template.Width/Height/Unit) + public string? LabelSizeText { get; set; } + + /// 打印时间(PrintedAt ?? CreationTime) + public DateTime PrintedAt { get; set; } + + /// 操作人姓名(当前登录账号 Name) + public string OperatorName { get; set; } = string.Empty; + + /// 门店名称 + public string LocationName { get; set; } = "无"; +} + diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/UsAppLabelReprintInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/UsAppLabelReprintInputVo.cs new file mode 100644 index 0000000..0c18998 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/UsAppLabeling/UsAppLabelReprintInputVo.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace FoodLabeling.Application.Contracts.Dtos.UsAppLabeling; + +/// +/// App 重新打印入参(根据历史任务Id重打) +/// +public class UsAppLabelReprintInputVo +{ + /// + /// 当前门店Id(用于权限校验,必须与历史任务一致) + /// + public string LocationId { get; set; } = string.Empty; + + /// + /// 历史打印任务Id(fl_label_print_task.Id) + /// + public string TaskId { get; set; } = string.Empty; + + /// + /// 重新打印份数(<=0 则按 1 处理;默认 1) + /// + public int PrintQuantity { get; set; } = 1; + + /// + /// 客户端幂等请求Id(可选)。 + /// 同一个 clientRequestId 重复调用 reprint 接口时,后端会直接返回首次创建的 batchId/taskIds,不会重复写库。 + /// + public string? ClientRequestId { get; set; } + + /// + /// 重新打印时可覆盖打印机Id(可选) + /// + public string? PrinterId { get; set; } + + /// + /// 重新打印时可覆盖打印机蓝牙 MAC(可选) + /// + public string? PrinterMac { get; set; } + + /// + /// 重新打印时可覆盖打印机地址(可选) + /// + public string? PrinterAddress { get; set; } +} + diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IUsAppLabelingAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IUsAppLabelingAppService.cs index 0006eec..7cbe514 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IUsAppLabelingAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IUsAppLabelingAppService.cs @@ -1,4 +1,5 @@ using FoodLabeling.Application.Contracts.Dtos.UsAppLabeling; +using FoodLabeling.Application.Contracts.Dtos.Common; using Volo.Abp.Application.Services; namespace FoodLabeling.Application.Contracts.IServices; @@ -22,4 +23,14 @@ public interface IUsAppLabelingAppService : IApplicationService /// App 打印:创建打印任务并落库打印明细(fl_label_print_task / fl_label_print_data) /// Task PrintAsync(UsAppLabelPrintInputVo input); + + /// + /// App 重新打印:根据历史任务Id重打(创建新任务与明细) + /// + Task ReprintAsync(UsAppLabelReprintInputVo input); + + /// + /// App 打印日志:获取当前登录账号在当前门店打印的记录(分页,时间倒序) + /// + Task> GetPrintLogListAsync(PrintLogGetListInputVo input); } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs index c26db25..11d27c6 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs @@ -4,16 +4,21 @@ using System.Globalization; using System.Linq; using System.Text.Json; using System.Threading.Tasks; +using FoodLabeling.Application.Contracts.Dtos.Common; using FoodLabeling.Application.Contracts.Dtos.Label; using FoodLabeling.Application.Contracts.Dtos.UsAppLabeling; using FoodLabeling.Application.Contracts.IServices; +using FoodLabeling.Application.Helpers; using FoodLabeling.Application.Services.DbModels; +using FoodLabeling.Domain.Entities; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using SqlSugar; using Volo.Abp; using Volo.Abp.Application.Services; using Volo.Abp.Guids; using Volo.Abp.Uow; +using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.SqlSugarCore.Abstractions; namespace FoodLabeling.Application.Services; @@ -26,12 +31,18 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ private readonly ISqlSugarDbContext _dbContext; private readonly ILabelAppService _labelAppService; private readonly IGuidGenerator _guidGenerator; + private readonly ISqlSugarRepository _userRepository; - public UsAppLabelingAppService(ISqlSugarDbContext dbContext, ILabelAppService labelAppService, IGuidGenerator guidGenerator) + public UsAppLabelingAppService( + ISqlSugarDbContext dbContext, + ILabelAppService labelAppService, + IGuidGenerator guidGenerator, + ISqlSugarRepository userRepository) { _dbContext = dbContext; _labelAppService = labelAppService; _guidGenerator = guidGenerator; + _userRepository = userRepository; } /// @@ -509,6 +520,297 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ }; } + /// + /// App 重新打印:根据历史任务Id重打(创建新任务与明细) + /// + [Authorize] + [UnitOfWork] + public virtual async Task ReprintAsync(UsAppLabelReprintInputVo input) + { + if (input is null) + { + throw new UserFriendlyException("入参不能为空"); + } + + var locationId = input.LocationId?.Trim(); + if (string.IsNullOrWhiteSpace(locationId)) + { + throw new UserFriendlyException("门店Id不能为空"); + } + + var taskId = input.TaskId?.Trim(); + if (string.IsNullOrWhiteSpace(taskId)) + { + throw new UserFriendlyException("taskId不能为空"); + } + + var quantity = input.PrintQuantity <= 0 ? 1 : input.PrintQuantity; + var clientRequestId = input.ClientRequestId?.Trim(); + if (!string.IsNullOrWhiteSpace(clientRequestId)) + { + var existed = await _dbContext.SqlSugarClient.Queryable() + .Where(x => x.ClientRequestId == clientRequestId) + .OrderBy(x => x.CopyIndex) + .ToListAsync(); + + if (existed is not null && existed.Count > 0) + { + var existedBatchId = existed.First().BatchId; + var existedTaskIds = existed.Select(x => x.Id).ToList(); + return new UsAppLabelPrintOutputDto + { + TaskId = existedTaskIds.FirstOrDefault() ?? string.Empty, + PrintQuantity = existedTaskIds.Count, + BatchId = existedBatchId, + TaskIds = existedTaskIds + }; + } + } + + var currentUserId = CurrentUser?.Id?.ToString(); + if (string.IsNullOrWhiteSpace(currentUserId)) + { + throw new UserFriendlyException("未登录"); + } + + var old = await _dbContext.SqlSugarClient.Queryable() + .FirstAsync(x => x.Id == taskId); + if (old is null) + { + throw new UserFriendlyException("打印任务不存在"); + } + + // 仅允许重打自己在当前门店的任务 + if (!string.Equals(old.CreatedBy?.Trim(), currentUserId, StringComparison.OrdinalIgnoreCase)) + { + throw new UserFriendlyException("无权限重打该任务"); + } + if (!string.Equals(old.LocationId?.Trim(), locationId, StringComparison.OrdinalIgnoreCase)) + { + throw new UserFriendlyException("该任务不属于当前门店"); + } + + LabelTemplatePreviewDto? resolvedTemplate = null; + try + { + resolvedTemplate = JsonSerializer.Deserialize(old.RenderTemplateJson); + } + catch + { + resolvedTemplate = null; + } + + if (resolvedTemplate is null) + { + throw new UserFriendlyException("历史任务渲染快照解析失败,无法重打"); + } + + var now = DateTime.Now; + var batchId = _guidGenerator.Create().ToString(); + var taskIds = new List(); + + for (var i = 1; i <= quantity; i++) + { + var newTaskId = _guidGenerator.Create().ToString(); + taskIds.Add(newTaskId); + + var newTask = new FlLabelPrintTaskDbEntity + { + Id = newTaskId, + BatchId = batchId, + CopyIndex = i, + ClientRequestId = string.IsNullOrWhiteSpace(clientRequestId) ? null : clientRequestId, + LabelId = old.LabelId, + TemplateId = old.TemplateId, + LabelTypeId = old.LabelTypeId, + ProductId = old.ProductId, + LocationId = old.LocationId, + BaseTime = old.BaseTime, + PrintInputJson = old.PrintInputJson, + TemplateProductDefaultValuesJson = old.TemplateProductDefaultValuesJson, + RenderTemplateJson = old.RenderTemplateJson, + PrinterId = string.IsNullOrWhiteSpace(input.PrinterId) ? old.PrinterId : input.PrinterId.Trim(), + PrinterMac = string.IsNullOrWhiteSpace(input.PrinterMac) ? old.PrinterMac : input.PrinterMac.Trim(), + PrinterAddress = string.IsNullOrWhiteSpace(input.PrinterAddress) ? old.PrinterAddress : input.PrinterAddress.Trim(), + Status = "CREATED", + PrintedAt = null, + ErrorMessage = null, + CreatedBy = currentUserId, + CreationTime = now + }; + + await _dbContext.SqlSugarClient.Insertable(newTask).ExecuteCommandAsync(); + + var rows = resolvedTemplate.Elements.Select(e => + { + var cfgJson = e.ConfigJson is null ? null : JsonSerializer.Serialize(e.ConfigJson); + string? renderValue = null; + if (e.ConfigJson is JsonElement je && je.ValueKind == JsonValueKind.Object && je.TryGetProperty("text", out var tv)) + { + renderValue = tv.ValueKind == JsonValueKind.String ? tv.GetString() : tv.ToString(); + } + else if (e.ConfigJson is Dictionary dict && dict.TryGetValue("text", out var v)) + { + renderValue = v?.ToString(); + } + + return new FlLabelPrintDataDbEntity + { + Id = _guidGenerator.Create().ToString(), + PrintTaskId = newTaskId, + ElementId = e.Id?.Trim() ?? string.Empty, + ElementName = e.ElementName?.Trim(), + RenderValue = renderValue, + RenderConfigJson = cfgJson + }; + }).Where(x => !string.IsNullOrWhiteSpace(x.ElementId)).ToList(); + + if (rows.Count > 0) + { + await _dbContext.SqlSugarClient.Insertable(rows).ExecuteCommandAsync(); + } + } + + return new UsAppLabelPrintOutputDto + { + TaskId = taskIds.FirstOrDefault() ?? string.Empty, + PrintQuantity = quantity, + BatchId = batchId, + TaskIds = taskIds + }; + } + + /// + /// App 打印日志:获取当前登录账号在当前门店打印的记录(分页,时间倒序) + /// + /// + /// 仅返回满足: + /// - CreatedBy == CurrentUser.Id + /// - LocationId == input.LocationId + /// 的打印任务记录(fl_label_print_task)。 + /// + /// 示例请求: + /// ```json + /// { + /// "locationId": "11111111-1111-1111-1111-111111111111", + /// "skipCount": 1, + /// "maxResultCount": 20 + /// } + /// ``` + /// + /// 参数说明: + /// - locationId: 当前门店 Id(必填) + /// - skipCount: 页码(从 1 开始,遵循本项目约定) + /// - maxResultCount: 每页条数 + /// + /// 分页查询入参 + /// 分页打印日志 + /// 成功 + /// 参数错误/未登录 + /// 服务器错误 + [Authorize] + [HttpPost] + public virtual async Task> GetPrintLogListAsync(PrintLogGetListInputVo input) + { + if (input is null) + { + throw new UserFriendlyException("入参不能为空"); + } + + if (!CurrentUser.Id.HasValue) + { + throw new UserFriendlyException("用户未登录"); + } + + var locationId = input.LocationId?.Trim(); + if (string.IsNullOrWhiteSpace(locationId)) + { + throw new UserFriendlyException("门店Id不能为空"); + } + + var currentUserIdStr = CurrentUser.Id.Value.ToString(); + + var currentUser = await _userRepository.GetByIdAsync(CurrentUser.Id.Value); + var operatorName = currentUser?.Name?.Trim() ?? string.Empty; + + var locationName = "无"; + if (Guid.TryParse(locationId, out var locationGuid)) + { + var loc = await _dbContext.SqlSugarClient.Queryable() + .Where(x => !x.IsDeleted && x.Id == locationGuid) + .Select(x => new { x.LocationCode, x.LocationName }) + .FirstAsync(); + if (loc is not null) + { + var name = loc.LocationName?.Trim(); + if (!string.IsNullOrWhiteSpace(name)) + { + locationName = name; + } + } + } + + RefAsync total = 0; + + var query = _dbContext.SqlSugarClient + .Queryable() + .LeftJoin((t, l) => t.LabelId == l.Id) + .LeftJoin((t, l, p) => t.ProductId == p.Id) + .LeftJoin((t, l, p, lt) => t.LabelTypeId == lt.Id) + .LeftJoin((t, l, p, lt, tpl) => t.TemplateId == tpl.Id) + .Where((t, l, p, lt, tpl) => t.CreatedBy == currentUserIdStr && t.LocationId == locationId) + .OrderBy((t, l, p, lt, tpl) => SqlFunc.IsNull(t.PrintedAt, t.CreationTime), OrderByType.Desc) + .OrderBy((t, l, p, lt, tpl) => t.CreationTime, OrderByType.Desc) + .Select((t, l, p, lt, tpl) => new + { + t.Id, + t.BatchId, + t.CopyIndex, + t.LabelId, + LabelCode = l.LabelCode, + t.ProductId, + ProductName = p.ProductName, + TypeName = lt.TypeName, + TemplateWidth = tpl.Width, + TemplateHeight = tpl.Height, + TemplateUnit = tpl.Unit, + t.PrintedAt, + t.CreationTime + }); + + var pageRows = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + + var items = pageRows.Select(x => new PrintLogItemDto + { + TaskId = x.Id, + BatchId = x.BatchId, + CopyIndex = x.CopyIndex, + LabelId = x.LabelId, + LabelCode = x.LabelCode ?? string.Empty, + ProductId = x.ProductId, + ProductName = string.IsNullOrWhiteSpace(x.ProductName) ? "无" : x.ProductName.Trim(), + TypeName = x.TypeName ?? string.Empty, + LabelSizeText = FormatLabelSizeWithUnit(x.TemplateWidth, x.TemplateHeight, x.TemplateUnit), + PrintedAt = x.PrintedAt ?? x.CreationTime, + OperatorName = operatorName, + LocationName = locationName + }).ToList(); + + var pageSize = input.MaxResultCount <= 0 ? items.Count : input.MaxResultCount; + var pageIndex = pageSize <= 0 ? 1 : PagedQueryConvention.PageIndexFromSkipCount(input.SkipCount); + var totalCount = (long)total; + var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(totalCount / (double)pageSize); + + return new PagedResultWithPageDto + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = totalPages, + Items = items + }; + } + private async Task ResolveTemplateProductDefaultValuesJsonAsync( string templateId, string? productId, @@ -657,4 +959,13 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ ? $"{ws}\"x{hs}\"" : $"{ws}x{hs}{u}"; } + + private static string? FormatLabelSizeWithUnit(decimal w, decimal h, string unit) + { + var u = (unit ?? "inch").Trim().ToLowerInvariant(); + var ws = w.ToString(CultureInfo.InvariantCulture); + var hs = h.ToString(CultureInfo.InvariantCulture); + var normalizedUnit = u is "in" ? "inch" : u; + return $"{ws}x{hs}{normalizedUnit}"; + } } diff --git a/项目相关文档/标签模块接口对接说明.md b/项目相关文档/标签模块接口对接说明.md index 12501f2..b3000d6 100644 --- a/项目相关文档/标签模块接口对接说明.md +++ b/项目相关文档/标签模块接口对接说明.md @@ -964,3 +964,113 @@ curl -X POST "http://localhost:19001/api/app/us-app-labeling/print" \ -d '{"locationId":"11111111-1111-1111-1111-111111111111","labelCode":"LBL_CHICKEN_DEFROST","productId":"22222222-2222-2222-2222-222222222222","printQuantity":2,"baseTime":"2026-03-26T10:30:00","printInputJson":{"price":"12.99"}}' ``` +--- + +## 接口 10:App 打印日志(当前登录账号 + 当前门店) + +**场景**:移动端“打印记录/历史”页面。只展示**当前登录账号**在**当前门店**打印的记录,便于追溯/重打。 + +### 10.1 分页获取打印日志 + +#### HTTP + +- **方法**:`POST`(与本模块其它复杂入参接口一致;若与 Swagger 不一致,**以 Swagger 为准**) +- **路径**:`/api/app/us-app-labeling/get-print-log-list` +- **鉴权**:需要登录(`Authorization: Bearer ...`) + +#### 入参(Body:`PrintLogGetListInputVo`) + +> 本项目分页约定:`skipCount` 表示 **页码(从 1 开始)**,不是 0 基 offset。 + +| 参数名(JSON) | 类型 | 必填 | 说明 | +|---|---|---|---| +| `locationId` | string | 是 | 当前门店Id(仅返回该门店记录) | +| `skipCount` | number | 否 | 页码,从 1 开始;默认 1 | +| `maxResultCount` | number | 否 | 每页条数;默认按后端/ABP 默认 | + +#### 过滤条件(后端固定逻辑) + +- `fl_label_print_task.CreatedBy == CurrentUser.Id` +- `fl_label_print_task.LocationId == locationId` +- 按时间倒序:`PrintedAt ?? CreationTime`(越新的越靠前) + +#### 出参(`PagedResultWithPageDto`) + +| 字段 | 类型 | 说明 | +|---|---|---| +| `pageIndex` | number | 当前页码(从 1 开始) | +| `pageSize` | number | 每页条数 | +| `totalCount` | number | 总条数 | +| `totalPages` | number | 总页数 | +| `items` | PrintLogItemDto[] | 列表 | + +`PrintLogItemDto`: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `taskId` | string | 任务Id(fl_label_print_task.Id) | +| `batchId` | string | 批次Id(同一次点击 Print 共享) | +| `copyIndex` | number | 第几份(从 1 开始) | +| `labelId` | string | 标签Id | +| `labelCode` | string | 标签编码(来自 fl_label.LabelCode) | +| `productId` | string | 产品Id | +| `productName` | string | 产品名(来自 fl_product.ProductName;无则 “无”) | +| `typeName` | string | 标签类型名称(来自 fl_label_type.TypeName) | +| `labelSizeText` | string | 模板尺寸(宽高+单位,如 `2.00x2.00inch` / `6.00x4.00cm`) | +| `printedAt` | string | 打印时间(PrintedAt ?? CreationTime) | +| `operatorName` | string | 操作人姓名(当前登录账号 Name) | +| `locationName` | string | 门店名称 | + +#### curl + +```bash +curl -X POST "http://localhost:19001/api/app/us-app-labeling/get-print-log-list" \ + -H "Authorization: " \ + -H "Content-Type: application/json" \ + -d '{"locationId":"11111111-1111-1111-1111-111111111111","skipCount":1,"maxResultCount":20}' +``` + +--- + +## 接口 11:App 重新打印(根据任务Id重打) + +**场景**:移动端“打印记录/历史”页面点击 **Reprint**。后端根据历史任务 `taskId` 创建一批新的打印任务与明细。 + +### 11.1 重打 + +#### HTTP + +- **方法**:`POST` +- **路径**:`/api/app/us-app-labeling/reprint`(若与 Swagger 不一致,**以 Swagger 为准**) +- **鉴权**:需要登录(`Authorization: Bearer ...`) + +#### 入参(Body:`UsAppLabelReprintInputVo`) + +| 参数名(JSON) | 类型 | 必填 | 说明 | +|---|---|---|---| +| `locationId` | string | 是 | 当前门店Id(后端校验历史任务必须属于该门店) | +| `taskId` | string | 是 | 历史打印任务Id(`fl_label_print_task.Id`) | +| `printQuantity` | number | 否 | 重新打印份数;`<=0` 按 1 处理;默认 1 | +| `clientRequestId` | string | 否 | 客户端幂等请求Id;同一个值重复调用会直接返回首次创建的 `batchId/taskIds`,避免重复写库 | +| `printerId` | string | 否 | 可选,覆盖历史任务的打印机Id | +| `printerMac` | string | 否 | 可选,覆盖历史任务的打印机MAC | +| `printerAddress` | string | 否 | 可选,覆盖历史任务的打印机地址 | + +#### 权限校验(后端固定逻辑) + +- 历史任务必须满足:`CreatedBy == CurrentUser.Id` +- 且 `LocationId == locationId` + +#### 出参(`UsAppLabelPrintOutputDto`) + +字段与接口 9 一致:`taskId / printQuantity / batchId / taskIds` + +#### curl + +```bash +curl -X POST "http://localhost:19001/api/app/us-app-labeling/reprint" \ + -H "Authorization: " \ + -H "Content-Type: application/json" \ + -d '{"locationId":"11111111-1111-1111-1111-111111111111","taskId":"3a205389-78dd-4750-51ab-720344c9f607","printQuantity":1}' +``` + -- libgit2 0.21.4