@worm-vue3-print/core 1.3.7 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @worm-vue3-print/core v1.3.7
2
+ * @worm-vue3-print/core v1.3.8
3
3
  * Copyright (c) 2026 worm <liu_long_qqcom@qq.com>
4
4
  * SPDX-FileCopyrightText: 2026 worm <liu_long_qqcom@qq.com>
5
5
  * SPDX-License-Identifier: MIT
@@ -31,6 +31,13 @@ __export(designer_exports, {
31
31
  BARCODE_MODULE_WIDTH_MM: () => BARCODE_MODULE_WIDTH_MM,
32
32
  BARCODE_QUIET_ZONE_MODULES: () => BARCODE_QUIET_ZONE_MODULES,
33
33
  BARCODE_TEXT_FONT_SIZE_MODULES: () => BARCODE_TEXT_FONT_SIZE_MODULES,
34
+ CROP_AXIS_OPTIONS: () => CROP_AXIS_OPTIONS,
35
+ CROP_GRID_OPTIONS: () => CROP_GRID_OPTIONS,
36
+ CROP_SAMPLE_IMAGE: () => CROP_SAMPLE_IMAGE,
37
+ CROP_SAMPLE_NOTE: () => CROP_SAMPLE_NOTE,
38
+ CROP_SCALE_LABEL: () => CROP_SCALE_LABEL,
39
+ CROP_SCALE_MAX: () => CROP_SCALE_MAX,
40
+ CROP_SCALE_MIN: () => CROP_SCALE_MIN,
34
41
  DEFAULT_DEMO_DATA: () => DEFAULT_DEMO_DATA,
35
42
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT: () => DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
36
43
  ELEMENT_BINDING_REGISTRY: () => ELEMENT_BINDING_REGISTRY,
@@ -38,6 +45,7 @@ __export(designer_exports, {
38
45
  EXTENDED_FUNCTIONS: () => EXTENDED_FUNCTIONS,
39
46
  FIT_SCALE_MIN_PERCENT: () => FIT_SCALE_MIN_PERCENT,
40
47
  GHOST_BORDER_CSS: () => GHOST_BORDER_CSS,
48
+ IMAGE_FIT_OPTIONS: () => IMAGE_FIT_OPTIONS,
41
49
  LABEL_PAPER_GROUP: () => LABEL_PAPER_GROUP,
42
50
  MIN_COL_WIDTH_MM: () => MIN_COL_WIDTH_MM,
43
51
  MIN_SCALE_PERCENT: () => MIN_SCALE_PERCENT,
@@ -54,12 +62,14 @@ __export(designer_exports, {
54
62
  barcodeAvailableBoxMm: () => barcodeAvailableBoxMm,
55
63
  barcodePreferredModuleWidthMm: () => barcodePreferredModuleWidthMm,
56
64
  barcodeUnitsPerModule: () => barcodeUnitsPerModule,
65
+ buildCropAnchor: () => buildCropAnchor,
57
66
  buildRulerTicks: () => buildRulerTicks,
58
67
  calcResizeRect: () => calcResizeRect,
59
68
  canMergeReason: () => canMergeReason,
60
69
  cellFitCapMm: () => cellFitCapMm,
61
70
  cellFitKey: () => cellFitKey,
62
71
  cellFitWidthMm: () => cellFitWidthMm,
72
+ cellImageBoxMm: () => cellImageBoxMm,
63
73
  chooseMajorStepMM: () => chooseMajorStepMM,
64
74
  clampResizedColumnWidth: () => clampResizedColumnWidth,
65
75
  clampScalePercent: () => clampScalePercent,
@@ -71,6 +81,13 @@ __export(designer_exports, {
71
81
  createDefaultTable: () => createDefaultTable,
72
82
  createFieldElement: () => createFieldElement,
73
83
  createRuntimeElement: () => createRuntimeElement,
84
+ cropAxisFields: () => cropAxisFields,
85
+ cropAxisLabel: () => cropAxisLabel,
86
+ cropAxisNote: () => cropAxisNote,
87
+ cropPresetOptions: () => cropPresetOptions,
88
+ cropScalePct: () => cropScalePct,
89
+ cropStyleDeclarations: () => cropStyleDeclarations,
90
+ cropWindow: () => cropWindow,
74
91
  deleteCol: () => deleteCol,
75
92
  deleteRow: () => deleteRow,
76
93
  engine: () => engine2,
@@ -102,6 +119,7 @@ __export(designer_exports, {
102
119
  normalizeSelection: () => normalizeSelection,
103
120
  normalizeTemplateUnits: () => normalizeTemplateUnits,
104
121
  parseCellFitKey: () => parseCellFitKey,
122
+ parseCropAnchor: () => parseCropAnchor,
105
123
  propertyTip: () => propertyTip,
106
124
  ptToMm: () => ptToMm,
107
125
  pxToMm: () => pxToMm,
@@ -109,13 +127,18 @@ __export(designer_exports, {
109
127
  resolveBarcodeSize: () => resolveBarcodeSize,
110
128
  resolveCellBorderCss: () => resolveCellBorderCss,
111
129
  resolveCellTextFit: () => resolveCellTextFit,
130
+ resolveCropPreview: () => resolveCropPreview,
131
+ resolveCropTravel: () => resolveCropTravel,
132
+ resolveDesignImageSrc: () => resolveDesignImageSrc,
112
133
  resolveElementBorder: () => resolveElementBorder,
113
134
  resolveElementTextFit: () => resolveElementTextFit,
135
+ resolveOverlayPlacement: () => resolveOverlayPlacement,
114
136
  resolveShrinkMinFontSize: () => resolveShrinkMinFontSize,
115
137
  resolveTextBinding: () => resolveTextBinding,
116
138
  resolveToolbarOverflow: () => resolveToolbarOverflow,
117
139
  roundFontSize: () => roundFontSize,
118
140
  safeEval: () => safeEval2,
141
+ sanitizeObjectPosition: () => sanitizeObjectPosition,
119
142
  searchProperties: () => searchProperties,
120
143
  setHeaderRepeat: () => setHeaderRepeat,
121
144
  setRowType: () => setRowType,
@@ -181,6 +204,9 @@ function parseCellFitKey(key) {
181
204
  if (!Number.isFinite(rowIndex) || !Number.isFinite(colIndex)) return void 0;
182
205
  return { elementId: key.slice(0, first), kind, rowIndex, colIndex };
183
206
  }
207
+ function cellImageBoxMm(fit, capMm) {
208
+ return (fit || "contain") === "cover" ? capMm : void 0;
209
+ }
184
210
  function cellFitWidthMm(colWidths, colIndex, cell, defaultPadding = 1) {
185
211
  const span = Math.max(cell?.colspan ?? 1, 1);
186
212
  let width = 0;
@@ -289,6 +315,35 @@ function resolveElementBorder(type, opts) {
289
315
  return { all, edges };
290
316
  }
291
317
 
318
+ // src/render/crop-style.ts
319
+ var OBJECT_POSITION_UNSAFE = /[;"'<>\\(){}\[\]@!#]/;
320
+ var OBJECT_POSITION_MAX_LEN = 64;
321
+ var CROP_SCALE_MIN = 100;
322
+ var CROP_SCALE_MAX = 400;
323
+ function sanitizeObjectPosition(value) {
324
+ const v = (value ?? "").trim();
325
+ if (!v || v.length > OBJECT_POSITION_MAX_LEN || OBJECT_POSITION_UNSAFE.test(v)) return "";
326
+ return v;
327
+ }
328
+ function cropScalePct(fit, scale) {
329
+ if ((fit || "contain") !== "cover") return void 0;
330
+ if (typeof scale !== "number" || !Number.isFinite(scale)) return void 0;
331
+ const pct = Math.round(scale);
332
+ if (pct <= CROP_SCALE_MIN) return void 0;
333
+ return Math.min(pct, CROP_SCALE_MAX);
334
+ }
335
+ function cropStyleDeclarations(fit, scale, objectPosition) {
336
+ const pos = sanitizeObjectPosition(objectPosition);
337
+ const out = {};
338
+ if (pos) out.objectPosition = pos;
339
+ const pct = cropScalePct(fit, scale);
340
+ if (pct !== void 0) {
341
+ out.transform = `scale(${Number((pct / 100).toFixed(2))})`;
342
+ out.transformOrigin = pos || "50% 50%";
343
+ }
344
+ return out;
345
+ }
346
+
292
347
  // src/designer/utils/scale.ts
293
348
  var MIN_SCALE_PERCENT = 25;
294
349
  var FIT_SCALE_MIN_PERCENT = 5;
@@ -327,6 +382,15 @@ function resolveToolbarOverflow(input) {
327
382
  return { movedIds: [...moved], overflowRemains: true };
328
383
  }
329
384
 
385
+ // src/designer/utils/overlay-placement.ts
386
+ function resolveOverlayPlacement(input) {
387
+ const gap = input.gap ?? 4;
388
+ const below = input.boundaryBottom - input.triggerBottom - gap;
389
+ const above = input.triggerTop - input.boundaryTop - gap;
390
+ if (below >= input.overlayHeight) return "down";
391
+ return above > below ? "up" : "down";
392
+ }
393
+
330
394
  // src/designer/utils/migrate.ts
331
395
  var PT_KEYS = ["left", "top", "width", "height"];
332
396
  function convertElement(el) {
@@ -1041,13 +1105,18 @@ var PROPERTY_REGISTRY = [
1041
1105
  },
1042
1106
  {
1043
1107
  key: "ap-img-fit",
1044
- keywords: ["\u7F29\u653E\u6A21\u5F0F", "\u62C9\u4F38", "\u7B49\u6BD4", "fit", "contain", "cover", "\u586B\u5145", "\u88C1\u526A"],
1045
- tip: "\u56FE\u7247\u5728\u5143\u7D20\u6846\u5185\u7684\u7F29\u653E\u65B9\u5F0F\uFF1A\u5305\u542B\uFF1D\u5B8C\u6574\u663E\u793A\u53EF\u80FD\u7559\u767D\uFF1B\u8986\u76D6\uFF1D\u94FA\u6EE1\u6846\u53EF\u80FD\u88C1\u8FB9\uFF1B\u62C9\u4F38\uFF1D\u586B\u6EE1\u6846\u4F1A\u53D8\u5F62\uFF1B\u539F\u59CB\u5C3A\u5BF8/\u7F29\u5C0F\u4E0D\u653E\u5927\u3002\u753B\u5E03\u4E0E\u4E09\u6761\u51FA\u7EB8\u94FE\u8DEF\u540C\u4E00\u53E3\u5F84\uFF08\u7F3A\u7701\u5305\u542B\uFF09"
1108
+ keywords: ["\u7F29\u653E\u6A21\u5F0F", "\u62C9\u4F38", "\u7B49\u6BD4", "fit", "contain", "cover", "\u586B\u5145", "\u88C1\u526A", "\u526A\u88C1", "\u951A\u70B9"],
1109
+ tip: "\u56FE\u7247\u5728\u5143\u7D20\u6846\u5185\u7684\u7F29\u653E\u65B9\u5F0F\uFF1A\u5305\u542B\uFF1D\u5B8C\u6574\u663E\u793A\u3001\u53EF\u80FD\u7559\u767D\uFF1B\u526A\u88C1\uFF1D\u94FA\u6EE1\u6846\u5E76\u6309\u300C\u88C1\u526A\u951A\u70B9\u300D\u53D6\u4E00\u5757\uFF1B\u62C9\u4F38\uFF1D\u586B\u6EE1\u6846\u4F1A\u53D8\u5F62\uFF1B\u539F\u59CB\u5C3A\u5BF8\u4E0E\u7F29\u5C0F\u4E0D\u653E\u5927\u3002\u753B\u5E03\u4E0E\u4E09\u6761\u51FA\u7EB8\u94FE\u8DEF\u540C\u4E00\u53E3\u5F84\uFF08\u7F3A\u7701\u5305\u542B\uFF09"
1046
1110
  },
1047
1111
  {
1048
1112
  key: "ap-img-object-position",
1049
- keywords: ["\u88C1\u526A\u951A\u70B9", "\u951A\u70B9", "objectposition", "object-position", "\u5BF9\u9F50\u70B9", "\u4E0A\u79FB", "\u5934\u9876"],
1050
- tip: "\u88C1\u526A\u65F6\u4FDD\u7559\u6846\u5185\u7684\u54EA\u4E00\u90E8\u5206\uFF0CCSS object-position \u503C\u539F\u6837\u751F\u6548\uFF08\u5982 center 20% \u8BA9\u753B\u9762\u4E0A\u79FB\u3001\u4FDD\u4F4F\u8BC1\u4EF6\u7167\u5934\u9876\uFF09\uFF1B\u53EA\u5728\u53D1\u751F\u88C1\u5207\u65F6\u53EF\u89C1\uFF0C\u7F3A\u7701\u6309 50% 50% \u5C45\u4E2D\u3002\u542B\u5206\u53F7\u3001\u5F15\u53F7\u3001url() \u7684\u503C\u4F1A\u88AB\u6574\u6761\u4E22\u5F03"
1113
+ keywords: ["\u88C1\u526A\u951A\u70B9", "\u526A\u88C1\u951A\u70B9", "\u951A\u70B9", "objectposition", "object-position", "\u5BF9\u9F50\u70B9", "\u4E0A\u79FB", "\u5934\u9876"],
1114
+ tip: "\u53D6\u4F4D\uFF08\u4EC5\u300C\u526A\u88C1\u300D\u6863\u6709\u8FD9\u4E00\u884C\uFF09\uFF1A\u526A\u88C1\u628A\u56FE\u7B49\u6BD4\u94FA\u6EE1\u5143\u7D20\u6846\uFF0C\u591A\u51FA\u6765\u7684\u90A3\u4E00\u6761\u8FB9\u6309\u8FD9\u91CC\u9009\u7684\u4F4D\u7F6E\u53D6\u820D\u3002\u5148\u9009\u4F4D\u7F6E\u6863\uFF08\u8D34\u8FB9\uFF0F\u5C45\u4E2D\uFF0F\u8D34\u53E6\u4E00\u5934\uFF09\uFF0C\u518D\u6309\u767E\u5206\u6BD4\u5FAE\u8C03\uFF0C0 \u8D34\u5DE6\uFF0F\u8D34\u9876\uFF0C100 \u632A\u5230\u53E6\u4E00\u5934\uFF0C\u6C34\u5E73\u4E0E\u5782\u76F4\u5404\u81EA\u72EC\u7ACB\uFF1B\u7F3A\u7701\u53D6\u6B63\u4E2D\u95F4\uFF08\u4FDD\u4F4F\u8BC1\u4EF6\u7167\u5934\u9876\u5C31\u9009\u9876\u90E8\uFF09\u3002\u5176\u4F59\u7F29\u653E\u6A21\u5F0F\u56FE\u6BD4\u6846\u5C0F\u6216\u521A\u597D\u94FA\u6EE1\uFF0C\u6CA1\u6709\u53EF\u88C1\u7684\u8FB9\uFF0C\u6240\u4EE5\u4E0D\u51FA\u672C\u884C"
1115
+ },
1116
+ {
1117
+ key: "ap-img-fit-scale",
1118
+ keywords: ["\u653E\u5927\u6BD4\u4F8B", "\u526A\u88C1\u653E\u5927", "\u653E\u5927\u500D\u6570", "\u53D6\u666F", "\u88C1\u5207\u8303\u56F4", "fitscale", "zoom"],
1119
+ tip: "\u526A\u88C1\u653E\u5927\uFF1A\u7B49\u6BD4\u94FA\u6EE1\u4E4B\u540E\u628A\u753B\u9762\u518D\u63A8\u5927\u8FD9\u4E48\u591A\uFF0C\u4E24\u8F74\u624D\u771F\u7684\u5404\u591A\u51FA\u4E00\u6761\u8FB9\u53EF\u88C1\u2014\u2014\u56FE\u4E0E\u6846\u540C\u6BD4\u4F8B\u65F6\u4E0D\u653E\u5927\u5C31\u4EC0\u4E48\u90FD\u88C1\u4E0D\u6389\u3002100\uFF1D\u4E0D\u653E\u5927\uFF08\u7F3A\u7701\uFF09\uFF0C\u4E0A\u9650 400\uFF1B\u8D85\u51FA\u6846\u7684\u90E8\u5206\u7531\u5143\u7D20\u6846\u88C1\u6389\u3002\u951A\u70B9\u9009\u4E2D\u7684\u90A3\u4E00\u70B9\u65E2\u662F\u53D6\u4F4D\u7684\u9489\u4F4F\u70B9\u3001\u4E5F\u662F\u653E\u5927\u7684\u4E2D\u5FC3\uFF0C\u4E24\u8005\u5171\u7528\u540C\u4E00\u4E2A\u503C\u3002\u4EC5\u300C\u526A\u88C1\u300D\u6863\u751F\u6548\uFF0C\u5176\u4F59\u7F29\u653E\u6A21\u5F0F\u4E0D\u51FA\u672C\u884C"
1051
1120
  }
1052
1121
  ]
1053
1122
  },
@@ -1149,194 +1218,6 @@ function searchProperties(search) {
1149
1218
  return { groups, itemKeys };
1150
1219
  }
1151
1220
 
1152
- // src/designer/utils/field-groups.ts
1153
- function groupFields(fields) {
1154
- const sorted = [...fields].sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
1155
- const groupMap = /* @__PURE__ */ new Map();
1156
- const groupOrder = [];
1157
- for (const f of sorted) {
1158
- const dot = f.fieldKey.indexOf(".");
1159
- if (dot === -1) continue;
1160
- const key = f.fieldKey.slice(0, dot);
1161
- let g = groupMap.get(key);
1162
- if (!g) {
1163
- g = { key, label: key, isList: false, fields: [] };
1164
- groupMap.set(key, g);
1165
- groupOrder.push(key);
1166
- }
1167
- g.fields.push(f);
1168
- }
1169
- const groups = [];
1170
- const standalone = [];
1171
- for (const f of sorted) {
1172
- if (f.fieldKey.includes(".")) continue;
1173
- const g = groupMap.get(f.fieldKey);
1174
- if (g) {
1175
- g.label = f.fieldLabel;
1176
- g.isList = f.fieldType === "list";
1177
- } else {
1178
- standalone.push(f);
1179
- }
1180
- }
1181
- if (standalone.length) groups.push({ key: "", label: "", isList: false, fields: standalone });
1182
- for (const key of groupOrder) groups.push(groupMap.get(key));
1183
- return groups;
1184
- }
1185
- function filterGroups(groups, keyword) {
1186
- const kw = keyword.trim().toLowerCase();
1187
- if (!kw) return groups;
1188
- return groups.map((g) => ({
1189
- ...g,
1190
- fields: g.fields.filter(
1191
- (f) => f.fieldLabel.toLowerCase().includes(kw) || f.fieldKey.toLowerCase().includes(kw)
1192
- )
1193
- })).filter((g) => g.fields.length > 0);
1194
- }
1195
-
1196
- // src/designer/utils/binding-registry.ts
1197
- var ELEMENT_BINDING_REGISTRY = {
1198
- text: [
1199
- { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1200
- ],
1201
- longText: [
1202
- { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" },
1203
- { targetPath: "options.styler", label: "\u6837\u5F0F", dataSource: "main" }
1204
- ],
1205
- barcode: [
1206
- { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1207
- ],
1208
- qrcode: [
1209
- { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1210
- ],
1211
- image: [
1212
- { targetPath: "options.src", label: "\u5185\u5BB9", dataSource: "main", placeholder: "\u8F93\u5165\u56FE\u7247\u8DEF\u5F84\uFF0C\u652F\u6301 /docfiles/... \u76F8\u5BF9\u8DEF\u5F84\u3001\u7EDD\u5BF9 URL \u6216 {\u5B57\u6BB5} \u8868\u8FBE\u5F0F" }
1213
- ],
1214
- table: []
1215
- };
1216
- function getTableCellBindings(rowType, rowIndex, cellIndex, listField) {
1217
- if (rowType === "data") {
1218
- return [{
1219
- targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1220
- label: "\u5185\u5BB9",
1221
- dataSource: "list",
1222
- listField,
1223
- placeholder: "{name}"
1224
- }];
1225
- }
1226
- if (rowType === "subtotal") {
1227
- return [{
1228
- targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1229
- label: "\u5185\u5BB9",
1230
- dataSource: "subtotal",
1231
- placeholder: "{MONEY(SUM(amount))}"
1232
- }];
1233
- }
1234
- if (rowType === "summary") {
1235
- return [{
1236
- targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1237
- label: "\u5185\u5BB9",
1238
- dataSource: "summary",
1239
- placeholder: "{MONEY(SUM(amount))}"
1240
- }];
1241
- }
1242
- return [{
1243
- targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1244
- label: "\u5185\u5BB9",
1245
- dataSource: "main",
1246
- placeholder: "\u5408\u8BA1: {order.total}"
1247
- }];
1248
- }
1249
- function getElementBindings(element) {
1250
- const type = element.printElementType.type;
1251
- const staticBindings = ELEMENT_BINDING_REGISTRY[type] ?? [];
1252
- const dynamicBindings = [];
1253
- if (type === "table") {
1254
- const listField = element.options.dataSource;
1255
- for (const [ri, row] of (element.options.tableRows ?? []).entries()) {
1256
- for (const [ci, cell] of row.cells.entries()) {
1257
- if (cell.merged) continue;
1258
- dynamicBindings.push(...getTableCellBindings(row.type, ri, ci, listField));
1259
- }
1260
- }
1261
- }
1262
- return [...staticBindings, ...dynamicBindings];
1263
- }
1264
-
1265
- // src/designer/utils/demo-data.ts
1266
- function getDemoData() {
1267
- return DEFAULT_DEMO_DATA;
1268
- }
1269
- var DEFAULT_DEMO_DATA = {
1270
- supplier: {
1271
- name: "\u946B\u8FBE\u4E94\u91D1\u6709\u9650\u516C\u53F8",
1272
- phone: "0571-88776655",
1273
- address: "\u676D\u5DDE\u5E02\u8427\u5C71\u533A\u7ECF\u6D4E\u5F00\u53D1\u533A88\u53F7"
1274
- },
1275
- receiver: {
1276
- name: "\u674E\u56DB",
1277
- phone: "13912345678",
1278
- address: "\u676D\u5DDE\u5E02\u4F59\u676D\u533A\u6587\u4E00\u897F\u8DEF998\u53F7"
1279
- },
1280
- order: {
1281
- no: "PO20260801001",
1282
- date: "2026-08-01",
1283
- total: 69543.75
1284
- },
1285
- // 50 条商品明细, 用于验证多页分页效果
1286
- goods: [
1287
- { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 100, price: 0.5, amount: 50, remark: "A\u7EA7" },
1288
- { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 117, price: 0.75, amount: 87.75, remark: "" },
1289
- { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 134, price: 1, amount: 134, remark: "" },
1290
- { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 151, price: 1.25, amount: 188.75, remark: "" },
1291
- { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 168, price: 1.5, amount: 252, remark: "" },
1292
- { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 185, price: 1.75, amount: 323.75, remark: "" },
1293
- { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 202, price: 2, amount: 404, remark: "" },
1294
- { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 219, price: 2.25, amount: 492.75, remark: "A\u7EA7" },
1295
- { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 236, price: 2.5, amount: 590, remark: "" },
1296
- { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 253, price: 2.75, amount: 695.75, remark: "" },
1297
- { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD720", unit: "\u4E2A", qty: 270, price: 3, amount: 810, remark: "" },
1298
- { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD721", unit: "\u5957", qty: 287, price: 3.25, amount: 932.75, remark: "" },
1299
- { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD722", unit: "\u76D2", qty: 304, price: 3.5, amount: 1064, remark: "" },
1300
- { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD723", unit: "\u652F", qty: 321, price: 3.75, amount: 1203.75, remark: "" },
1301
- { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD724", unit: "\u888B", qty: 338, price: 4, amount: 1352, remark: "A\u7EA7" },
1302
- { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD725", unit: "\u4EF6", qty: 355, price: 4.25, amount: 1508.75, remark: "" },
1303
- { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD726", unit: "\u6839", qty: 372, price: 4.5, amount: 1674, remark: "" },
1304
- { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD727", unit: "\u5305", qty: 389, price: 4.75, amount: 1847.75, remark: "" },
1305
- { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD728", unit: "\u53EA", qty: 406, price: 5, amount: 2030, remark: "" },
1306
- { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD729", unit: "\u7EC4", qty: 423, price: 5.25, amount: 2220.75, remark: "" },
1307
- { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD730", unit: "\u4E2A", qty: 440, price: 0.5, amount: 220, remark: "" },
1308
- { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD731", unit: "\u5957", qty: 457, price: 0.75, amount: 342.75, remark: "A\u7EA7" },
1309
- { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD732", unit: "\u76D2", qty: 474, price: 1, amount: 474, remark: "" },
1310
- { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD733", unit: "\u652F", qty: 491, price: 1.25, amount: 613.75, remark: "" },
1311
- { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD734", unit: "\u888B", qty: 508, price: 1.5, amount: 762, remark: "" },
1312
- { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD735", unit: "\u4EF6", qty: 525, price: 1.75, amount: 918.75, remark: "" },
1313
- { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD736", unit: "\u6839", qty: 542, price: 2, amount: 1084, remark: "" },
1314
- { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD737", unit: "\u5305", qty: 559, price: 2.25, amount: 1257.75, remark: "" },
1315
- { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD738", unit: "\u53EA", qty: 576, price: 2.5, amount: 1440, remark: "A\u7EA7" },
1316
- { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD739", unit: "\u7EC4", qty: 593, price: 2.75, amount: 1630.75, remark: "" },
1317
- { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD740", unit: "\u4E2A", qty: 610, price: 3, amount: 1830, remark: "" },
1318
- { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD741", unit: "\u5957", qty: 627, price: 3.25, amount: 2037.75, remark: "" },
1319
- { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD742", unit: "\u76D2", qty: 644, price: 3.5, amount: 2254, remark: "" },
1320
- { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD743", unit: "\u652F", qty: 661, price: 3.75, amount: 2478.75, remark: "" },
1321
- { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD744", unit: "\u888B", qty: 678, price: 4, amount: 2712, remark: "" },
1322
- { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD745", unit: "\u4EF6", qty: 695, price: 4.25, amount: 2953.75, remark: "A\u7EA7" },
1323
- { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD746", unit: "\u6839", qty: 712, price: 4.5, amount: 3204, remark: "" },
1324
- { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD747", unit: "\u5305", qty: 729, price: 4.75, amount: 3462.75, remark: "" },
1325
- { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD748", unit: "\u53EA", qty: 746, price: 5, amount: 3730, remark: "" },
1326
- { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD749", unit: "\u7EC4", qty: 763, price: 5.25, amount: 4005.75, remark: "" },
1327
- { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 780, price: 0.5, amount: 390, remark: "" },
1328
- { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 797, price: 0.75, amount: 597.75, remark: "" },
1329
- { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 814, price: 1, amount: 814, remark: "A\u7EA7" },
1330
- { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 831, price: 1.25, amount: 1038.75, remark: "" },
1331
- { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 848, price: 1.5, amount: 1272, remark: "" },
1332
- { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 865, price: 1.75, amount: 1513.75, remark: "" },
1333
- { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 882, price: 2, amount: 1764, remark: "" },
1334
- { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 899, price: 2.25, amount: 2022.75, remark: "" },
1335
- { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 916, price: 2.5, amount: 2290, remark: "" },
1336
- { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 933, price: 2.75, amount: 2565.75, remark: "A\u7EA7" }
1337
- ]
1338
- };
1339
-
1340
1221
  // src/lexer.ts
1341
1222
  var DANGEROUS_PROPS = /* @__PURE__ */ new Set([
1342
1223
  "constructor",
@@ -2048,55 +1929,55 @@ function formatDate(value, fmt) {
2048
1929
  const pad = (n) => String(n).padStart(2, "0");
2049
1930
  return fmt.replace("YYYY", String(date.getFullYear())).replace("MM", pad(date.getMonth() + 1)).replace("DD", pad(date.getDate())).replace("HH", pad(date.getHours())).replace("mm", pad(date.getMinutes())).replace("ss", pad(date.getSeconds()));
2050
1931
  }
1932
+ var CN_DIGITS = ["\u96F6", "\u58F9", "\u8D30", "\u53C1", "\u8086", "\u4F0D", "\u9646", "\u67D2", "\u634C", "\u7396"];
1933
+ var CN_UNITS = ["", "\u62FE", "\u4F70", "\u4EDF"];
1934
+ var CN_GROUP_UNITS = ["", "\u4E07", "\u4EBF", "\u4E07\u4EBF", "\u4EBF\u4EBF"];
1935
+ function fourDigitToCapital(n) {
1936
+ let out = "";
1937
+ let zeroPending = false;
1938
+ for (let pos = 3; pos >= 0; pos--) {
1939
+ const d = Math.floor(n / 10 ** pos) % 10;
1940
+ if (d === 0) {
1941
+ if (out) zeroPending = true;
1942
+ continue;
1943
+ }
1944
+ if (zeroPending) {
1945
+ out += "\u96F6";
1946
+ zeroPending = false;
1947
+ }
1948
+ out += CN_DIGITS[d] + CN_UNITS[pos];
1949
+ }
1950
+ return out;
1951
+ }
2051
1952
  function toUpperCaseAmount(value) {
2052
1953
  const num = Number(value);
2053
1954
  if (isNaN(num)) return String(value);
2054
1955
  if (num === 0) return "\u96F6\u5143\u6574";
2055
- const digits = ["\u96F6", "\u58F9", "\u8D30", "\u53C1", "\u8086", "\u4F0D", "\u9646", "\u67D2", "\u634C", "\u7396"];
2056
- const units = ["", "\u62FE", "\u4F70", "\u4EDF"];
2057
- const bigUnits = ["", "\u4E07", "\u4EBF"];
2058
1956
  const sign = num < 0 ? "\u8D1F" : "";
2059
- const abs = Math.abs(num);
2060
- const [intStr, decStr] = abs.toFixed(2).split(".");
2061
- const intNum = parseInt(intStr, 10);
1957
+ const [intStr, decStr] = Math.abs(num).toFixed(2).split(".");
1958
+ const groupCount = Math.ceil(intStr.length / 4);
2062
1959
  let result = "";
2063
- if (intNum > 0) {
2064
- const intChars = intStr.split("").reverse();
2065
- let groupIdx = 0;
2066
- let lastDigit = 0;
2067
- let needZero = false;
2068
- for (let i = 0; i < intChars.length; i++) {
2069
- const d = parseInt(intChars[i], 10);
2070
- const unit = units[groupIdx % 4];
2071
- const bigUnit = bigUnits[Math.floor(groupIdx / 4)];
2072
- if (d === 0) {
2073
- if (lastDigit !== 0) needZero = true;
2074
- } else {
2075
- if (needZero) {
2076
- result = "\u96F6" + result;
2077
- needZero = false;
2078
- }
2079
- result = digits[d] + unit + result;
2080
- lastDigit = d;
2081
- }
2082
- if (groupIdx % 4 === 3 && groupIdx > 0) {
2083
- result = bigUnit + result;
2084
- }
2085
- groupIdx++;
1960
+ let zeroPending = false;
1961
+ for (let groupIdx = groupCount - 1; groupIdx >= 0; groupIdx--) {
1962
+ const end = intStr.length - groupIdx * 4;
1963
+ const group = parseInt(intStr.slice(Math.max(0, end - 4), end), 10);
1964
+ if (group === 0) {
1965
+ if (result) zeroPending = true;
1966
+ continue;
2086
1967
  }
2087
- result += "\u5143";
1968
+ if (result && (zeroPending || group < 1e3)) result += "\u96F6";
1969
+ zeroPending = false;
1970
+ result += fourDigitToCapital(group) + (CN_GROUP_UNITS[groupIdx] ?? "");
2088
1971
  }
1972
+ result = `${result || "\u96F6"}\u5143`;
2089
1973
  const jiao = parseInt(decStr[0], 10);
2090
1974
  const fen = parseInt(decStr[1], 10);
2091
1975
  if (jiao === 0 && fen === 0) {
2092
1976
  result += "\u6574";
2093
1977
  } else {
2094
- if (jiao > 0) {
2095
- result += digits[jiao] + "\u89D2";
2096
- }
2097
- if (fen > 0) {
2098
- result += digits[fen] + "\u5206";
2099
- }
1978
+ if (jiao === 0) result += "\u96F6";
1979
+ else result += CN_DIGITS[jiao] + "\u89D2";
1980
+ if (fen > 0) result += CN_DIGITS[fen] + "\u5206";
2100
1981
  }
2101
1982
  return sign + result;
2102
1983
  }
@@ -2296,6 +2177,358 @@ function evaluateTemplate2(text, ctx) {
2296
2177
  }
2297
2178
  }
2298
2179
 
2180
+ // src/designer/utils/demo-data.ts
2181
+ function getDemoData() {
2182
+ return DEFAULT_DEMO_DATA;
2183
+ }
2184
+ var DEFAULT_DEMO_DATA = {
2185
+ supplier: {
2186
+ name: "\u946B\u8FBE\u4E94\u91D1\u6709\u9650\u516C\u53F8",
2187
+ phone: "0571-88776655",
2188
+ address: "\u676D\u5DDE\u5E02\u8427\u5C71\u533A\u7ECF\u6D4E\u5F00\u53D1\u533A88\u53F7"
2189
+ },
2190
+ receiver: {
2191
+ name: "\u674E\u56DB",
2192
+ phone: "13912345678",
2193
+ address: "\u676D\u5DDE\u5E02\u4F59\u676D\u533A\u6587\u4E00\u897F\u8DEF998\u53F7"
2194
+ },
2195
+ order: {
2196
+ no: "PO20260801001",
2197
+ date: "2026-08-01",
2198
+ total: 69543.75
2199
+ },
2200
+ // 50 条商品明细, 用于验证多页分页效果
2201
+ goods: [
2202
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 100, price: 0.5, amount: 50, remark: "A\u7EA7" },
2203
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 117, price: 0.75, amount: 87.75, remark: "" },
2204
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 134, price: 1, amount: 134, remark: "" },
2205
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 151, price: 1.25, amount: 188.75, remark: "" },
2206
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 168, price: 1.5, amount: 252, remark: "" },
2207
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 185, price: 1.75, amount: 323.75, remark: "" },
2208
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 202, price: 2, amount: 404, remark: "" },
2209
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 219, price: 2.25, amount: 492.75, remark: "A\u7EA7" },
2210
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 236, price: 2.5, amount: 590, remark: "" },
2211
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 253, price: 2.75, amount: 695.75, remark: "" },
2212
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD720", unit: "\u4E2A", qty: 270, price: 3, amount: 810, remark: "" },
2213
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD721", unit: "\u5957", qty: 287, price: 3.25, amount: 932.75, remark: "" },
2214
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD722", unit: "\u76D2", qty: 304, price: 3.5, amount: 1064, remark: "" },
2215
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD723", unit: "\u652F", qty: 321, price: 3.75, amount: 1203.75, remark: "" },
2216
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD724", unit: "\u888B", qty: 338, price: 4, amount: 1352, remark: "A\u7EA7" },
2217
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD725", unit: "\u4EF6", qty: 355, price: 4.25, amount: 1508.75, remark: "" },
2218
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD726", unit: "\u6839", qty: 372, price: 4.5, amount: 1674, remark: "" },
2219
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD727", unit: "\u5305", qty: 389, price: 4.75, amount: 1847.75, remark: "" },
2220
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD728", unit: "\u53EA", qty: 406, price: 5, amount: 2030, remark: "" },
2221
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD729", unit: "\u7EC4", qty: 423, price: 5.25, amount: 2220.75, remark: "" },
2222
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD730", unit: "\u4E2A", qty: 440, price: 0.5, amount: 220, remark: "" },
2223
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD731", unit: "\u5957", qty: 457, price: 0.75, amount: 342.75, remark: "A\u7EA7" },
2224
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD732", unit: "\u76D2", qty: 474, price: 1, amount: 474, remark: "" },
2225
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD733", unit: "\u652F", qty: 491, price: 1.25, amount: 613.75, remark: "" },
2226
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD734", unit: "\u888B", qty: 508, price: 1.5, amount: 762, remark: "" },
2227
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD735", unit: "\u4EF6", qty: 525, price: 1.75, amount: 918.75, remark: "" },
2228
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD736", unit: "\u6839", qty: 542, price: 2, amount: 1084, remark: "" },
2229
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD737", unit: "\u5305", qty: 559, price: 2.25, amount: 1257.75, remark: "" },
2230
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD738", unit: "\u53EA", qty: 576, price: 2.5, amount: 1440, remark: "A\u7EA7" },
2231
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD739", unit: "\u7EC4", qty: 593, price: 2.75, amount: 1630.75, remark: "" },
2232
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD740", unit: "\u4E2A", qty: 610, price: 3, amount: 1830, remark: "" },
2233
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD741", unit: "\u5957", qty: 627, price: 3.25, amount: 2037.75, remark: "" },
2234
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD742", unit: "\u76D2", qty: 644, price: 3.5, amount: 2254, remark: "" },
2235
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD743", unit: "\u652F", qty: 661, price: 3.75, amount: 2478.75, remark: "" },
2236
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD744", unit: "\u888B", qty: 678, price: 4, amount: 2712, remark: "" },
2237
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD745", unit: "\u4EF6", qty: 695, price: 4.25, amount: 2953.75, remark: "A\u7EA7" },
2238
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD746", unit: "\u6839", qty: 712, price: 4.5, amount: 3204, remark: "" },
2239
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD747", unit: "\u5305", qty: 729, price: 4.75, amount: 3462.75, remark: "" },
2240
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD748", unit: "\u53EA", qty: 746, price: 5, amount: 3730, remark: "" },
2241
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD749", unit: "\u7EC4", qty: 763, price: 5.25, amount: 4005.75, remark: "" },
2242
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 780, price: 0.5, amount: 390, remark: "" },
2243
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 797, price: 0.75, amount: 597.75, remark: "" },
2244
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 814, price: 1, amount: 814, remark: "A\u7EA7" },
2245
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 831, price: 1.25, amount: 1038.75, remark: "" },
2246
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 848, price: 1.5, amount: 1272, remark: "" },
2247
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 865, price: 1.75, amount: 1513.75, remark: "" },
2248
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 882, price: 2, amount: 1764, remark: "" },
2249
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 899, price: 2.25, amount: 2022.75, remark: "" },
2250
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 916, price: 2.5, amount: 2290, remark: "" },
2251
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 933, price: 2.75, amount: 2565.75, remark: "A\u7EA7" }
2252
+ ]
2253
+ };
2254
+
2255
+ // src/designer/utils/crop-anchor.ts
2256
+ var AXIS_X = { left: 0, center: 50, right: 100 };
2257
+ var AXIS_Y = { top: 0, center: 50, bottom: 100 };
2258
+ function clampPct(v) {
2259
+ if (!Number.isFinite(v)) return 50;
2260
+ return Math.round(Math.min(100, Math.max(0, v)));
2261
+ }
2262
+ function roundMm(v) {
2263
+ return Math.round(v * 100) / 100;
2264
+ }
2265
+ function buildCropAnchor(x, y) {
2266
+ const cx = clampPct(x);
2267
+ const cy = clampPct(y);
2268
+ if (cx === 50 && cy === 50) return void 0;
2269
+ return `${cx}% ${cy}%`;
2270
+ }
2271
+ function asPct(token) {
2272
+ return /^\d+(?:\.\d+)?%$/.test(token) ? parseFloat(token) : void 0;
2273
+ }
2274
+ function parseCropAnchor(value) {
2275
+ const raw = (value ?? "").trim();
2276
+ if (!raw) return { kind: "empty" };
2277
+ const tokens = raw.toLowerCase().split(/\s+/);
2278
+ let x;
2279
+ let y;
2280
+ for (let i = 0; i < tokens.length; i++) {
2281
+ const t = tokens[i];
2282
+ const pct = asPct(t);
2283
+ if (i === 0) {
2284
+ if (t in AXIS_X) x = AXIS_X[t];
2285
+ else if (pct !== void 0) x = pct;
2286
+ else if (t in AXIS_Y) y = AXIS_Y[t];
2287
+ else return { kind: "custom", raw: value };
2288
+ } else {
2289
+ if (t in AXIS_Y && y === void 0) y = AXIS_Y[t];
2290
+ else if (pct !== void 0 && x === void 0) x = pct;
2291
+ else if (pct !== void 0 && y === void 0) y = pct;
2292
+ else if (t in AXIS_X && x === void 0) x = AXIS_X[t];
2293
+ else return { kind: "custom", raw: value };
2294
+ }
2295
+ }
2296
+ return { kind: "axes", x: clampPct(x ?? 50), y: clampPct(y ?? 50) };
2297
+ }
2298
+ var MM_PER_PX2 = 25.4 / 96;
2299
+ function contentMm(box) {
2300
+ const { widthMm, heightMm, naturalWidth, naturalHeight } = box;
2301
+ if (!naturalWidth || !naturalHeight || !widthMm || !heightMm) return null;
2302
+ const k = widthMm / naturalWidth;
2303
+ const l = heightMm / naturalHeight;
2304
+ const zoom = (cropScalePct(box.fit, box.scalePct) ?? CROP_SCALE_MIN) / 100;
2305
+ switch (box.fit || "contain") {
2306
+ // 拉伸填满:图被钉成框,两轴都挪不动(放大比例只给剪裁档,这里不受影响)
2307
+ case "fill":
2308
+ return { w: widthMm, h: heightMm };
2309
+ case "cover": {
2310
+ const s = Math.max(k, l) * zoom;
2311
+ return { w: naturalWidth * s, h: naturalHeight * s };
2312
+ }
2313
+ // 原始尺寸不缩放:按图片内在像素尺寸绘制
2314
+ case "none":
2315
+ return { w: naturalWidth * MM_PER_PX2, h: naturalHeight * MM_PER_PX2 };
2316
+ case "scale-down": {
2317
+ const s = Math.min(1, Math.min(k, l));
2318
+ return { w: naturalWidth * s, h: naturalHeight * s };
2319
+ }
2320
+ default: {
2321
+ const s = Math.min(k, l);
2322
+ return { w: naturalWidth * s, h: naturalHeight * s };
2323
+ }
2324
+ }
2325
+ }
2326
+ function resolveCropTravel(box) {
2327
+ const c = contentMm(box);
2328
+ if (!c) return { x: null, y: null };
2329
+ return {
2330
+ x: roundMm(Math.abs(box.widthMm - c.w)),
2331
+ y: roundMm(Math.abs(box.heightMm - c.h))
2332
+ };
2333
+ }
2334
+ function cropWindow(box, x, y) {
2335
+ const c = contentMm(box);
2336
+ if (!c) return null;
2337
+ const fx = Math.min(1, box.widthMm / c.w);
2338
+ const fy = Math.min(1, box.heightMm / c.h);
2339
+ return {
2340
+ leftPct: (1 - fx) * clampPct(x),
2341
+ topPct: (1 - fy) * clampPct(y),
2342
+ widthPct: fx * 100,
2343
+ heightPct: fy * 100
2344
+ };
2345
+ }
2346
+ function resolveDesignImageSrc(raw) {
2347
+ const value = String(raw ?? "");
2348
+ if (!value) return "";
2349
+ return value.includes("{") ? String(evaluateTemplate2(value, DEFAULT_DEMO_DATA)) : value;
2350
+ }
2351
+ var CROP_AXIS_OPTIONS = {
2352
+ vertical: [
2353
+ { value: 0, label: "\u9876\u90E8" },
2354
+ { value: 50, label: "\u5C45\u4E2D" },
2355
+ { value: 100, label: "\u5E95\u90E8" }
2356
+ ],
2357
+ horizontal: [
2358
+ { value: 0, label: "\u5DE6\u4FA7" },
2359
+ { value: 50, label: "\u5C45\u4E2D" },
2360
+ { value: 100, label: "\u53F3\u4FA7" }
2361
+ ]
2362
+ };
2363
+ var CROP_GRID_OPTIONS = [
2364
+ { x: 0, y: 0, label: "\u5DE6\u4E0A" },
2365
+ { x: 50, y: 0, label: "\u4E0A\u4E2D" },
2366
+ { x: 100, y: 0, label: "\u53F3\u4E0A" },
2367
+ { x: 0, y: 50, label: "\u5DE6\u4E2D" },
2368
+ { x: 50, y: 50, label: "\u5C45\u4E2D" },
2369
+ { x: 100, y: 50, label: "\u53F3\u4E2D" },
2370
+ { x: 0, y: 100, label: "\u5DE6\u4E0B" },
2371
+ { x: 50, y: 100, label: "\u4E0B\u4E2D" },
2372
+ { x: 100, y: 100, label: "\u53F3\u4E0B" }
2373
+ ];
2374
+ var IMAGE_FIT_OPTIONS = [
2375
+ { value: "contain", label: "\u5305\u542B\uFF08\u4FDD\u6301\u6BD4\u4F8B\uFF09" },
2376
+ { value: "cover", label: "\u526A\u88C1\uFF08\u7B49\u6BD4\u94FA\u6EE1\u540E\u88C1\u8FB9\uFF09" },
2377
+ { value: "fill", label: "\u62C9\u4F38\u586B\u6EE1" },
2378
+ { value: "none", label: "\u539F\u59CB\u5C3A\u5BF8" },
2379
+ { value: "scale-down", label: "\u7F29\u5C0F\uFF08\u4FDD\u6301\u6BD4\u4F8B\uFF09" }
2380
+ ];
2381
+ var CROP_SAMPLE_IMAGE = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTIwIDEyMCI+PHJlY3Qgd2lkdGg9IjEyMCIgaGVpZ2h0PSIxMjAiIGZpbGw9IiNmZmZmZmYiLz48cGF0aCBkPSJNNDAgMFYxMjBNODAgMFYxMjBNMCA0MEgxMjBNMCA4MEgxMjAiIHN0cm9rZT0iI2VlZjFmNiIgc3Ryb2tlLXdpZHRoPSIxIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIyMCIgcj0iMy41IiBmaWxsPSIjOGI5NWE1Ii8+PGNpcmNsZSBjeD0iMTAwIiBjeT0iMjAiIHI9IjMuNSIgZmlsbD0iIzhiOTVhNSIvPjxjaXJjbGUgY3g9IjIwIiBjeT0iMTAwIiByPSIzLjUiIGZpbGw9IiM4Yjk1YTUiLz48Y2lyY2xlIGN4PSIxMDAiIGN5PSIxMDAiIHI9IjMuNSIgZmlsbD0iIzhiOTVhNSIvPjxjaXJjbGUgY3g9IjYwIiBjeT0iMjAiIHI9IjciIGZpbGw9IiNjMDM5MmIiLz48Y2lyY2xlIGN4PSI2MCIgY3k9IjEwMCIgcj0iNyIgZmlsbD0iIzFmNGZhMyIvPjxjaXJjbGUgY3g9IjIwIiBjeT0iNjAiIHI9IjciIGZpbGw9IiMyYzdhNGEiLz48Y2lyY2xlIGN4PSIxMDAiIGN5PSI2MCIgcj0iNyIgZmlsbD0iI2UwN2EyMCIvPjxjaXJjbGUgY3g9IjYwIiBjeT0iNjAiIHI9IjE0IiBmaWxsPSJub25lIiBzdHJva2U9IiMyZjNhNGEiIHN0cm9rZS13aWR0aD0iNCIvPjxjaXJjbGUgY3g9IjYwIiBjeT0iNjAiIHI9IjYiIGZpbGw9IiMyZjNhNGEiLz48L3N2Zz4=";
2382
+ var CROP_SAMPLE_NOTE = "\u56FE\u7247\u8FD8\u6CA1\u8BBE\u7F6E\uFF0C\u4E0A\u9762\u6309\u5185\u7F6E\u793A\u4F8B\u56FE\u6F14\u793A\u53D6\u4F4D\uFF1B\u6362\u4E0A\u771F\u56FE\u540E\u6863\u4F4D\u4E0E\u53EF\u632A\u91CF\u6309\u771F\u56FE\u91CD\u7B97";
2383
+ function resolveCropPreview(resolvedSrc) {
2384
+ const value = String(resolvedSrc ?? "").trim();
2385
+ if (!value || value.includes("{") || value.includes("}")) return { src: CROP_SAMPLE_IMAGE, isSample: true };
2386
+ return { src: value, isSample: false };
2387
+ }
2388
+ function cropAxisLabel(axis) {
2389
+ return axis === "vertical" ? "\u5782\u76F4\u4F4D\u7F6E (%)" : "\u6C34\u5E73\u4F4D\u7F6E (%)";
2390
+ }
2391
+ var CROP_SCALE_LABEL = "\u653E\u5927\u6BD4\u4F8B (%)";
2392
+ function cropAxisNote(travel, keepRaw = false) {
2393
+ if (keepRaw) return "\u5DF2\u4FDD\u7559\u6A21\u677F\u91CC\u7684\u539F\u503C\uFF1B\u6539\u52A8\u4E0B\u9762\u4EFB\u4E00\u9879\u5C31\u6574\u4F53\u66FF\u6362\u6210\u65B0\u7684\u53D6\u4F4D";
2394
+ const { x, y } = travel;
2395
+ if (x === null || y === null) return "";
2396
+ if (x > 0 && y > 0) return `\u6C34\u5E73\u53EF\u632A ${x}mm\u3001\u5782\u76F4\u53EF\u632A ${y}mm\uFF1A0 \u8D34\u5DE6\uFF0F\u8D34\u9876\uFF0C100 \u8D34\u53F3\uFF0F\u8D34\u5E95`;
2397
+ if (x > 0) return `\u6C34\u5E73\u53EF\u632A ${x}mm\uFF1B\u5782\u76F4\u8FD9\u4E00\u8F74\u5DF2\u8D34\u6EE1\uFF0C\u632A\u4E0D\u52A8`;
2398
+ if (y > 0) return `\u5782\u76F4\u53EF\u632A ${y}mm\uFF1B\u6C34\u5E73\u8FD9\u4E00\u8F74\u5DF2\u8D34\u6EE1\uFF0C\u632A\u4E0D\u52A8`;
2399
+ return "\u8FD9\u4E2A\u7F29\u653E\u4E0B\u56FE\u4E0E\u6846\u6B63\u597D\u4E00\u6837\u5927\uFF0C\u4E24\u8F74\u90FD\u6CA1\u6709\u53EF\u632A\u7684\u4F59\u91CF";
2400
+ }
2401
+ function cropAxisFields(travel, x, y) {
2402
+ return [
2403
+ { name: "horizontal", label: cropAxisLabel("horizontal"), value: x, travelMm: travel.x },
2404
+ { name: "vertical", label: cropAxisLabel("vertical"), value: y, travelMm: travel.y }
2405
+ ];
2406
+ }
2407
+ function cropPresetOptions(travel, x, y) {
2408
+ const movX = travel.x !== null && travel.x > 0;
2409
+ const movY = travel.y !== null && travel.y > 0;
2410
+ if (movY && !movX) {
2411
+ return CROP_AXIS_OPTIONS.vertical.map((o) => ({ value: `${x},${o.value}`, label: o.label }));
2412
+ }
2413
+ if (movX && !movY) {
2414
+ return CROP_AXIS_OPTIONS.horizontal.map((o) => ({ value: `${o.value},${y}`, label: o.label }));
2415
+ }
2416
+ return CROP_GRID_OPTIONS.map((o) => ({ value: `${o.x},${o.y}`, label: o.label }));
2417
+ }
2418
+
2419
+ // src/designer/utils/field-groups.ts
2420
+ function groupFields(fields) {
2421
+ const sorted = [...fields].sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
2422
+ const groupMap = /* @__PURE__ */ new Map();
2423
+ const groupOrder = [];
2424
+ for (const f of sorted) {
2425
+ const dot = f.fieldKey.indexOf(".");
2426
+ if (dot === -1) continue;
2427
+ const key = f.fieldKey.slice(0, dot);
2428
+ let g = groupMap.get(key);
2429
+ if (!g) {
2430
+ g = { key, label: key, isList: false, fields: [] };
2431
+ groupMap.set(key, g);
2432
+ groupOrder.push(key);
2433
+ }
2434
+ g.fields.push(f);
2435
+ }
2436
+ const groups = [];
2437
+ const standalone = [];
2438
+ for (const f of sorted) {
2439
+ if (f.fieldKey.includes(".")) continue;
2440
+ const g = groupMap.get(f.fieldKey);
2441
+ if (g) {
2442
+ g.label = f.fieldLabel;
2443
+ g.isList = f.fieldType === "list";
2444
+ } else {
2445
+ standalone.push(f);
2446
+ }
2447
+ }
2448
+ if (standalone.length) groups.push({ key: "", label: "", isList: false, fields: standalone });
2449
+ for (const key of groupOrder) groups.push(groupMap.get(key));
2450
+ return groups;
2451
+ }
2452
+ function filterGroups(groups, keyword) {
2453
+ const kw = keyword.trim().toLowerCase();
2454
+ if (!kw) return groups;
2455
+ return groups.map((g) => ({
2456
+ ...g,
2457
+ fields: g.fields.filter(
2458
+ (f) => f.fieldLabel.toLowerCase().includes(kw) || f.fieldKey.toLowerCase().includes(kw)
2459
+ )
2460
+ })).filter((g) => g.fields.length > 0);
2461
+ }
2462
+
2463
+ // src/designer/utils/binding-registry.ts
2464
+ var ELEMENT_BINDING_REGISTRY = {
2465
+ text: [
2466
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
2467
+ ],
2468
+ longText: [
2469
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" },
2470
+ { targetPath: "options.styler", label: "\u6837\u5F0F", dataSource: "main" }
2471
+ ],
2472
+ barcode: [
2473
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
2474
+ ],
2475
+ qrcode: [
2476
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
2477
+ ],
2478
+ image: [
2479
+ { targetPath: "options.src", label: "\u5185\u5BB9", dataSource: "main", placeholder: "\u8F93\u5165\u56FE\u7247\u8DEF\u5F84\uFF0C\u652F\u6301 /docfiles/... \u76F8\u5BF9\u8DEF\u5F84\u3001\u7EDD\u5BF9 URL \u6216 {\u5B57\u6BB5} \u8868\u8FBE\u5F0F" }
2480
+ ],
2481
+ table: []
2482
+ };
2483
+ function getTableCellBindings(rowType, rowIndex, cellIndex, listField) {
2484
+ if (rowType === "data") {
2485
+ return [{
2486
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
2487
+ label: "\u5185\u5BB9",
2488
+ dataSource: "list",
2489
+ listField,
2490
+ placeholder: "{name}"
2491
+ }];
2492
+ }
2493
+ if (rowType === "subtotal") {
2494
+ return [{
2495
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
2496
+ label: "\u5185\u5BB9",
2497
+ dataSource: "subtotal",
2498
+ placeholder: "{MONEY(SUM(amount))}"
2499
+ }];
2500
+ }
2501
+ if (rowType === "summary") {
2502
+ return [{
2503
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
2504
+ label: "\u5185\u5BB9",
2505
+ dataSource: "summary",
2506
+ placeholder: "{MONEY(SUM(amount))}"
2507
+ }];
2508
+ }
2509
+ return [{
2510
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
2511
+ label: "\u5185\u5BB9",
2512
+ dataSource: "main",
2513
+ placeholder: "\u5408\u8BA1: {order.total}"
2514
+ }];
2515
+ }
2516
+ function getElementBindings(element) {
2517
+ const type = element.printElementType.type;
2518
+ const staticBindings = ELEMENT_BINDING_REGISTRY[type] ?? [];
2519
+ const dynamicBindings = [];
2520
+ if (type === "table") {
2521
+ const listField = element.options.dataSource;
2522
+ for (const [ri, row] of (element.options.tableRows ?? []).entries()) {
2523
+ for (const [ci, cell] of row.cells.entries()) {
2524
+ if (cell.merged) continue;
2525
+ dynamicBindings.push(...getTableCellBindings(row.type, ri, ci, listField));
2526
+ }
2527
+ }
2528
+ }
2529
+ return [...staticBindings, ...dynamicBindings];
2530
+ }
2531
+
2299
2532
  // src/designer/utils/binding.ts
2300
2533
  function createFieldElement(field) {
2301
2534
  return createRuntimeElement("text", {
@@ -2825,6 +3058,13 @@ function useBindingDisplay() {
2825
3058
  BARCODE_MODULE_WIDTH_MM,
2826
3059
  BARCODE_QUIET_ZONE_MODULES,
2827
3060
  BARCODE_TEXT_FONT_SIZE_MODULES,
3061
+ CROP_AXIS_OPTIONS,
3062
+ CROP_GRID_OPTIONS,
3063
+ CROP_SAMPLE_IMAGE,
3064
+ CROP_SAMPLE_NOTE,
3065
+ CROP_SCALE_LABEL,
3066
+ CROP_SCALE_MAX,
3067
+ CROP_SCALE_MIN,
2828
3068
  DEFAULT_DEMO_DATA,
2829
3069
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
2830
3070
  ELEMENT_BINDING_REGISTRY,
@@ -2832,6 +3072,7 @@ function useBindingDisplay() {
2832
3072
  EXTENDED_FUNCTIONS,
2833
3073
  FIT_SCALE_MIN_PERCENT,
2834
3074
  GHOST_BORDER_CSS,
3075
+ IMAGE_FIT_OPTIONS,
2835
3076
  LABEL_PAPER_GROUP,
2836
3077
  MIN_COL_WIDTH_MM,
2837
3078
  MIN_SCALE_PERCENT,
@@ -2848,12 +3089,14 @@ function useBindingDisplay() {
2848
3089
  barcodeAvailableBoxMm,
2849
3090
  barcodePreferredModuleWidthMm,
2850
3091
  barcodeUnitsPerModule,
3092
+ buildCropAnchor,
2851
3093
  buildRulerTicks,
2852
3094
  calcResizeRect,
2853
3095
  canMergeReason,
2854
3096
  cellFitCapMm,
2855
3097
  cellFitKey,
2856
3098
  cellFitWidthMm,
3099
+ cellImageBoxMm,
2857
3100
  chooseMajorStepMM,
2858
3101
  clampResizedColumnWidth,
2859
3102
  clampScalePercent,
@@ -2865,6 +3108,13 @@ function useBindingDisplay() {
2865
3108
  createDefaultTable,
2866
3109
  createFieldElement,
2867
3110
  createRuntimeElement,
3111
+ cropAxisFields,
3112
+ cropAxisLabel,
3113
+ cropAxisNote,
3114
+ cropPresetOptions,
3115
+ cropScalePct,
3116
+ cropStyleDeclarations,
3117
+ cropWindow,
2868
3118
  deleteCol,
2869
3119
  deleteRow,
2870
3120
  engine,
@@ -2896,6 +3146,7 @@ function useBindingDisplay() {
2896
3146
  normalizeSelection,
2897
3147
  normalizeTemplateUnits,
2898
3148
  parseCellFitKey,
3149
+ parseCropAnchor,
2899
3150
  propertyTip,
2900
3151
  ptToMm,
2901
3152
  pxToMm,
@@ -2903,13 +3154,18 @@ function useBindingDisplay() {
2903
3154
  resolveBarcodeSize,
2904
3155
  resolveCellBorderCss,
2905
3156
  resolveCellTextFit,
3157
+ resolveCropPreview,
3158
+ resolveCropTravel,
3159
+ resolveDesignImageSrc,
2906
3160
  resolveElementBorder,
2907
3161
  resolveElementTextFit,
3162
+ resolveOverlayPlacement,
2908
3163
  resolveShrinkMinFontSize,
2909
3164
  resolveTextBinding,
2910
3165
  resolveToolbarOverflow,
2911
3166
  roundFontSize,
2912
3167
  safeEval,
3168
+ sanitizeObjectPosition,
2913
3169
  searchProperties,
2914
3170
  setHeaderRepeat,
2915
3171
  setRowType,