@worm-vue3-print/core 1.3.0 → 1.3.2
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.
- package/dist/browser/index.cjs +300 -63
- package/dist/browser/index.d.cts +2 -2
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.js +1 -1
- package/dist/{chunk-V4A5623C.js → chunk-B2XJSF4V.js} +1 -1
- package/dist/{chunk-VFEURLAZ.js → chunk-BBSFBAWT.js} +308 -63
- package/dist/client/index.cjs +381 -0
- package/dist/client/index.d.cts +241 -0
- package/dist/client/index.d.ts +241 -0
- package/dist/client/index.js +346 -0
- package/dist/designer/index.cjs +196 -11
- package/dist/designer/index.d.cts +21 -6
- package/dist/designer/index.d.ts +21 -6
- package/dist/designer/index.js +35 -4
- package/dist/{driver-CsWkGK4a.d.cts → driver-Dn_YAzO5.d.cts} +4 -1
- package/dist/{driver-CsWkGK4a.d.ts → driver-Dn_YAzO5.d.ts} +4 -1
- package/dist/index.cjs +316 -63
- package/dist/index.d.cts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +18 -2
- package/dist/node/index.d.cts +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/{ports-B63x7kCX.d.ts → ports-BvwlA_km.d.ts} +1 -1
- package/dist/{ports-q934kIC7.d.cts → ports-Cf5sjwls.d.cts} +1 -1
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,7 @@ __export(index_exports, {
|
|
|
40
40
|
TilingError: () => TilingError,
|
|
41
41
|
WATERMARK_DEFAULTS: () => WATERMARK_DEFAULTS,
|
|
42
42
|
WATERMARK_DENSITY_PRESETS: () => WATERMARK_DENSITY_PRESETS,
|
|
43
|
+
addNumbers: () => addNumbers,
|
|
43
44
|
applyTextFitSizes: () => applyTextFitSizes,
|
|
44
45
|
avg: () => avg,
|
|
45
46
|
bindData: () => bindData,
|
|
@@ -64,6 +65,7 @@ __export(index_exports, {
|
|
|
64
65
|
createCollectingCodeRenderer: () => createCollectingCodeRenderer,
|
|
65
66
|
createDomHostRuntime: () => createDomHostRuntime,
|
|
66
67
|
createMapCodeRenderer: () => createMapCodeRenderer,
|
|
68
|
+
divideNumbers: () => divideNumbers,
|
|
67
69
|
elementPositionStyle: () => elementPositionStyle,
|
|
68
70
|
escapeHeightMm: () => escapeHeightMm,
|
|
69
71
|
escapeInlineStyleValue: () => escapeInlineStyleValue,
|
|
@@ -91,6 +93,7 @@ __export(index_exports, {
|
|
|
91
93
|
min: () => min,
|
|
92
94
|
mm: () => mm,
|
|
93
95
|
mmToPx: () => mmToPx,
|
|
96
|
+
multiplyNumbers: () => multiplyNumbers,
|
|
94
97
|
normalizeMeasurements: () => normalizeMeasurements,
|
|
95
98
|
normalizePrintData: () => normalizePrintData,
|
|
96
99
|
normalizeTemplate: () => normalizeTemplate,
|
|
@@ -115,11 +118,16 @@ __export(index_exports, {
|
|
|
115
118
|
resolveSystemVariables: () => resolveSystemVariables,
|
|
116
119
|
resolveWatermarkLayout: () => resolveWatermarkLayout,
|
|
117
120
|
resolveWatermarkText: () => resolveWatermarkText,
|
|
121
|
+
round: () => round,
|
|
122
|
+
roundDown: () => roundDown,
|
|
118
123
|
roundFontSize: () => roundFontSize,
|
|
124
|
+
roundHalfEven: () => roundHalfEven,
|
|
119
125
|
roundMm: () => roundMm,
|
|
126
|
+
roundUp: () => roundUp,
|
|
120
127
|
safeEval: () => safeEval,
|
|
121
128
|
setPageIndex: () => setPageIndex,
|
|
122
129
|
setTotalPages: () => setTotalPages,
|
|
130
|
+
subtractNumbers: () => subtractNumbers,
|
|
123
131
|
sum: () => sum,
|
|
124
132
|
systemVars: () => systemVars,
|
|
125
133
|
tableDesignBottom: () => tableDesignBottom,
|
|
@@ -477,6 +485,113 @@ var Parser = class {
|
|
|
477
485
|
}
|
|
478
486
|
};
|
|
479
487
|
|
|
488
|
+
// src/numeric.ts
|
|
489
|
+
var MAX_DIGITS = 20;
|
|
490
|
+
var EXTRA_SCALE = 8;
|
|
491
|
+
function toNumber(value, fallback = 0) {
|
|
492
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : fallback;
|
|
493
|
+
if (typeof value === "string") {
|
|
494
|
+
const s = value.trim();
|
|
495
|
+
if (s === "") return fallback;
|
|
496
|
+
const n = Number(s);
|
|
497
|
+
return Number.isFinite(n) ? n : fallback;
|
|
498
|
+
}
|
|
499
|
+
if (value == null) return fallback;
|
|
500
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
501
|
+
return fallback;
|
|
502
|
+
}
|
|
503
|
+
function isNumericLike(value) {
|
|
504
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
505
|
+
if (typeof value === "string") {
|
|
506
|
+
const s = value.trim();
|
|
507
|
+
return s !== "" && Number.isFinite(Number(s));
|
|
508
|
+
}
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
function normalizeFloat(value) {
|
|
512
|
+
if (!Number.isFinite(value) || Number.isInteger(value)) return value;
|
|
513
|
+
if (Math.abs(value) >= 1e15) return value;
|
|
514
|
+
return Number(value.toPrecision(12));
|
|
515
|
+
}
|
|
516
|
+
function decimalsOf(n) {
|
|
517
|
+
if (!Number.isFinite(n) || Number.isInteger(n)) return 0;
|
|
518
|
+
const s = String(n);
|
|
519
|
+
if (s.includes("e") || s.includes("E")) return 0;
|
|
520
|
+
const i = s.indexOf(".");
|
|
521
|
+
return i === -1 ? 0 : s.length - i - 1;
|
|
522
|
+
}
|
|
523
|
+
function rescale(value, decimals) {
|
|
524
|
+
if (!Number.isFinite(value)) return 0;
|
|
525
|
+
const d = Math.min(Math.max(decimals, 0), 12);
|
|
526
|
+
if (d === 0) return Math.round(value);
|
|
527
|
+
const f = 10 ** d;
|
|
528
|
+
const scaled = value * f;
|
|
529
|
+
if (!Number.isFinite(scaled) || Math.abs(scaled) >= 1e15) return normalizeFloat(value);
|
|
530
|
+
return Math.round(scaled) / f;
|
|
531
|
+
}
|
|
532
|
+
function decimalAdd(left, right) {
|
|
533
|
+
const a = toNumber(left);
|
|
534
|
+
const b = toNumber(right);
|
|
535
|
+
const raw = a + b;
|
|
536
|
+
return rescale(raw, Math.max(decimalsOf(a), decimalsOf(b)));
|
|
537
|
+
}
|
|
538
|
+
function decimalSubtract(left, right) {
|
|
539
|
+
const a = toNumber(left);
|
|
540
|
+
const b = toNumber(right);
|
|
541
|
+
const raw = a - b;
|
|
542
|
+
return rescale(raw, Math.max(decimalsOf(a), decimalsOf(b)));
|
|
543
|
+
}
|
|
544
|
+
function decimalMultiply(left, right) {
|
|
545
|
+
const a = toNumber(left);
|
|
546
|
+
const b = toNumber(right);
|
|
547
|
+
const raw = a * b;
|
|
548
|
+
return rescale(raw, decimalsOf(a) + decimalsOf(b));
|
|
549
|
+
}
|
|
550
|
+
function decimalDivide(left, right) {
|
|
551
|
+
const a = toNumber(left);
|
|
552
|
+
const b = toNumber(right);
|
|
553
|
+
if (b === 0) return 0;
|
|
554
|
+
return normalizeFloat(a / b);
|
|
555
|
+
}
|
|
556
|
+
function decimalModulo(left, right) {
|
|
557
|
+
const a = toNumber(left);
|
|
558
|
+
const b = toNumber(right);
|
|
559
|
+
if (b === 0) return 0;
|
|
560
|
+
return normalizeFloat(a % b);
|
|
561
|
+
}
|
|
562
|
+
function normalizeDigits(digits) {
|
|
563
|
+
if (digits === void 0 || digits === null) return 2;
|
|
564
|
+
const d = Math.trunc(toNumber(digits, 2));
|
|
565
|
+
if (!Number.isFinite(d)) return 2;
|
|
566
|
+
return Math.min(Math.max(d, -MAX_DIGITS), MAX_DIGITS);
|
|
567
|
+
}
|
|
568
|
+
function roundTo(value, digits, mode) {
|
|
569
|
+
const n = toNumber(value, 0);
|
|
570
|
+
const d = normalizeDigits(digits);
|
|
571
|
+
if (n === 0) return 0;
|
|
572
|
+
if (Math.abs(n) >= 1e21) return normalizeFloat(n);
|
|
573
|
+
const scale = Math.max(d, 0) + EXTRA_SCALE;
|
|
574
|
+
const fixed = n.toFixed(scale);
|
|
575
|
+
if (!/^-?\d+(\.\d+)?$/.test(fixed)) return normalizeFloat(n);
|
|
576
|
+
const negative = fixed.startsWith("-");
|
|
577
|
+
const digitsStr = fixed.replace("-", "").replace(".", "");
|
|
578
|
+
let scaled = BigInt(digitsStr || "0");
|
|
579
|
+
if (negative) scaled = -scaled;
|
|
580
|
+
const pow10 = 10n ** BigInt(scale - d);
|
|
581
|
+
const sign = scaled < 0n ? -1n : 1n;
|
|
582
|
+
const abs = scaled < 0n ? -scaled : scaled;
|
|
583
|
+
let q = abs / pow10;
|
|
584
|
+
const r = abs % pow10;
|
|
585
|
+
const doubled = 2n * r;
|
|
586
|
+
if (mode === "up") {
|
|
587
|
+
if (r !== 0n) q += 1n;
|
|
588
|
+
} else if (mode !== "down" && doubled >= pow10) {
|
|
589
|
+
if (doubled > pow10 || mode === "half-up" || q % 2n === 1n) q += 1n;
|
|
590
|
+
}
|
|
591
|
+
const result = sign * q;
|
|
592
|
+
return normalizeFloat(d >= 0 ? Number(result) / 10 ** d : Number(result) * 10 ** -d);
|
|
593
|
+
}
|
|
594
|
+
|
|
480
595
|
// src/evaluator.ts
|
|
481
596
|
var SAFE_GLOBALS = {
|
|
482
597
|
Math,
|
|
@@ -542,16 +657,17 @@ function evalBinary(node, context, functions) {
|
|
|
542
657
|
const left = evaluate(node.left, context, functions);
|
|
543
658
|
const right = evaluate(node.right, context, functions);
|
|
544
659
|
switch (node.op) {
|
|
660
|
+
// 数值运算统一走十进制精确实现:消除 0.1 + 0.2 类浮点噪声、字符串数字按数值处理、除零兜底 0
|
|
545
661
|
case "+":
|
|
546
|
-
return left
|
|
662
|
+
return isNumericOperands(left, right) ? decimalAdd(left, right) : concatOperands(left, right);
|
|
547
663
|
case "-":
|
|
548
|
-
return left
|
|
664
|
+
return decimalSubtract(left, right);
|
|
549
665
|
case "*":
|
|
550
|
-
return left
|
|
666
|
+
return decimalMultiply(left, right);
|
|
551
667
|
case "/":
|
|
552
|
-
return left
|
|
668
|
+
return decimalDivide(left, right);
|
|
553
669
|
case "%":
|
|
554
|
-
return left
|
|
670
|
+
return decimalModulo(left, right);
|
|
555
671
|
case "<":
|
|
556
672
|
return left < right;
|
|
557
673
|
case ">":
|
|
@@ -580,15 +696,29 @@ function evalUnary(node, context, functions) {
|
|
|
580
696
|
const arg = evaluate(node.arg, context, functions);
|
|
581
697
|
switch (node.op) {
|
|
582
698
|
case "-":
|
|
583
|
-
return
|
|
699
|
+
return decimalSubtract(0, arg);
|
|
584
700
|
case "+":
|
|
585
|
-
return
|
|
701
|
+
return toNumber(arg);
|
|
586
702
|
case "!":
|
|
587
703
|
return !arg;
|
|
588
704
|
default:
|
|
589
705
|
throw new Error(`\u672A\u77E5\u4E00\u5143\u8FD0\u7B97\u7B26: ${node.op}`);
|
|
590
706
|
}
|
|
591
707
|
}
|
|
708
|
+
function concatOperands(left, right) {
|
|
709
|
+
return `${left == null ? "" : String(left)}${right == null ? "" : String(right)}`;
|
|
710
|
+
}
|
|
711
|
+
function isNumericOperands(left, right) {
|
|
712
|
+
const l = operandKind(left);
|
|
713
|
+
const r = operandKind(right);
|
|
714
|
+
if (l === "other" || r === "other") return false;
|
|
715
|
+
return l === "num" || r === "num";
|
|
716
|
+
}
|
|
717
|
+
function operandKind(value) {
|
|
718
|
+
if (value == null || value === "") return "neutral";
|
|
719
|
+
if (isNumericLike(value)) return "num";
|
|
720
|
+
return "other";
|
|
721
|
+
}
|
|
592
722
|
function evalMember(node, context, functions) {
|
|
593
723
|
const obj = evaluate(node.object, context, functions);
|
|
594
724
|
if (obj == null) {
|
|
@@ -822,6 +952,34 @@ var systemVars = {
|
|
|
822
952
|
printTime: () => Date.now()
|
|
823
953
|
};
|
|
824
954
|
|
|
955
|
+
// src/functions/math.ts
|
|
956
|
+
function addNumbers(...values) {
|
|
957
|
+
return values.reduce((acc, v) => decimalAdd(acc, v), 0);
|
|
958
|
+
}
|
|
959
|
+
function subtractNumbers(...values) {
|
|
960
|
+
if (values.length === 0) return 0;
|
|
961
|
+
return values.slice(1).reduce((acc, v) => decimalSubtract(acc, v), decimalAdd(values[0], 0));
|
|
962
|
+
}
|
|
963
|
+
function multiplyNumbers(...values) {
|
|
964
|
+
if (values.length === 0) return 0;
|
|
965
|
+
return values.reduce((acc, v) => decimalMultiply(acc, v), 1);
|
|
966
|
+
}
|
|
967
|
+
function divideNumbers(a, b) {
|
|
968
|
+
return decimalDivide(a, b);
|
|
969
|
+
}
|
|
970
|
+
function round(value, digits) {
|
|
971
|
+
return roundTo(value, digits, "half-up");
|
|
972
|
+
}
|
|
973
|
+
function roundUp(value, digits) {
|
|
974
|
+
return roundTo(value, digits, "up");
|
|
975
|
+
}
|
|
976
|
+
function roundDown(value, digits) {
|
|
977
|
+
return roundTo(value, digits, "down");
|
|
978
|
+
}
|
|
979
|
+
function roundHalfEven(value, digits) {
|
|
980
|
+
return roundTo(value, digits, "half-even");
|
|
981
|
+
}
|
|
982
|
+
|
|
825
983
|
// src/render/expression-eval.ts
|
|
826
984
|
var RenderEngine = class {
|
|
827
985
|
constructor() {
|
|
@@ -847,8 +1005,19 @@ var FORMAT_FUNCTIONS = {
|
|
|
847
1005
|
IF: ifFn,
|
|
848
1006
|
CONCAT: (...args) => args.filter((v) => v != null).map(String).join(""),
|
|
849
1007
|
IFEMPTY: (v, d) => v != null && v !== "" ? String(v) : d,
|
|
850
|
-
|
|
851
|
-
|
|
1008
|
+
LEN: (s) => String(s).length,
|
|
1009
|
+
// 四则运算(与 +/-/*// 运算符同一套数值语义,供不方便写运算符的场景使用)
|
|
1010
|
+
ADD: addNumbers,
|
|
1011
|
+
SUB: subtractNumbers,
|
|
1012
|
+
MUL: multiplyNumbers,
|
|
1013
|
+
DIV: divideNumbers,
|
|
1014
|
+
// 数值修约
|
|
1015
|
+
ROUND: round,
|
|
1016
|
+
ROUNDUP: roundUp,
|
|
1017
|
+
CEIL: roundUp,
|
|
1018
|
+
ROUNDDOWN: roundDown,
|
|
1019
|
+
FLOOR: roundDown,
|
|
1020
|
+
ROUNDBANK: roundHalfEven
|
|
852
1021
|
};
|
|
853
1022
|
for (const [name, fn] of Object.entries(FORMAT_FUNCTIONS)) {
|
|
854
1023
|
engine.registerFunction(name, fn);
|
|
@@ -893,7 +1062,7 @@ function evaluateTemplate(text, ctx) {
|
|
|
893
1062
|
|
|
894
1063
|
// src/render/data-binder.ts
|
|
895
1064
|
function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
896
|
-
const data = printData ?? {};
|
|
1065
|
+
const data = { ...resolveSystemVariables(), ...printData ?? {} };
|
|
897
1066
|
const bound = JSON.parse(JSON.stringify(template));
|
|
898
1067
|
if (bound.header?.elements) {
|
|
899
1068
|
bound.header.elements = bound.header.elements.map((el) => bindElement(el, data, baseUrl));
|
|
@@ -922,7 +1091,12 @@ function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
|
922
1091
|
function bindElement(el, data, baseUrl) {
|
|
923
1092
|
const cloned = { ...el, options: { ...el.options } };
|
|
924
1093
|
if (typeof cloned.options.formatter === "string") {
|
|
925
|
-
|
|
1094
|
+
const raw = cloned.options.formatter;
|
|
1095
|
+
if (referencesPageNumbers(raw)) {
|
|
1096
|
+
cloned.options.rawFormatter = raw;
|
|
1097
|
+
} else {
|
|
1098
|
+
cloned.options.formatter = evaluateTemplate(raw, data);
|
|
1099
|
+
}
|
|
926
1100
|
}
|
|
927
1101
|
const isImage = cloned.type === "image" || cloned.printElementType?.type === "image";
|
|
928
1102
|
if (isImage && typeof cloned.options.src === "string") {
|
|
@@ -969,39 +1143,25 @@ function bindTableData(el, data) {
|
|
|
969
1143
|
if (dataStartIdx < 0) dataStartIdx = renderRows.length;
|
|
970
1144
|
const ctx = itemCtx(item);
|
|
971
1145
|
renderRows.push(makeRenderRow(row, (cell) => {
|
|
972
|
-
|
|
973
|
-
if (!formatter) return "";
|
|
974
|
-
return evaluateTemplate(formatter, ctx);
|
|
1146
|
+
return resolveCellText(cell, ctx);
|
|
975
1147
|
}));
|
|
976
1148
|
dataRowCtx.push(ctx);
|
|
977
1149
|
}
|
|
978
1150
|
continue;
|
|
979
1151
|
}
|
|
980
1152
|
if (mode === "dynamic" && row.type === "subtotal") {
|
|
981
|
-
const tpl = makeRenderRow(row, (cell) => {
|
|
982
|
-
const formatter = cell.formatter;
|
|
983
|
-
if (!formatter) return "";
|
|
984
|
-
return evaluateTemplate(formatter, { rows: summaryRows, ...data });
|
|
985
|
-
}, true);
|
|
1153
|
+
const tpl = makeRenderRow(row, (cell) => resolveCellText(cell, { rows: summaryRows, ...data }), true);
|
|
986
1154
|
subtotalTemplates.push(tpl);
|
|
987
1155
|
renderRows.push(tpl);
|
|
988
1156
|
continue;
|
|
989
1157
|
}
|
|
990
1158
|
if (mode === "dynamic" && row.type === "summary") {
|
|
991
|
-
const summaryRow = makeRenderRow(row, (cell) => {
|
|
992
|
-
const formatter = cell.formatter;
|
|
993
|
-
if (!formatter) return "";
|
|
994
|
-
return evaluateTemplate(formatter, { rows: summaryRows, ...data });
|
|
995
|
-
});
|
|
1159
|
+
const summaryRow = makeRenderRow(row, (cell) => resolveCellText(cell, { rows: summaryRows, ...data }));
|
|
996
1160
|
summaryRenderRows.push(summaryRow);
|
|
997
1161
|
renderRows.push(summaryRow);
|
|
998
1162
|
continue;
|
|
999
1163
|
}
|
|
1000
|
-
renderRows.push(makeRenderRow(row, (cell) =>
|
|
1001
|
-
const formatter = cell.formatter;
|
|
1002
|
-
if (!formatter) return "";
|
|
1003
|
-
return evaluateTemplate(formatter, data);
|
|
1004
|
-
}));
|
|
1164
|
+
renderRows.push(makeRenderRow(row, (cell) => resolveCellText(cell, data)));
|
|
1005
1165
|
}
|
|
1006
1166
|
opts._renderRows = renderRows;
|
|
1007
1167
|
opts._repeatHeaderCount = countRepeatHeader(rows);
|
|
@@ -1011,13 +1171,20 @@ function bindTableData(el, data) {
|
|
|
1011
1171
|
opts._summaryRows = summaryRenderRows;
|
|
1012
1172
|
opts._mainData = data;
|
|
1013
1173
|
}
|
|
1174
|
+
function resolveCellText(cell, ctx) {
|
|
1175
|
+
const formatter = cell.formatter;
|
|
1176
|
+
if (!formatter) return "";
|
|
1177
|
+
if (referencesPageNumbers(formatter)) return formatter;
|
|
1178
|
+
return evaluateTemplate(formatter, ctx);
|
|
1179
|
+
}
|
|
1014
1180
|
function makeRenderRow(row, resolve, keepRaw = false) {
|
|
1015
1181
|
return {
|
|
1016
1182
|
type: row.type,
|
|
1017
1183
|
height: row.height ?? 8,
|
|
1018
1184
|
cells: row.cells.map((cell) => ({
|
|
1019
1185
|
content: cell.merged ? "" : resolve(cell),
|
|
1020
|
-
|
|
1186
|
+
// 小计行(keepRaw)与引用页码的单元格都保留原始表达式:前者按当页数据行重算,后者按当页页码重算
|
|
1187
|
+
...(keepRaw || referencesPageNumbers(cell.formatter)) && !cell.merged ? { rawFormatter: cell.formatter ?? "" } : {},
|
|
1021
1188
|
cellType: cell.cellType,
|
|
1022
1189
|
barcodeType: cell.barcodeType,
|
|
1023
1190
|
qrCodeLevel: cell.qrCodeLevel,
|
|
@@ -1045,16 +1212,35 @@ function makeRenderRow(row, resolve, keepRaw = false) {
|
|
|
1045
1212
|
};
|
|
1046
1213
|
}
|
|
1047
1214
|
function countRepeatHeader(rows) {
|
|
1215
|
+
const headerCount = countLeadingHeaderRows(rows);
|
|
1216
|
+
if (headerCount === 0) return 0;
|
|
1217
|
+
const enabled = rows.slice(0, headerCount).some((row) => row.repeatOnPage === true);
|
|
1218
|
+
if (!enabled) return 0;
|
|
1219
|
+
return alignToRowspanBoundary(rows, headerCount);
|
|
1220
|
+
}
|
|
1221
|
+
function countLeadingHeaderRows(rows) {
|
|
1048
1222
|
let n = 0;
|
|
1049
1223
|
for (const row of rows) {
|
|
1050
|
-
if (row
|
|
1051
|
-
|
|
1052
|
-
} else {
|
|
1053
|
-
break;
|
|
1054
|
-
}
|
|
1224
|
+
if (row?.type !== "header") break;
|
|
1225
|
+
n++;
|
|
1055
1226
|
}
|
|
1056
1227
|
return n;
|
|
1057
1228
|
}
|
|
1229
|
+
function isRowspanComplete(rows, n) {
|
|
1230
|
+
for (let r = 0; r < n; r++) {
|
|
1231
|
+
for (const cell of rows[r]?.cells ?? []) {
|
|
1232
|
+
if (cell?.merged) continue;
|
|
1233
|
+
if (r + (cell?.rowspan ?? 1) > n) return false;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
function alignToRowspanBoundary(rows, max2) {
|
|
1239
|
+
for (let n = max2; n >= 1; n--) {
|
|
1240
|
+
if (isRowspanComplete(rows, n)) return n;
|
|
1241
|
+
}
|
|
1242
|
+
return 1;
|
|
1243
|
+
}
|
|
1058
1244
|
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1059
1245
|
function resolveSystemVariables(now = /* @__PURE__ */ new Date(), page = {}) {
|
|
1060
1246
|
return {
|
|
@@ -1064,6 +1250,9 @@ function resolveSystemVariables(now = /* @__PURE__ */ new Date(), page = {}) {
|
|
|
1064
1250
|
totalPages: page.totalPages ?? 1
|
|
1065
1251
|
};
|
|
1066
1252
|
}
|
|
1253
|
+
function referencesPageNumbers(expr) {
|
|
1254
|
+
return typeof expr === "string" && /\b(pageIndex|totalPages)\b/.test(expr);
|
|
1255
|
+
}
|
|
1067
1256
|
function injectSystemVariables(html, now = /* @__PURE__ */ new Date()) {
|
|
1068
1257
|
const { printDate, printTime } = resolveSystemVariables(now);
|
|
1069
1258
|
return html.replace(/\{printDate\}/g, printDate).replace(/\{printTime\}/g, printTime);
|
|
@@ -1704,10 +1893,9 @@ function tableDesignBottom(el) {
|
|
|
1704
1893
|
const opts = el.options ?? {};
|
|
1705
1894
|
const top = opts.top ?? 0;
|
|
1706
1895
|
const rows = opts.tableRows ?? [];
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
return top + (opts.height ?? 0);
|
|
1896
|
+
const rowSum = rows.reduce((s, r) => s + (r.height ?? 0), 0);
|
|
1897
|
+
const designHeight = Math.max(opts.height ?? 0, rowSum);
|
|
1898
|
+
return top + designHeight;
|
|
1711
1899
|
}
|
|
1712
1900
|
function buildFollowMap(sorted, excludedIds) {
|
|
1713
1901
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -1848,7 +2036,10 @@ function paginate(template, measuredElements) {
|
|
|
1848
2036
|
let isFirstPage = true;
|
|
1849
2037
|
let pageBroken = false;
|
|
1850
2038
|
function sectionTop(el) {
|
|
1851
|
-
return pageBroken ?
|
|
2039
|
+
return pageBroken ? pageCursorTop() : el.options?.top ?? 0;
|
|
2040
|
+
}
|
|
2041
|
+
function pageCursorTop() {
|
|
2042
|
+
return Math.max(0, fullPageHeight() - remaining);
|
|
1852
2043
|
}
|
|
1853
2044
|
function fullPageHeight() {
|
|
1854
2045
|
return isFirstPage ? contentHeight - overlayH - SAFETY_MARGIN : contentHeight - SAFETY_MARGIN;
|
|
@@ -1915,7 +2106,7 @@ function paginate(template, measuredElements) {
|
|
|
1915
2106
|
function paginateNonTable(el, measured, sortedList, idx) {
|
|
1916
2107
|
const elHeight = measured.get(el.id)?.measuredHeight ?? el.options?.height ?? 0;
|
|
1917
2108
|
if (elHeight <= remaining) {
|
|
1918
|
-
const top2 = pageBroken ?
|
|
2109
|
+
const top2 = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
|
|
1919
2110
|
noteOverflow(top2 + elHeight);
|
|
1920
2111
|
currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
|
|
1921
2112
|
remaining -= elHeight;
|
|
@@ -1934,8 +2125,9 @@ function paginate(template, measuredElements) {
|
|
|
1934
2125
|
}
|
|
1935
2126
|
return idx + 1;
|
|
1936
2127
|
}
|
|
1937
|
-
|
|
1938
|
-
|
|
2128
|
+
finishPage();
|
|
2129
|
+
const top = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
|
|
2130
|
+
if (top + elHeight > contentHeight) overflowOnCurrent = true;
|
|
1939
2131
|
currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
|
|
1940
2132
|
remaining -= elHeight;
|
|
1941
2133
|
return idx + 1;
|
|
@@ -1951,7 +2143,7 @@ function paginate(template, measuredElements) {
|
|
|
1951
2143
|
}
|
|
1952
2144
|
const unitHeight = Math.max(maxBottom - minTop, 0);
|
|
1953
2145
|
const place = () => {
|
|
1954
|
-
const offset = pageBroken ? -minTop : 0;
|
|
2146
|
+
const offset = pageBroken ? pageCursorTop() - minTop : 0;
|
|
1955
2147
|
noteOverflow(minTop + offset + unitHeight);
|
|
1956
2148
|
for (const m of members) {
|
|
1957
2149
|
currentPage.push({
|
|
@@ -2025,6 +2217,7 @@ function paginate(template, measuredElements) {
|
|
|
2025
2217
|
const groups = buildRowGroups(bodyRows, rowCount);
|
|
2026
2218
|
let sliceStart = 0;
|
|
2027
2219
|
let firstSlice = true;
|
|
2220
|
+
let sliceTop = sectionTop(el);
|
|
2028
2221
|
for (const g of groups) {
|
|
2029
2222
|
const gh = bodyHeights.slice(g.start, g.end).reduce((s, h) => s + h, 0);
|
|
2030
2223
|
if (gh + subtotalH <= remaining) {
|
|
@@ -2039,12 +2232,13 @@ function paginate(template, measuredElements) {
|
|
|
2039
2232
|
endRow: g.start,
|
|
2040
2233
|
subtotal: subtotalH > 0,
|
|
2041
2234
|
...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
|
|
2042
|
-
renderTop:
|
|
2235
|
+
renderTop: sliceTop
|
|
2043
2236
|
});
|
|
2044
2237
|
firstSlice = false;
|
|
2045
2238
|
sliceStart = g.start;
|
|
2046
2239
|
}
|
|
2047
2240
|
finishPage();
|
|
2241
|
+
sliceTop = sectionTop(el);
|
|
2048
2242
|
if (!firstSlice) remaining -= repeatH;
|
|
2049
2243
|
remaining -= gh;
|
|
2050
2244
|
}
|
|
@@ -2056,7 +2250,7 @@ function paginate(template, measuredElements) {
|
|
|
2056
2250
|
endRow: rowCount,
|
|
2057
2251
|
subtotal: subtotalH > 0,
|
|
2058
2252
|
...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
|
|
2059
|
-
renderTop:
|
|
2253
|
+
renderTop: sliceTop
|
|
2060
2254
|
});
|
|
2061
2255
|
}
|
|
2062
2256
|
if (summaryH > 0) {
|
|
@@ -2144,6 +2338,13 @@ function barcodeAvailableBoxMm(boxMm, maxMm) {
|
|
|
2144
2338
|
}
|
|
2145
2339
|
|
|
2146
2340
|
// src/render/html-generator.ts
|
|
2341
|
+
function pageVarsContext(vars) {
|
|
2342
|
+
return { ...vars.data ?? {}, pageIndex: vars.pageIndex, totalPages: vars.totalPages };
|
|
2343
|
+
}
|
|
2344
|
+
function pageVarsData(printData) {
|
|
2345
|
+
if (Array.isArray(printData)) return printData[0] ?? {};
|
|
2346
|
+
return printData ?? {};
|
|
2347
|
+
}
|
|
2147
2348
|
function generateHtml(template, pageLayouts, printData, options) {
|
|
2148
2349
|
const css = buildFontFaceCss(template.fonts) + buildPageCss(template, options?.pageHeightMm);
|
|
2149
2350
|
const isMeasure = options?.isMeasurementPass === true;
|
|
@@ -2228,22 +2429,25 @@ function renderPage(template, page, pageNum, totalPages, ctx, printData, pageCla
|
|
|
2228
2429
|
height: ctx.pageHeightMm && ctx.pageHeightMm > 0 ? ctx.pageHeightMm : paper.height
|
|
2229
2430
|
};
|
|
2230
2431
|
const contentWidth = paper.width - template.margins.left - template.margins.right;
|
|
2432
|
+
const pageVars = { pageIndex: pageNum, totalPages, data: pageVarsData(printData) };
|
|
2433
|
+
const scoped = withPageNumbers(template, pageVars);
|
|
2434
|
+
const pageCtx = { ...ctx, pageVars };
|
|
2231
2435
|
const headerHtml = renderAreaElements(
|
|
2232
|
-
|
|
2436
|
+
scoped.header?.elements ?? [],
|
|
2233
2437
|
contentWidth,
|
|
2234
2438
|
pageNum,
|
|
2235
2439
|
totalPages,
|
|
2236
|
-
|
|
2440
|
+
pageCtx
|
|
2237
2441
|
);
|
|
2238
2442
|
const footerHtml = renderAreaElements(
|
|
2239
|
-
|
|
2443
|
+
scoped.footer?.elements ?? [],
|
|
2240
2444
|
contentWidth,
|
|
2241
2445
|
pageNum,
|
|
2242
2446
|
totalPages,
|
|
2243
|
-
|
|
2447
|
+
pageCtx
|
|
2244
2448
|
);
|
|
2245
|
-
const overlayHtml = page.pageIndex === 0 ? `<div class="first-page-overlay">${renderAreaElements(
|
|
2246
|
-
let contentHtml = page.sections.map((section) => renderSection(section,
|
|
2449
|
+
const overlayHtml = page.pageIndex === 0 ? `<div class="first-page-overlay">${renderAreaElements(scoped.firstPageOverlay?.elements ?? [], contentWidth, pageNum, totalPages, pageCtx)}</div>` : "";
|
|
2450
|
+
let contentHtml = page.sections.map((section) => renderSection(section, scoped, pageCtx)).join("\n");
|
|
2247
2451
|
contentHtml = contentHtml.replace(/\{pageIndex\}/g, String(pageNum));
|
|
2248
2452
|
contentHtml = contentHtml.replace(/\{totalPages\}/g, String(totalPages));
|
|
2249
2453
|
const pageInner = `
|
|
@@ -2260,6 +2464,39 @@ function renderPage(template, page, pageNum, totalPages, ctx, printData, pageCla
|
|
|
2260
2464
|
${pageBody}
|
|
2261
2465
|
</section>`;
|
|
2262
2466
|
}
|
|
2467
|
+
function withPageNumbers(template, vars) {
|
|
2468
|
+
if (!templateReferencesPageNumbers(template)) return template;
|
|
2469
|
+
const context = pageVarsContext(vars);
|
|
2470
|
+
const mapEl = (el) => {
|
|
2471
|
+
const raw = el.options?.rawFormatter;
|
|
2472
|
+
if (typeof raw !== "string") return el;
|
|
2473
|
+
return { ...el, options: { ...el.options, formatter: evaluateTemplate(raw, context) } };
|
|
2474
|
+
};
|
|
2475
|
+
const mapArea = (area) => area ? { ...area, elements: (area.elements ?? []).map(mapEl) } : area;
|
|
2476
|
+
return {
|
|
2477
|
+
...template,
|
|
2478
|
+
elements: template.elements.map(mapEl),
|
|
2479
|
+
header: mapArea(template.header),
|
|
2480
|
+
footer: mapArea(template.footer),
|
|
2481
|
+
firstPageOverlay: mapArea(template.firstPageOverlay)
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
function templateReferencesPageNumbers(template) {
|
|
2485
|
+
const areas = [
|
|
2486
|
+
template.elements,
|
|
2487
|
+
template.header?.elements,
|
|
2488
|
+
template.footer?.elements,
|
|
2489
|
+
template.firstPageOverlay?.elements
|
|
2490
|
+
];
|
|
2491
|
+
return areas.some((list) => (list ?? []).some((el) => typeof el.options?.rawFormatter === "string"));
|
|
2492
|
+
}
|
|
2493
|
+
function resolveCellContent(cell, ctx) {
|
|
2494
|
+
const raw = cell.rawFormatter;
|
|
2495
|
+
if (typeof raw === "string" && raw !== "" && ctx?.pageVars) {
|
|
2496
|
+
return evaluateTemplate(raw, pageVarsContext(ctx.pageVars));
|
|
2497
|
+
}
|
|
2498
|
+
return cell.content;
|
|
2499
|
+
}
|
|
2263
2500
|
function renderSection(section, template, ctx) {
|
|
2264
2501
|
const el = findElement(template, section.elementId);
|
|
2265
2502
|
if (!el) {
|
|
@@ -2412,7 +2649,7 @@ function matrixCellStyle(cell, opts) {
|
|
|
2412
2649
|
}
|
|
2413
2650
|
return parts.join(";");
|
|
2414
2651
|
}
|
|
2415
|
-
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOwner = { elementId: "", kind: "b" }) {
|
|
2652
|
+
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOwner = { elementId: "", kind: "b" }, rowLimit) {
|
|
2416
2653
|
const trs = [];
|
|
2417
2654
|
const defaultPadding = opts.tableDefaultPadding ?? 1;
|
|
2418
2655
|
for (let r = start; r < end; r++) {
|
|
@@ -2420,12 +2657,14 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2420
2657
|
if (!row) continue;
|
|
2421
2658
|
const idxAttr = withRowIndex ? ` data-row-index="${r}"` : "";
|
|
2422
2659
|
const tds = row.cells.map((cell, ci) => ({ cell, ci })).filter(({ cell }) => !cell.merged).map(({ cell, ci }) => {
|
|
2423
|
-
const
|
|
2660
|
+
const rowspan = rowLimit === void 0 ? cell.rowspan ?? 1 : Math.max(1, Math.min(cell.rowspan ?? 1, rowLimit - r));
|
|
2661
|
+
const span = `${rowspan > 1 ? ` rowspan="${rowspan}"` : ""}${cell.colspan > 1 ? ` colspan="${cell.colspan}"` : ""}`;
|
|
2424
2662
|
const colIndex = ci;
|
|
2425
2663
|
let inner;
|
|
2426
2664
|
if (cell.cellType === "barcode" || cell.cellType === "qrcode") {
|
|
2427
|
-
|
|
2428
|
-
|
|
2665
|
+
const codeValue = resolveCellContent(cell, ctx);
|
|
2666
|
+
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;">${codeImgHtml(codeValue, cell.cellType, cell, {
|
|
2667
|
+
fallback: esc(codeValue),
|
|
2429
2668
|
codeRenderer: ctx?.codeRenderer,
|
|
2430
2669
|
fit: cell.fit,
|
|
2431
2670
|
maxWidth: cell.maxWidth,
|
|
@@ -2439,9 +2678,9 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2439
2678
|
const fit = cell.fit || "contain";
|
|
2440
2679
|
const maxWidth = cell.maxWidth ? `max-width:${cell.maxWidth}mm;` : "max-width:100%;";
|
|
2441
2680
|
const maxHeight = cell.maxHeight ? `max-height:${cell.maxHeight}mm;` : "max-height:100%;";
|
|
2442
|
-
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;"><img src="${esc(cell
|
|
2681
|
+
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;"><img src="${esc(resolveCellContent(cell, ctx))}" style="object-fit:${fit};${maxWidth}${maxHeight}display:block;" /></div>`;
|
|
2443
2682
|
} else {
|
|
2444
|
-
inner = renderTextCellInner(renderRows, r, colIndex, cell, opts, fitOwner, defaultPadding);
|
|
2683
|
+
inner = renderTextCellInner(renderRows, r, colIndex, cell, opts, fitOwner, defaultPadding, ctx);
|
|
2445
2684
|
}
|
|
2446
2685
|
return `<td${span} style="${matrixCellStyle(cell, opts)}">${inner}</td>`;
|
|
2447
2686
|
}).join("");
|
|
@@ -2449,9 +2688,9 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2449
2688
|
}
|
|
2450
2689
|
return trs.join("\n");
|
|
2451
2690
|
}
|
|
2452
|
-
function renderTextCellInner(renderRows, rowIndex, colIndex, cell, opts, fitOwner, defaultPadding) {
|
|
2691
|
+
function renderTextCellInner(renderRows, rowIndex, colIndex, cell, opts, fitOwner, defaultPadding, ctx) {
|
|
2453
2692
|
const fit = resolveCellTextFit(cell);
|
|
2454
|
-
const text = esc(cell
|
|
2693
|
+
const text = esc(resolveCellContent(cell, ctx));
|
|
2455
2694
|
if (fit === "autoHeight") return text;
|
|
2456
2695
|
const capMm = cellFitCapMm(renderRows, rowIndex, cell, defaultPadding);
|
|
2457
2696
|
const nowrap = cell.wordWrap === false;
|
|
@@ -2489,7 +2728,7 @@ function renderTableSlice(el, section, ctx) {
|
|
|
2489
2728
|
const startRow = section.startRow ?? 0;
|
|
2490
2729
|
const endRow = section.endRow ?? renderRows.length;
|
|
2491
2730
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
2492
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
2731
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }, repeatCount) : "";
|
|
2493
2732
|
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
2494
2733
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
2495
2734
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
|
@@ -2510,9 +2749,15 @@ function renderSubtotalRows(el, section, opts, ctx) {
|
|
|
2510
2749
|
const dataStart = Math.max(startRow, dataStartIdx);
|
|
2511
2750
|
const dataEnd = Math.max(endRow, dataStart);
|
|
2512
2751
|
const pageCtx = dataEnd > dataStartIdx ? dataRowCtx.slice(Math.max(dataStart - dataStartIdx, 0), dataEnd - dataStartIdx) : [];
|
|
2752
|
+
const pageVars = ctx?.pageVars ? pageVarsContext(ctx.pageVars) : {};
|
|
2513
2753
|
const rows = templates.map((tpl) => ({
|
|
2514
2754
|
...tpl,
|
|
2515
|
-
cells: tpl.cells.map((cell) => cell.rawFormatter ? {
|
|
2755
|
+
cells: tpl.cells.map((cell) => cell.rawFormatter ? {
|
|
2756
|
+
...cell,
|
|
2757
|
+
content: evaluateTemplate(cell.rawFormatter, { rows: pageCtx, ...mainData, ...pageVars }),
|
|
2758
|
+
// 已按本页上下文求值,清标记避免渲染时再按页码重算一次(会丢掉 rows)
|
|
2759
|
+
rawFormatter: ""
|
|
2760
|
+
} : cell)
|
|
2516
2761
|
}));
|
|
2517
2762
|
return renderMatrixRows(rows, 0, rows.length, opts, false, ctx, { elementId: el.id, kind: "st" });
|
|
2518
2763
|
}
|
|
@@ -2535,7 +2780,7 @@ function renderFlowGroup(el, section, template, ctx) {
|
|
|
2535
2780
|
if (endRow > startRow || section.subtotal || section.summary) {
|
|
2536
2781
|
const renderRows = opts._renderRows ?? [];
|
|
2537
2782
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
2538
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
2783
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }, repeatCount) : "";
|
|
2539
2784
|
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
2540
2785
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
2541
2786
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
|
@@ -3576,6 +3821,7 @@ var TemplateEngine = class {
|
|
|
3576
3821
|
TilingError,
|
|
3577
3822
|
WATERMARK_DEFAULTS,
|
|
3578
3823
|
WATERMARK_DENSITY_PRESETS,
|
|
3824
|
+
addNumbers,
|
|
3579
3825
|
applyTextFitSizes,
|
|
3580
3826
|
avg,
|
|
3581
3827
|
bindData,
|
|
@@ -3600,6 +3846,7 @@ var TemplateEngine = class {
|
|
|
3600
3846
|
createCollectingCodeRenderer,
|
|
3601
3847
|
createDomHostRuntime,
|
|
3602
3848
|
createMapCodeRenderer,
|
|
3849
|
+
divideNumbers,
|
|
3603
3850
|
elementPositionStyle,
|
|
3604
3851
|
escapeHeightMm,
|
|
3605
3852
|
escapeInlineStyleValue,
|
|
@@ -3627,6 +3874,7 @@ var TemplateEngine = class {
|
|
|
3627
3874
|
min,
|
|
3628
3875
|
mm,
|
|
3629
3876
|
mmToPx,
|
|
3877
|
+
multiplyNumbers,
|
|
3630
3878
|
normalizeMeasurements,
|
|
3631
3879
|
normalizePrintData,
|
|
3632
3880
|
normalizeTemplate,
|
|
@@ -3651,11 +3899,16 @@ var TemplateEngine = class {
|
|
|
3651
3899
|
resolveSystemVariables,
|
|
3652
3900
|
resolveWatermarkLayout,
|
|
3653
3901
|
resolveWatermarkText,
|
|
3902
|
+
round,
|
|
3903
|
+
roundDown,
|
|
3654
3904
|
roundFontSize,
|
|
3905
|
+
roundHalfEven,
|
|
3655
3906
|
roundMm,
|
|
3907
|
+
roundUp,
|
|
3656
3908
|
safeEval,
|
|
3657
3909
|
setPageIndex,
|
|
3658
3910
|
setTotalPages,
|
|
3911
|
+
subtractNumbers,
|
|
3659
3912
|
sum,
|
|
3660
3913
|
systemVars,
|
|
3661
3914
|
tableDesignBottom,
|