using Fake.Application; using Microsoft.AspNetCore.Mvc; using Oms.Application.Dtos.Channels; using Oms.Application.Dtos.Shared; using Oms.Application.Labeling; using Oms.Application.Shared; using Oms.Domain.ChannelsAggregate.Consts; using Oms.Domain.ChannelsAggregate.Entities; using Oms.Domain.ChannelsAggregate.Repositories; namespace Oms.Application.Services.Channels; /// /// 面单模板 API 服务。 /// [ApiExplorerSettings(GroupName = "OMS-Channel")] public class LabelTemplateService : ApplicationService { private ILabelTemplateRepository LabelTemplateRepository => LazyServiceProvider.GetRequiredService(); private LabelPdfGenerationService LabelPdfGenerationService => LazyServiceProvider.GetRequiredService(); /// /// 标签模板列表(不含 JSON,供浏览/下拉)。 /// [HttpGet("/channel/label-template/list")] public async Task> GetListAsync( [FromQuery] string? keyword = null, [FromQuery] string? templateType = null) { var keywordValue = keyword?.Trim(); var typeValue = templateType?.Trim(); var hasKeyword = !string.IsNullOrEmpty(keywordValue); var hasType = !string.IsNullOrEmpty(typeValue); var entities = await LabelTemplateRepository.GetListAsync(x => (!hasKeyword || x.Name.Contains(keywordValue!)) && (!hasType || x.TemplateType == typeValue)); var items = entities .OrderByDescending(x => x.UpdateTime) .ThenByDescending(x => x.Id) .Select(x => new LabelTemplateListItemOutput { Id = x.Id, Name = x.Name, TemplateType = x.TemplateType, CreateTime = x.CreateTime, UpdateTime = OmsDocHelper.NullIfDefault(x.UpdateTime) }) .ToList(); return new OmsItemsResult { Items = items }; } /// /// 标签模板详情(含 TemplateJson,编辑用)。 /// [HttpGet("/channel/label-template/{id:int}")] public async Task GetAsync(int id) { var entity = await GetEntityOrThrowAsync(id); return MapOutput(entity); } /// /// 设计器字段字典(可拖字段分组)。 /// [HttpGet("/channel/label-template/field-dictionary")] public Task> GetFieldDictionaryAsync() { return Task.FromResult(new OmsItemsResult { Items = LabelFieldDictionary.GetGroups().ToList() }); } /// /// 预览 PDF(同一套 ILabelPdfRenderer)。 /// [HttpPost("/channel/label-template/preview-pdf")] public async Task PreviewPdfAsync([FromBody] LabelTemplatePreviewInput input) { string? templateJson = null; string? templateType = null; if (input.TemplateId is > 0) { var entity = await GetEntityOrThrowAsync(input.TemplateId.Value); templateJson = entity.TemplateJson; templateType = entity.TemplateType; } else { templateJson = OmsDocHelper.SerializeJson(input.TemplateJson); } if (string.IsNullOrWhiteSpace(templateJson)) { throw new BusinessException("模板 JSON 为空"); } IReadOnlyDictionary? printData = null; if (input.PrintData is { Count: > 0 }) { printData = input.PrintData.ToDictionary( x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase); } else if (string.Equals(templateType, LabelTemplateTypeCodes.Box, StringComparison.OrdinalIgnoreCase)) { printData = InboundBoxLabelPrintDataBuilder.BuildMock(); } else if (string.Equals(templateType, LabelTemplateTypeCodes.Sku, StringComparison.OrdinalIgnoreCase)) { printData = SkuLabelPrintDataBuilder.BuildMock(); } var bytes = await LabelPdfGenerationService.PreviewAsync(templateJson, printData); return new FileContentResult(bytes, "application/pdf") { FileDownloadName = $"label-preview-{DateTime.Now:yyyyMMddHHmmss}.pdf" }; } /// /// 保存标签模板。 /// [HttpPost("/channel/label-template/save")] public async Task SaveAsync(LabelTemplateSaveInput input) { LabelTemplate entity; if (input.Id > 0) { entity = await GetEntityOrThrowAsync(input.Id); await ValidateUniqueNameAsync(input.Name, input.TemplateType, entity.Id); entity.Name = input.Name; entity.TemplateType = input.TemplateType; entity.TemplateJson = OmsDocHelper.SerializeJson(input.TemplateJson); await LabelTemplateRepository.UpdateAsync(entity); } else { await ValidateUniqueNameAsync(input.Name, input.TemplateType, null); entity = new LabelTemplate { Name = input.Name, TemplateType = input.TemplateType, TemplateJson = OmsDocHelper.SerializeJson(input.TemplateJson) }; entity = await LabelTemplateRepository.InsertAsync(entity); } return MapOutput(entity); } /// /// 删除标签模板。 /// [HttpPost("/channel/label-template/delete")] public async Task DeleteAsync(IdInput input) { var entity = await GetEntityOrThrowAsync(input.Id); await LabelTemplateRepository.DeleteAsync(entity); } private async Task ValidateUniqueNameAsync(string name, string? templateType, int? id) { var existed = await LabelTemplateRepository.GetByNameAndTypeAsync(name, templateType); if (existed != null && existed.Id != id) { throw new BusinessException("标签模板名称已存在"); } } private async Task GetEntityOrThrowAsync(int id) { var entity = await LabelTemplateRepository.FirstOrDefaultAsync(x => x.Id == id); if (entity == null) { throw new BusinessException("标签模板不存在"); } return entity; } private static LabelTemplateSaveOutput MapOutput(LabelTemplate entity) { return new LabelTemplateSaveOutput { Id = entity.Id, Name = entity.Name, TemplateType = entity.TemplateType, TemplateJson = OmsDocHelper.DeserializeJsonObject(entity.TemplateJson), CreateTime = entity.CreateTime, UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime) }; } }