using System.Globalization; using System.Text.Json; using Fake.Application; using Fake.DependencyInjection; namespace Oms.Application.Labeling.Hiprint; /// /// 将 hiprint TemplateJson 转为中间绘制 IR。 /// public sealed class HiprintTemplateParser : ITransientDependency { private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; public LabelPageIr Parse(string templateJson, IReadOnlyDictionary printData) { if (string.IsNullOrWhiteSpace(templateJson)) { throw new ArgumentException("模板 JSON 为空", nameof(templateJson)); } var doc = JsonSerializer.Deserialize(templateJson, JsonOptions) ?? throw new BusinessException("模板 JSON 无法解析"); var panel = doc.Panels.OrderBy(x => x.Index).FirstOrDefault() ?? throw new BusinessException("模板缺少 panels"); var widthMm = panel.Width > 0 ? panel.Width : 100f; var heightMm = panel.Height > 0 ? panel.Height : 150f; var ops = new List(); foreach (var element in panel.PrintElements) { var op = MapElement(element, printData); if (op != null) { ops.Add(op); } } return new LabelPageIr { WidthMm = widthMm, HeightMm = heightMm, Ops = ops }; } private static LabelDrawOp? MapElement( HiprintPrintElement element, IReadOnlyDictionary printData) { var type = element.PrintElementType?.Type?.Trim().ToLowerInvariant() ?? "text"; var opt = element.Options; var left = opt.Left; var top = opt.Top; var width = Math.Max(opt.Width, 1f); var height = Math.Max(opt.Height, 1f); switch (type) { case "hline": return new LabelLineOp { LeftPt = left, TopPt = top, WidthPt = width, HeightPt = Math.Max(opt.BorderWidth ?? 1f, 0.5f), Vertical = false, ColorHex = opt.Color, ThicknessPt = opt.BorderWidth ?? 1f }; case "vline": return new LabelLineOp { LeftPt = left, TopPt = top, WidthPt = Math.Max(opt.BorderWidth ?? 1f, 0.5f), HeightPt = height, Vertical = true, ColorHex = opt.Color, ThicknessPt = opt.BorderWidth ?? 1f }; case "rect": return new LabelRectOp { LeftPt = left, TopPt = top, WidthPt = width, HeightPt = height, BorderColorHex = opt.Color, BorderWidthPt = opt.BorderWidth ?? 1f }; case "image": return new LabelImageOp { LeftPt = left, TopPt = top, WidthPt = width, HeightPt = height, Src = ResolveValue(opt.Field, opt.Src ?? opt.Title, printData) }; case "longtext": return BuildTextOp(opt, left, top, width, height, printData, wrap: true); case "text": default: { var textType = opt.TextType?.Trim().ToLowerInvariant(); if (textType is "barcode" or "qrcode") { var content = ResolveValue(opt.Field, opt.Title, printData); if (string.IsNullOrWhiteSpace(content)) { return null; } return new LabelBarcodeOp { LeftPt = left, TopPt = top, WidthPt = width, HeightPt = height, Content = content, QrCode = textType == "qrcode" }; } return BuildTextOp(opt, left, top, width, height, printData, wrap: false); } } } private static LabelTextOp? BuildTextOp( HiprintElementOptions opt, float left, float top, float width, float height, IReadOnlyDictionary printData, bool wrap) { var value = ResolveValue(opt.Field, null, printData); string text; if (!string.IsNullOrWhiteSpace(opt.Field)) { // 有 field:默认只打字段值;hideTitle=false 且有 title 时拼「标题:值」 if (opt.HideTitle == false && !string.IsNullOrWhiteSpace(opt.Title) && !string.IsNullOrWhiteSpace(value)) { text = $"{opt.Title}:{value}"; } else { text = value ?? string.Empty; } } else { text = opt.Title ?? string.Empty; } if (string.IsNullOrWhiteSpace(text)) { return null; } var bold = string.Equals(opt.FontWeight, "bold", StringComparison.OrdinalIgnoreCase) || opt.FontWeight is "700" or "600"; return new LabelTextOp { LeftPt = left, TopPt = top, WidthPt = width, HeightPt = height, Text = text, FontSizePt = opt.FontSize is > 0 ? opt.FontSize.Value : 10f, Bold = bold, ColorHex = opt.Color, Align = (opt.TextAlign ?? "left").ToLowerInvariant(), Wrap = wrap }; } private static string? ResolveValue( string? field, string? fallback, IReadOnlyDictionary printData) { if (!string.IsNullOrWhiteSpace(field) && printData.TryGetValue(field, out var raw) && raw != null) { return Convert.ToString(raw, CultureInfo.InvariantCulture); } return fallback; } }