7083cd6d
李曜臣
优化代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
using FoodLabeling.Application.Contracts.Dtos.LabelTemplate;
using FoodLabeling.Application.Services.DbModels;
using SqlSugar;
namespace FoodLabeling.Application.Helpers;
/// <summary>
/// 标签模板 <c>Contents</c>:汇总各控件展示名(编辑器 Element name / typeAdd 推导),逗号拼接。
/// </summary>
public static class LabelTemplateContentsHelper
{
/// <summary>
/// 保存时解析 Contents:优先入参 <paramref name="inputContents"/>,否则从 <paramref name="elements"/> 推导。
/// </summary>
public static string ResolveForSave(string? inputContents, IReadOnlyList<LabelTemplateElementDto>? elements)
{
var trimmed = inputContents?.Trim();
if (!string.IsNullOrWhiteSpace(trimmed))
{
return trimmed;
}
return BuildFromElements(elements);
}
/// <summary>
/// 从 elements 推导 Contents(去重、按 OrderNum 排序)。
/// </summary>
public static string BuildFromElements(IReadOnlyList<LabelTemplateElementDto>? elements)
{
if (elements is null || elements.Count == 0)
{
return string.Empty;
}
var names = CollectOrderedDistinctLabels(
elements
.OrderBy(e => e.OrderNum)
.ThenBy(e => e.Id, StringComparer.Ordinal)
.Select(e => ResolveElementContentsLabel(e.ElementName, e.TypeAdd, e.ElementType)));
return names.Count > 0 ? string.Join(", ", names) : string.Empty;
}
/// <summary>
/// 批量从 <c>fl_label_template_element</c> 推导 Contents。Key = 模板主键 Id。
/// </summary>
public static async Task<Dictionary<string, string>> ResolveContentsMapFromElementsAsync(
ISqlSugarClient db,
IReadOnlyList<string> templateIds)
{
var result = new Dictionary<string, string>(StringComparer.Ordinal);
if (templateIds.Count == 0)
{
return result;
}
var rows = await db.Queryable<FlLabelTemplateElementDbEntity>()
.Where(x => templateIds.Contains(x.TemplateId))
.Select(x => new ElementContentsRow
{
TemplateId = x.TemplateId,
ElementName = x.ElementName,
TypeAdd = x.TypeAdd,
ElementType = x.ElementType,
OrderNum = x.OrderNum,
ElementKey = x.ElementKey
})
.ToListAsync();
foreach (var group in rows.GroupBy(x => x.TemplateId))
{
var names = CollectOrderedDistinctLabels(
group
.OrderBy(x => x.OrderNum)
.ThenBy(x => x.ElementKey, StringComparer.Ordinal)
.Select(x => ResolveElementContentsLabel(x.ElementName, x.TypeAdd, x.ElementType)));
if (names.Count > 0)
{
result[group.Key] = string.Join(", ", names);
}
}
return result;
}
/// <summary>
/// 单控件 Contents 展示名:优先用户编辑的 Element name;旧 slug 则按 typeAdd 推导「控件名 (For Template)」。
/// </summary>
public static string ResolveElementContentsLabel(string? elementName, string? typeAdd, string? elementType)
{
var derived = DeriveLabelFromTypeAdd(typeAdd, elementType);
var name = elementName?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
return derived;
}
if (IsLegacySlugElementName(name, typeAdd, elementType))
{
return string.IsNullOrWhiteSpace(derived) ? name : derived;
}
return name;
}
/// <summary>
/// 从 typeAdd(如 <c>template_Text</c>、<c>label_Nutrition Facts</c>)推导展示名。
/// </summary>
public static string DeriveLabelFromTypeAdd(string? typeAdd, string? elementType)
{
var ta = typeAdd?.Trim();
if (!string.IsNullOrWhiteSpace(ta))
{
var idx = ta.IndexOf('_');
if (idx >= 0 && idx < ta.Length - 1)
{
var prefix = ta[..idx].Trim().ToLowerInvariant();
var field = ta[(idx + 1)..].Trim();
if (!string.IsNullOrWhiteSpace(field))
{
var category = MapPrefixToCategoryTitle(prefix);
return category != null ? $"{field} ({category})" : field;
}
}
}
return MapElementTypeToDisplayLabel(elementType);
}
private static bool IsLegacySlugElementName(string name, string? typeAdd, string? elementType)
{
if (name.Contains(' ') || name.Contains('('))
{
return false;
}
if (!LegacySlugPattern.IsMatch(name))
{
return false;
}
var derived = DeriveLabelFromTypeAdd(typeAdd, elementType);
if (string.IsNullOrWhiteSpace(derived))
{
return true;
}
var field = ExtractTypeAddField(typeAdd);
if (string.IsNullOrWhiteSpace(field))
{
return true;
}
var slugField = SlugPaletteLabel(field);
var slugName = name.Trim().ToLowerInvariant();
if (slugName == slugField)
{
return true;
}
if (slugName.StartsWith(slugField, StringComparison.Ordinal)
&& slugName.Length > slugField.Length
&& int.TryParse(slugName[slugField.Length..], out _))
{
return true;
}
return false;
}
private static string? ExtractTypeAddField(string? typeAdd)
{
var ta = typeAdd?.Trim();
if (string.IsNullOrWhiteSpace(ta))
{
return null;
}
var idx = ta.IndexOf('_');
return idx >= 0 && idx < ta.Length - 1 ? ta[(idx + 1)..].Trim() : null;
}
private static string SlugPaletteLabel(string label) =>
new string(label.Trim().ToLowerInvariant().Where(char.IsLetterOrDigit).ToArray());
private static string? MapPrefixToCategoryTitle(string prefix) =>
prefix switch
{
"template" => "For Template",
"label" => "For Label",
"auto" => "Entered Automatically",
"print" => "Entered When Printing",
_ => null
};
private static string MapElementTypeToDisplayLabel(string? elementType)
{
var t = (elementType ?? string.Empty).Trim().ToUpperInvariant();
return t switch
{
"TEXT_PRODUCT" => "Label Name (For Label)",
"TEXT_PRICE" => "Price (For Label)",
"NUTRITION" or "NUTRITIONFACTS" => "Nutrition Facts (For Label)",
"DURATION" => "Duration (For Label)",
"DATE" => "Current Date (Entered Automatically)",
"TIME" => "Current Time (Entered Automatically)",
"BARCODE" => "Barcode (For Label)",
"QRCODE" => "QR Code (For Label)",
"BLANK" => "Blank Space (For Template)",
"IMAGE" => "Image (For Label)",
"TEXT_STATIC" => "Text (For Template)",
_ => string.IsNullOrWhiteSpace(t) ? string.Empty : t.Replace('_', ' ')
};
}
private static List<string> CollectOrderedDistinctLabels(IEnumerable<string> labels)
{
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var names = new List<string>();
foreach (var label in labels)
{
var text = label?.Trim();
if (string.IsNullOrWhiteSpace(text) || !seen.Add(text))
{
continue;
}
names.Add(text);
}
return names;
}
private static readonly System.Text.RegularExpressions.Regex LegacySlugPattern =
new("^[a-z0-9]+$", System.Text.RegularExpressions.RegexOptions.Compiled);
private sealed class ElementContentsRow
{
public string TemplateId { get; init; } = string.Empty;
public string ElementName { get; init; } = string.Empty;
public string? TypeAdd { get; init; }
public string ElementType { get; init; } = string.Empty;
public int OrderNum { get; init; }
public string ElementKey { get; init; } = string.Empty;
}
}
|