fix: 面单自定义文本支持 testData,并避免文本框高度裁切
All checks were successful
Build and Deploy / deploy (push) Successful in 1m11s

无 field 时按 title/testData 输出;框高至少字号×1.4,防止设计器矮框打成空白。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-10-23 14:50:23 +08:00
parent 7b54eff764
commit af7909948e
3 changed files with 89 additions and 11 deletions

View File

@ -63,6 +63,10 @@ public sealed class HiprintElementOptions
[JsonPropertyName("title")]
public string? Title { get; set; }
/// <summary>设计器「测试数据」;无 field 的纯文本有时只把文案写在这里。</summary>
[JsonPropertyName("testData")]
public string? TestData { get; set; }
[JsonPropertyName("field")]
public string? Field { get; set; }

View File

@ -105,14 +105,15 @@ public sealed class HiprintTemplateParser
Src = ResolveValue(opt.Field, opt.Src ?? opt.Title, printData)
};
case "longtext":
return BuildTextOp(opt, left, top, width, height, printData, wrap: true);
return BuildTextOp(
opt, left, top, width, height, printData, wrap: true, element.PrintElementType?.Title);
case "text":
default:
{
var textType = opt.TextType?.Trim().ToLowerInvariant();
if (textType is "barcode" or "qrcode")
{
var content = ResolveValue(opt.Field, opt.Title, printData);
var content = ResolveValue(opt.Field, FirstNonEmpty(opt.Title, opt.TestData), printData);
if (string.IsNullOrWhiteSpace(content))
{
return null;
@ -129,7 +130,8 @@ public sealed class HiprintTemplateParser
};
}
return BuildTextOp(opt, left, top, width, height, printData, wrap: false);
return BuildTextOp(
opt, left, top, width, height, printData, wrap: false, element.PrintElementType?.Title);
}
}
}
@ -141,25 +143,38 @@ public sealed class HiprintTemplateParser
float width,
float height,
IReadOnlyDictionary<string, object?> printData,
bool wrap)
bool wrap,
string? elementTypeTitle = null)
{
var value = ResolveValue(opt.Field, null, printData);
// 与 vg-print 一致:无 field 时打印 title;有 field 时按 hideTitle 决定是否带标题
var title = FirstNonEmpty(opt.Title, elementTypeTitle);
string text;
if (!string.IsNullOrWhiteSpace(opt.Field))
{
// 有 field:默认只打字段值;hideTitle=false 且有 title 时拼「标题:值」
if (opt.HideTitle == false && !string.IsNullOrWhiteSpace(opt.Title) && !string.IsNullOrWhiteSpace(value))
var hideTitle = opt.HideTitle != false; // null/true → 隐藏标题(OMS 字段默认 hideTitle:true)
if (!hideTitle && !string.IsNullOrWhiteSpace(title) && !string.IsNullOrWhiteSpace(value))
{
text = $"{opt.Title}:{value}";
text = $"{title}:{value}";
}
else if (!string.IsNullOrWhiteSpace(value))
{
text = value!;
}
else if (!hideTitle && !string.IsNullOrWhiteSpace(title))
{
// 仅标题(值为空时仍保留自定义标题文案)
text = title!;
}
else
{
text = value ?? string.Empty;
text = string.Empty;
}
}
else
{
text = opt.Title ?? string.Empty;
// 纯自定义文本:title → testData → 元素类型名
text = FirstNonEmpty(opt.Title, opt.TestData, elementTypeTitle) ?? string.Empty;
}
if (string.IsNullOrWhiteSpace(text))
@ -169,15 +184,18 @@ public sealed class HiprintTemplateParser
var bold = string.Equals(opt.FontWeight, "bold", StringComparison.OrdinalIgnoreCase)
|| opt.FontWeight is "700" or "600";
var fontSize = opt.FontSize is > 0 ? opt.FontSize.Value : 10f;
// 设计器文本框常只有十余 pt 高,行高略大于字号时会被裁成「空白」
var boxHeight = Math.Max(height, fontSize * 1.4f);
return new LabelTextOp
{
LeftPt = left,
TopPt = top,
WidthPt = width,
HeightPt = height,
HeightPt = boxHeight,
Text = text,
FontSizePt = opt.FontSize is > 0 ? opt.FontSize.Value : 10f,
FontSizePt = fontSize,
Bold = bold,
ColorHex = opt.Color,
Align = (opt.TextAlign ?? "left").ToLowerInvariant(),
@ -185,6 +203,9 @@ public sealed class HiprintTemplateParser
};
}
private static string? FirstNonEmpty(params string?[] values) =>
values.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
private static string? ResolveValue(
string? field,
string? fallback,

View File

@ -49,6 +49,59 @@ public class HiprintTemplateParserTests
act.Should().Throw<Exception>();
}
[Fact]
public void Parse_StaticCustomText_ShouldKeepTitleAndNotClipHeight()
{
const string json = """
{
"panels": [{
"width": 100,
"height": 50,
"printElements": [{
"options": {
"left": 10,
"top": 10,
"width": 80,
"height": 13,
"title": "箱子数量",
"fontSize": 10,
"hideTitle": true
},
"printElementType": { "type": "text", "title": "文本" }
}]
}]
}
""";
var page = new HiprintTemplateParser().Parse(json, new Dictionary<string, object?>());
var text = page.Ops.OfType<LabelTextOp>().Should().ContainSingle().Subject;
text.Text.Should().Be("箱子数量");
text.HeightPt.Should().BeGreaterThanOrEqualTo(14f);
}
[Fact]
public void Parse_StaticTextFromTestData_WhenTitleEmpty()
{
const string json = """
{
"panels": [{
"width": 100,
"height": 50,
"printElements": [{
"options": {
"left": 1, "top": 1, "width": 50, "height": 16,
"testData": "仅测试数据文案"
},
"printElementType": { "type": "text" }
}]
}]
}
""";
var page = new HiprintTemplateParser().Parse(json, new Dictionary<string, object?>());
page.Ops.OfType<LabelTextOp>().Should().ContainSingle(x => x.Text == "仅测试数据文案");
}
internal static string LoadFixture(string fileName)
{
var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;