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;
}
}