@worm-vue3-print/core 1.3.0 → 1.3.1
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 +284 -52
- 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-AKWV6SID.js} +1 -1
- package/dist/{chunk-VFEURLAZ.js → chunk-KFRPTLFV.js} +292 -52
- 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 +300 -52
- package/dist/index.d.cts +24 -5
- package/dist/index.d.ts +24 -5
- 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/browser/index.cjs
CHANGED
|
@@ -954,6 +954,113 @@ var Parser = class {
|
|
|
954
954
|
}
|
|
955
955
|
};
|
|
956
956
|
|
|
957
|
+
// src/numeric.ts
|
|
958
|
+
var MAX_DIGITS = 20;
|
|
959
|
+
var EXTRA_SCALE = 8;
|
|
960
|
+
function toNumber(value, fallback = 0) {
|
|
961
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : fallback;
|
|
962
|
+
if (typeof value === "string") {
|
|
963
|
+
const s = value.trim();
|
|
964
|
+
if (s === "") return fallback;
|
|
965
|
+
const n = Number(s);
|
|
966
|
+
return Number.isFinite(n) ? n : fallback;
|
|
967
|
+
}
|
|
968
|
+
if (value == null) return fallback;
|
|
969
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
970
|
+
return fallback;
|
|
971
|
+
}
|
|
972
|
+
function isNumericLike(value) {
|
|
973
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
974
|
+
if (typeof value === "string") {
|
|
975
|
+
const s = value.trim();
|
|
976
|
+
return s !== "" && Number.isFinite(Number(s));
|
|
977
|
+
}
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
function normalizeFloat(value) {
|
|
981
|
+
if (!Number.isFinite(value) || Number.isInteger(value)) return value;
|
|
982
|
+
if (Math.abs(value) >= 1e15) return value;
|
|
983
|
+
return Number(value.toPrecision(12));
|
|
984
|
+
}
|
|
985
|
+
function decimalsOf(n) {
|
|
986
|
+
if (!Number.isFinite(n) || Number.isInteger(n)) return 0;
|
|
987
|
+
const s = String(n);
|
|
988
|
+
if (s.includes("e") || s.includes("E")) return 0;
|
|
989
|
+
const i = s.indexOf(".");
|
|
990
|
+
return i === -1 ? 0 : s.length - i - 1;
|
|
991
|
+
}
|
|
992
|
+
function rescale(value, decimals) {
|
|
993
|
+
if (!Number.isFinite(value)) return 0;
|
|
994
|
+
const d = Math.min(Math.max(decimals, 0), 12);
|
|
995
|
+
if (d === 0) return Math.round(value);
|
|
996
|
+
const f = 10 ** d;
|
|
997
|
+
const scaled = value * f;
|
|
998
|
+
if (!Number.isFinite(scaled) || Math.abs(scaled) >= 1e15) return normalizeFloat(value);
|
|
999
|
+
return Math.round(scaled) / f;
|
|
1000
|
+
}
|
|
1001
|
+
function decimalAdd(left, right) {
|
|
1002
|
+
const a = toNumber(left);
|
|
1003
|
+
const b = toNumber(right);
|
|
1004
|
+
const raw = a + b;
|
|
1005
|
+
return rescale(raw, Math.max(decimalsOf(a), decimalsOf(b)));
|
|
1006
|
+
}
|
|
1007
|
+
function decimalSubtract(left, right) {
|
|
1008
|
+
const a = toNumber(left);
|
|
1009
|
+
const b = toNumber(right);
|
|
1010
|
+
const raw = a - b;
|
|
1011
|
+
return rescale(raw, Math.max(decimalsOf(a), decimalsOf(b)));
|
|
1012
|
+
}
|
|
1013
|
+
function decimalMultiply(left, right) {
|
|
1014
|
+
const a = toNumber(left);
|
|
1015
|
+
const b = toNumber(right);
|
|
1016
|
+
const raw = a * b;
|
|
1017
|
+
return rescale(raw, decimalsOf(a) + decimalsOf(b));
|
|
1018
|
+
}
|
|
1019
|
+
function decimalDivide(left, right) {
|
|
1020
|
+
const a = toNumber(left);
|
|
1021
|
+
const b = toNumber(right);
|
|
1022
|
+
if (b === 0) return 0;
|
|
1023
|
+
return normalizeFloat(a / b);
|
|
1024
|
+
}
|
|
1025
|
+
function decimalModulo(left, right) {
|
|
1026
|
+
const a = toNumber(left);
|
|
1027
|
+
const b = toNumber(right);
|
|
1028
|
+
if (b === 0) return 0;
|
|
1029
|
+
return normalizeFloat(a % b);
|
|
1030
|
+
}
|
|
1031
|
+
function normalizeDigits(digits) {
|
|
1032
|
+
if (digits === void 0 || digits === null) return 2;
|
|
1033
|
+
const d = Math.trunc(toNumber(digits, 2));
|
|
1034
|
+
if (!Number.isFinite(d)) return 2;
|
|
1035
|
+
return Math.min(Math.max(d, -MAX_DIGITS), MAX_DIGITS);
|
|
1036
|
+
}
|
|
1037
|
+
function roundTo(value, digits, mode) {
|
|
1038
|
+
const n = toNumber(value, 0);
|
|
1039
|
+
const d = normalizeDigits(digits);
|
|
1040
|
+
if (n === 0) return 0;
|
|
1041
|
+
if (Math.abs(n) >= 1e21) return normalizeFloat(n);
|
|
1042
|
+
const scale = Math.max(d, 0) + EXTRA_SCALE;
|
|
1043
|
+
const fixed = n.toFixed(scale);
|
|
1044
|
+
if (!/^-?\d+(\.\d+)?$/.test(fixed)) return normalizeFloat(n);
|
|
1045
|
+
const negative = fixed.startsWith("-");
|
|
1046
|
+
const digitsStr = fixed.replace("-", "").replace(".", "");
|
|
1047
|
+
let scaled = BigInt(digitsStr || "0");
|
|
1048
|
+
if (negative) scaled = -scaled;
|
|
1049
|
+
const pow10 = 10n ** BigInt(scale - d);
|
|
1050
|
+
const sign = scaled < 0n ? -1n : 1n;
|
|
1051
|
+
const abs = scaled < 0n ? -scaled : scaled;
|
|
1052
|
+
let q = abs / pow10;
|
|
1053
|
+
const r = abs % pow10;
|
|
1054
|
+
const doubled = 2n * r;
|
|
1055
|
+
if (mode === "up") {
|
|
1056
|
+
if (r !== 0n) q += 1n;
|
|
1057
|
+
} else if (mode !== "down" && doubled >= pow10) {
|
|
1058
|
+
if (doubled > pow10 || mode === "half-up" || q % 2n === 1n) q += 1n;
|
|
1059
|
+
}
|
|
1060
|
+
const result = sign * q;
|
|
1061
|
+
return normalizeFloat(d >= 0 ? Number(result) / 10 ** d : Number(result) * 10 ** -d);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
957
1064
|
// src/evaluator.ts
|
|
958
1065
|
var SAFE_GLOBALS = {
|
|
959
1066
|
Math,
|
|
@@ -1019,16 +1126,17 @@ function evalBinary(node, context, functions) {
|
|
|
1019
1126
|
const left = evaluate(node.left, context, functions);
|
|
1020
1127
|
const right = evaluate(node.right, context, functions);
|
|
1021
1128
|
switch (node.op) {
|
|
1129
|
+
// 数值运算统一走十进制精确实现:消除 0.1 + 0.2 类浮点噪声、字符串数字按数值处理、除零兜底 0
|
|
1022
1130
|
case "+":
|
|
1023
|
-
return left
|
|
1131
|
+
return isNumericOperands(left, right) ? decimalAdd(left, right) : concatOperands(left, right);
|
|
1024
1132
|
case "-":
|
|
1025
|
-
return left
|
|
1133
|
+
return decimalSubtract(left, right);
|
|
1026
1134
|
case "*":
|
|
1027
|
-
return left
|
|
1135
|
+
return decimalMultiply(left, right);
|
|
1028
1136
|
case "/":
|
|
1029
|
-
return left
|
|
1137
|
+
return decimalDivide(left, right);
|
|
1030
1138
|
case "%":
|
|
1031
|
-
return left
|
|
1139
|
+
return decimalModulo(left, right);
|
|
1032
1140
|
case "<":
|
|
1033
1141
|
return left < right;
|
|
1034
1142
|
case ">":
|
|
@@ -1057,15 +1165,29 @@ function evalUnary(node, context, functions) {
|
|
|
1057
1165
|
const arg = evaluate(node.arg, context, functions);
|
|
1058
1166
|
switch (node.op) {
|
|
1059
1167
|
case "-":
|
|
1060
|
-
return
|
|
1168
|
+
return decimalSubtract(0, arg);
|
|
1061
1169
|
case "+":
|
|
1062
|
-
return
|
|
1170
|
+
return toNumber(arg);
|
|
1063
1171
|
case "!":
|
|
1064
1172
|
return !arg;
|
|
1065
1173
|
default:
|
|
1066
1174
|
throw new Error(`\u672A\u77E5\u4E00\u5143\u8FD0\u7B97\u7B26: ${node.op}`);
|
|
1067
1175
|
}
|
|
1068
1176
|
}
|
|
1177
|
+
function concatOperands(left, right) {
|
|
1178
|
+
return `${left == null ? "" : String(left)}${right == null ? "" : String(right)}`;
|
|
1179
|
+
}
|
|
1180
|
+
function isNumericOperands(left, right) {
|
|
1181
|
+
const l = operandKind(left);
|
|
1182
|
+
const r = operandKind(right);
|
|
1183
|
+
if (l === "other" || r === "other") return false;
|
|
1184
|
+
return l === "num" || r === "num";
|
|
1185
|
+
}
|
|
1186
|
+
function operandKind(value) {
|
|
1187
|
+
if (value == null || value === "") return "neutral";
|
|
1188
|
+
if (isNumericLike(value)) return "num";
|
|
1189
|
+
return "other";
|
|
1190
|
+
}
|
|
1069
1191
|
function evalMember(node, context, functions) {
|
|
1070
1192
|
const obj = evaluate(node.object, context, functions);
|
|
1071
1193
|
if (obj == null) {
|
|
@@ -1277,6 +1399,34 @@ function max(rows, field) {
|
|
|
1277
1399
|
return Math.max(...rows.map((row) => Number(getByPath(row, field)) || 0));
|
|
1278
1400
|
}
|
|
1279
1401
|
|
|
1402
|
+
// src/functions/math.ts
|
|
1403
|
+
function addNumbers(...values) {
|
|
1404
|
+
return values.reduce((acc, v) => decimalAdd(acc, v), 0);
|
|
1405
|
+
}
|
|
1406
|
+
function subtractNumbers(...values) {
|
|
1407
|
+
if (values.length === 0) return 0;
|
|
1408
|
+
return values.slice(1).reduce((acc, v) => decimalSubtract(acc, v), decimalAdd(values[0], 0));
|
|
1409
|
+
}
|
|
1410
|
+
function multiplyNumbers(...values) {
|
|
1411
|
+
if (values.length === 0) return 0;
|
|
1412
|
+
return values.reduce((acc, v) => decimalMultiply(acc, v), 1);
|
|
1413
|
+
}
|
|
1414
|
+
function divideNumbers(a, b) {
|
|
1415
|
+
return decimalDivide(a, b);
|
|
1416
|
+
}
|
|
1417
|
+
function round(value, digits) {
|
|
1418
|
+
return roundTo(value, digits, "half-up");
|
|
1419
|
+
}
|
|
1420
|
+
function roundUp(value, digits) {
|
|
1421
|
+
return roundTo(value, digits, "up");
|
|
1422
|
+
}
|
|
1423
|
+
function roundDown(value, digits) {
|
|
1424
|
+
return roundTo(value, digits, "down");
|
|
1425
|
+
}
|
|
1426
|
+
function roundHalfEven(value, digits) {
|
|
1427
|
+
return roundTo(value, digits, "half-even");
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1280
1430
|
// src/render/expression-eval.ts
|
|
1281
1431
|
var RenderEngine = class {
|
|
1282
1432
|
constructor() {
|
|
@@ -1302,8 +1452,19 @@ var FORMAT_FUNCTIONS = {
|
|
|
1302
1452
|
IF: ifFn,
|
|
1303
1453
|
CONCAT: (...args) => args.filter((v) => v != null).map(String).join(""),
|
|
1304
1454
|
IFEMPTY: (v, d) => v != null && v !== "" ? String(v) : d,
|
|
1305
|
-
|
|
1306
|
-
|
|
1455
|
+
LEN: (s) => String(s).length,
|
|
1456
|
+
// 四则运算(与 +/-/*// 运算符同一套数值语义,供不方便写运算符的场景使用)
|
|
1457
|
+
ADD: addNumbers,
|
|
1458
|
+
SUB: subtractNumbers,
|
|
1459
|
+
MUL: multiplyNumbers,
|
|
1460
|
+
DIV: divideNumbers,
|
|
1461
|
+
// 数值修约
|
|
1462
|
+
ROUND: round,
|
|
1463
|
+
ROUNDUP: roundUp,
|
|
1464
|
+
CEIL: roundUp,
|
|
1465
|
+
ROUNDDOWN: roundDown,
|
|
1466
|
+
FLOOR: roundDown,
|
|
1467
|
+
ROUNDBANK: roundHalfEven
|
|
1307
1468
|
};
|
|
1308
1469
|
for (const [name, fn] of Object.entries(FORMAT_FUNCTIONS)) {
|
|
1309
1470
|
engine.registerFunction(name, fn);
|
|
@@ -1348,7 +1509,7 @@ function evaluateTemplate(text, ctx) {
|
|
|
1348
1509
|
|
|
1349
1510
|
// src/render/data-binder.ts
|
|
1350
1511
|
function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
1351
|
-
const data = printData ?? {};
|
|
1512
|
+
const data = { ...resolveSystemVariables(), ...printData ?? {} };
|
|
1352
1513
|
const bound = JSON.parse(JSON.stringify(template));
|
|
1353
1514
|
if (bound.header?.elements) {
|
|
1354
1515
|
bound.header.elements = bound.header.elements.map((el) => bindElement(el, data, baseUrl));
|
|
@@ -1377,7 +1538,12 @@ function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
|
1377
1538
|
function bindElement(el, data, baseUrl) {
|
|
1378
1539
|
const cloned = { ...el, options: { ...el.options } };
|
|
1379
1540
|
if (typeof cloned.options.formatter === "string") {
|
|
1380
|
-
|
|
1541
|
+
const raw = cloned.options.formatter;
|
|
1542
|
+
if (referencesPageNumbers(raw)) {
|
|
1543
|
+
cloned.options.rawFormatter = raw;
|
|
1544
|
+
} else {
|
|
1545
|
+
cloned.options.formatter = evaluateTemplate(raw, data);
|
|
1546
|
+
}
|
|
1381
1547
|
}
|
|
1382
1548
|
const isImage = cloned.type === "image" || cloned.printElementType?.type === "image";
|
|
1383
1549
|
if (isImage && typeof cloned.options.src === "string") {
|
|
@@ -1424,39 +1590,25 @@ function bindTableData(el, data) {
|
|
|
1424
1590
|
if (dataStartIdx < 0) dataStartIdx = renderRows.length;
|
|
1425
1591
|
const ctx = itemCtx(item);
|
|
1426
1592
|
renderRows.push(makeRenderRow(row, (cell) => {
|
|
1427
|
-
|
|
1428
|
-
if (!formatter) return "";
|
|
1429
|
-
return evaluateTemplate(formatter, ctx);
|
|
1593
|
+
return resolveCellText(cell, ctx);
|
|
1430
1594
|
}));
|
|
1431
1595
|
dataRowCtx.push(ctx);
|
|
1432
1596
|
}
|
|
1433
1597
|
continue;
|
|
1434
1598
|
}
|
|
1435
1599
|
if (mode === "dynamic" && row.type === "subtotal") {
|
|
1436
|
-
const tpl = makeRenderRow(row, (cell) => {
|
|
1437
|
-
const formatter = cell.formatter;
|
|
1438
|
-
if (!formatter) return "";
|
|
1439
|
-
return evaluateTemplate(formatter, { rows: summaryRows, ...data });
|
|
1440
|
-
}, true);
|
|
1600
|
+
const tpl = makeRenderRow(row, (cell) => resolveCellText(cell, { rows: summaryRows, ...data }), true);
|
|
1441
1601
|
subtotalTemplates.push(tpl);
|
|
1442
1602
|
renderRows.push(tpl);
|
|
1443
1603
|
continue;
|
|
1444
1604
|
}
|
|
1445
1605
|
if (mode === "dynamic" && row.type === "summary") {
|
|
1446
|
-
const summaryRow = makeRenderRow(row, (cell) => {
|
|
1447
|
-
const formatter = cell.formatter;
|
|
1448
|
-
if (!formatter) return "";
|
|
1449
|
-
return evaluateTemplate(formatter, { rows: summaryRows, ...data });
|
|
1450
|
-
});
|
|
1606
|
+
const summaryRow = makeRenderRow(row, (cell) => resolveCellText(cell, { rows: summaryRows, ...data }));
|
|
1451
1607
|
summaryRenderRows.push(summaryRow);
|
|
1452
1608
|
renderRows.push(summaryRow);
|
|
1453
1609
|
continue;
|
|
1454
1610
|
}
|
|
1455
|
-
renderRows.push(makeRenderRow(row, (cell) =>
|
|
1456
|
-
const formatter = cell.formatter;
|
|
1457
|
-
if (!formatter) return "";
|
|
1458
|
-
return evaluateTemplate(formatter, data);
|
|
1459
|
-
}));
|
|
1611
|
+
renderRows.push(makeRenderRow(row, (cell) => resolveCellText(cell, data)));
|
|
1460
1612
|
}
|
|
1461
1613
|
opts._renderRows = renderRows;
|
|
1462
1614
|
opts._repeatHeaderCount = countRepeatHeader(rows);
|
|
@@ -1466,13 +1618,20 @@ function bindTableData(el, data) {
|
|
|
1466
1618
|
opts._summaryRows = summaryRenderRows;
|
|
1467
1619
|
opts._mainData = data;
|
|
1468
1620
|
}
|
|
1621
|
+
function resolveCellText(cell, ctx) {
|
|
1622
|
+
const formatter = cell.formatter;
|
|
1623
|
+
if (!formatter) return "";
|
|
1624
|
+
if (referencesPageNumbers(formatter)) return formatter;
|
|
1625
|
+
return evaluateTemplate(formatter, ctx);
|
|
1626
|
+
}
|
|
1469
1627
|
function makeRenderRow(row, resolve, keepRaw = false) {
|
|
1470
1628
|
return {
|
|
1471
1629
|
type: row.type,
|
|
1472
1630
|
height: row.height ?? 8,
|
|
1473
1631
|
cells: row.cells.map((cell) => ({
|
|
1474
1632
|
content: cell.merged ? "" : resolve(cell),
|
|
1475
|
-
|
|
1633
|
+
// 小计行(keepRaw)与引用页码的单元格都保留原始表达式:前者按当页数据行重算,后者按当页页码重算
|
|
1634
|
+
...(keepRaw || referencesPageNumbers(cell.formatter)) && !cell.merged ? { rawFormatter: cell.formatter ?? "" } : {},
|
|
1476
1635
|
cellType: cell.cellType,
|
|
1477
1636
|
barcodeType: cell.barcodeType,
|
|
1478
1637
|
qrCodeLevel: cell.qrCodeLevel,
|
|
@@ -1500,16 +1659,35 @@ function makeRenderRow(row, resolve, keepRaw = false) {
|
|
|
1500
1659
|
};
|
|
1501
1660
|
}
|
|
1502
1661
|
function countRepeatHeader(rows) {
|
|
1662
|
+
const headerCount = countLeadingHeaderRows(rows);
|
|
1663
|
+
if (headerCount === 0) return 0;
|
|
1664
|
+
const enabled = rows.slice(0, headerCount).some((row) => row.repeatOnPage === true);
|
|
1665
|
+
if (!enabled) return 0;
|
|
1666
|
+
return alignToRowspanBoundary(rows, headerCount);
|
|
1667
|
+
}
|
|
1668
|
+
function countLeadingHeaderRows(rows) {
|
|
1503
1669
|
let n = 0;
|
|
1504
1670
|
for (const row of rows) {
|
|
1505
|
-
if (row
|
|
1506
|
-
|
|
1507
|
-
} else {
|
|
1508
|
-
break;
|
|
1509
|
-
}
|
|
1671
|
+
if (row?.type !== "header") break;
|
|
1672
|
+
n++;
|
|
1510
1673
|
}
|
|
1511
1674
|
return n;
|
|
1512
1675
|
}
|
|
1676
|
+
function isRowspanComplete(rows, n) {
|
|
1677
|
+
for (let r = 0; r < n; r++) {
|
|
1678
|
+
for (const cell of rows[r]?.cells ?? []) {
|
|
1679
|
+
if (cell?.merged) continue;
|
|
1680
|
+
if (r + (cell?.rowspan ?? 1) > n) return false;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
return true;
|
|
1684
|
+
}
|
|
1685
|
+
function alignToRowspanBoundary(rows, max2) {
|
|
1686
|
+
for (let n = max2; n >= 1; n--) {
|
|
1687
|
+
if (isRowspanComplete(rows, n)) return n;
|
|
1688
|
+
}
|
|
1689
|
+
return 1;
|
|
1690
|
+
}
|
|
1513
1691
|
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1514
1692
|
function resolveSystemVariables(now = /* @__PURE__ */ new Date(), page = {}) {
|
|
1515
1693
|
return {
|
|
@@ -1519,6 +1697,9 @@ function resolveSystemVariables(now = /* @__PURE__ */ new Date(), page = {}) {
|
|
|
1519
1697
|
totalPages: page.totalPages ?? 1
|
|
1520
1698
|
};
|
|
1521
1699
|
}
|
|
1700
|
+
function referencesPageNumbers(expr) {
|
|
1701
|
+
return typeof expr === "string" && /\b(pageIndex|totalPages)\b/.test(expr);
|
|
1702
|
+
}
|
|
1522
1703
|
function injectSystemVariables(html, now = /* @__PURE__ */ new Date()) {
|
|
1523
1704
|
const { printDate, printTime } = resolveSystemVariables(now);
|
|
1524
1705
|
return html.replace(/\{printDate\}/g, printDate).replace(/\{printTime\}/g, printTime);
|
|
@@ -2520,6 +2701,13 @@ function specialRowHeight(renderRows, rowHeights, type) {
|
|
|
2520
2701
|
}
|
|
2521
2702
|
|
|
2522
2703
|
// src/render/html-generator.ts
|
|
2704
|
+
function pageVarsContext(vars) {
|
|
2705
|
+
return { ...vars.data ?? {}, pageIndex: vars.pageIndex, totalPages: vars.totalPages };
|
|
2706
|
+
}
|
|
2707
|
+
function pageVarsData(printData) {
|
|
2708
|
+
if (Array.isArray(printData)) return printData[0] ?? {};
|
|
2709
|
+
return printData ?? {};
|
|
2710
|
+
}
|
|
2523
2711
|
function generateHtml(template, pageLayouts, printData, options) {
|
|
2524
2712
|
const css = buildFontFaceCss(template.fonts) + buildPageCss(template, options?.pageHeightMm);
|
|
2525
2713
|
const isMeasure = options?.isMeasurementPass === true;
|
|
@@ -2604,22 +2792,25 @@ function renderPage(template, page, pageNum, totalPages, ctx, printData, pageCla
|
|
|
2604
2792
|
height: ctx.pageHeightMm && ctx.pageHeightMm > 0 ? ctx.pageHeightMm : paper.height
|
|
2605
2793
|
};
|
|
2606
2794
|
const contentWidth = paper.width - template.margins.left - template.margins.right;
|
|
2795
|
+
const pageVars = { pageIndex: pageNum, totalPages, data: pageVarsData(printData) };
|
|
2796
|
+
const scoped = withPageNumbers(template, pageVars);
|
|
2797
|
+
const pageCtx = { ...ctx, pageVars };
|
|
2607
2798
|
const headerHtml = renderAreaElements(
|
|
2608
|
-
|
|
2799
|
+
scoped.header?.elements ?? [],
|
|
2609
2800
|
contentWidth,
|
|
2610
2801
|
pageNum,
|
|
2611
2802
|
totalPages,
|
|
2612
|
-
|
|
2803
|
+
pageCtx
|
|
2613
2804
|
);
|
|
2614
2805
|
const footerHtml = renderAreaElements(
|
|
2615
|
-
|
|
2806
|
+
scoped.footer?.elements ?? [],
|
|
2616
2807
|
contentWidth,
|
|
2617
2808
|
pageNum,
|
|
2618
2809
|
totalPages,
|
|
2619
|
-
|
|
2810
|
+
pageCtx
|
|
2620
2811
|
);
|
|
2621
|
-
const overlayHtml = page.pageIndex === 0 ? `<div class="first-page-overlay">${renderAreaElements(
|
|
2622
|
-
let contentHtml = page.sections.map((section) => renderSection(section,
|
|
2812
|
+
const overlayHtml = page.pageIndex === 0 ? `<div class="first-page-overlay">${renderAreaElements(scoped.firstPageOverlay?.elements ?? [], contentWidth, pageNum, totalPages, pageCtx)}</div>` : "";
|
|
2813
|
+
let contentHtml = page.sections.map((section) => renderSection(section, scoped, pageCtx)).join("\n");
|
|
2623
2814
|
contentHtml = contentHtml.replace(/\{pageIndex\}/g, String(pageNum));
|
|
2624
2815
|
contentHtml = contentHtml.replace(/\{totalPages\}/g, String(totalPages));
|
|
2625
2816
|
const pageInner = `
|
|
@@ -2636,6 +2827,39 @@ function renderPage(template, page, pageNum, totalPages, ctx, printData, pageCla
|
|
|
2636
2827
|
${pageBody}
|
|
2637
2828
|
</section>`;
|
|
2638
2829
|
}
|
|
2830
|
+
function withPageNumbers(template, vars) {
|
|
2831
|
+
if (!templateReferencesPageNumbers(template)) return template;
|
|
2832
|
+
const context = pageVarsContext(vars);
|
|
2833
|
+
const mapEl = (el) => {
|
|
2834
|
+
const raw = el.options?.rawFormatter;
|
|
2835
|
+
if (typeof raw !== "string") return el;
|
|
2836
|
+
return { ...el, options: { ...el.options, formatter: evaluateTemplate(raw, context) } };
|
|
2837
|
+
};
|
|
2838
|
+
const mapArea = (area) => area ? { ...area, elements: (area.elements ?? []).map(mapEl) } : area;
|
|
2839
|
+
return {
|
|
2840
|
+
...template,
|
|
2841
|
+
elements: template.elements.map(mapEl),
|
|
2842
|
+
header: mapArea(template.header),
|
|
2843
|
+
footer: mapArea(template.footer),
|
|
2844
|
+
firstPageOverlay: mapArea(template.firstPageOverlay)
|
|
2845
|
+
};
|
|
2846
|
+
}
|
|
2847
|
+
function templateReferencesPageNumbers(template) {
|
|
2848
|
+
const areas = [
|
|
2849
|
+
template.elements,
|
|
2850
|
+
template.header?.elements,
|
|
2851
|
+
template.footer?.elements,
|
|
2852
|
+
template.firstPageOverlay?.elements
|
|
2853
|
+
];
|
|
2854
|
+
return areas.some((list) => (list ?? []).some((el) => typeof el.options?.rawFormatter === "string"));
|
|
2855
|
+
}
|
|
2856
|
+
function resolveCellContent(cell, ctx) {
|
|
2857
|
+
const raw = cell.rawFormatter;
|
|
2858
|
+
if (typeof raw === "string" && raw !== "" && ctx?.pageVars) {
|
|
2859
|
+
return evaluateTemplate(raw, pageVarsContext(ctx.pageVars));
|
|
2860
|
+
}
|
|
2861
|
+
return cell.content;
|
|
2862
|
+
}
|
|
2639
2863
|
function renderSection(section, template, ctx) {
|
|
2640
2864
|
const el = findElement(template, section.elementId);
|
|
2641
2865
|
if (!el) {
|
|
@@ -2788,7 +3012,7 @@ function matrixCellStyle(cell, opts) {
|
|
|
2788
3012
|
}
|
|
2789
3013
|
return parts.join(";");
|
|
2790
3014
|
}
|
|
2791
|
-
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOwner = { elementId: "", kind: "b" }) {
|
|
3015
|
+
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOwner = { elementId: "", kind: "b" }, rowLimit) {
|
|
2792
3016
|
const trs = [];
|
|
2793
3017
|
const defaultPadding = opts.tableDefaultPadding ?? 1;
|
|
2794
3018
|
for (let r = start; r < end; r++) {
|
|
@@ -2796,12 +3020,14 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2796
3020
|
if (!row) continue;
|
|
2797
3021
|
const idxAttr = withRowIndex ? ` data-row-index="${r}"` : "";
|
|
2798
3022
|
const tds = row.cells.map((cell, ci) => ({ cell, ci })).filter(({ cell }) => !cell.merged).map(({ cell, ci }) => {
|
|
2799
|
-
const
|
|
3023
|
+
const rowspan = rowLimit === void 0 ? cell.rowspan ?? 1 : Math.max(1, Math.min(cell.rowspan ?? 1, rowLimit - r));
|
|
3024
|
+
const span = `${rowspan > 1 ? ` rowspan="${rowspan}"` : ""}${cell.colspan > 1 ? ` colspan="${cell.colspan}"` : ""}`;
|
|
2800
3025
|
const colIndex = ci;
|
|
2801
3026
|
let inner;
|
|
2802
3027
|
if (cell.cellType === "barcode" || cell.cellType === "qrcode") {
|
|
2803
|
-
|
|
2804
|
-
|
|
3028
|
+
const codeValue = resolveCellContent(cell, ctx);
|
|
3029
|
+
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;">${codeImgHtml(codeValue, cell.cellType, cell, {
|
|
3030
|
+
fallback: esc(codeValue),
|
|
2805
3031
|
codeRenderer: ctx?.codeRenderer,
|
|
2806
3032
|
fit: cell.fit,
|
|
2807
3033
|
maxWidth: cell.maxWidth,
|
|
@@ -2815,9 +3041,9 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2815
3041
|
const fit = cell.fit || "contain";
|
|
2816
3042
|
const maxWidth = cell.maxWidth ? `max-width:${cell.maxWidth}mm;` : "max-width:100%;";
|
|
2817
3043
|
const maxHeight = cell.maxHeight ? `max-height:${cell.maxHeight}mm;` : "max-height:100%;";
|
|
2818
|
-
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;"><img src="${esc(cell
|
|
3044
|
+
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>`;
|
|
2819
3045
|
} else {
|
|
2820
|
-
inner = renderTextCellInner(renderRows, r, colIndex, cell, opts, fitOwner, defaultPadding);
|
|
3046
|
+
inner = renderTextCellInner(renderRows, r, colIndex, cell, opts, fitOwner, defaultPadding, ctx);
|
|
2821
3047
|
}
|
|
2822
3048
|
return `<td${span} style="${matrixCellStyle(cell, opts)}">${inner}</td>`;
|
|
2823
3049
|
}).join("");
|
|
@@ -2825,9 +3051,9 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOw
|
|
|
2825
3051
|
}
|
|
2826
3052
|
return trs.join("\n");
|
|
2827
3053
|
}
|
|
2828
|
-
function renderTextCellInner(renderRows, rowIndex, colIndex, cell, opts, fitOwner, defaultPadding) {
|
|
3054
|
+
function renderTextCellInner(renderRows, rowIndex, colIndex, cell, opts, fitOwner, defaultPadding, ctx) {
|
|
2829
3055
|
const fit = resolveCellTextFit(cell);
|
|
2830
|
-
const text = esc(cell
|
|
3056
|
+
const text = esc(resolveCellContent(cell, ctx));
|
|
2831
3057
|
if (fit === "autoHeight") return text;
|
|
2832
3058
|
const capMm = cellFitCapMm(renderRows, rowIndex, cell, defaultPadding);
|
|
2833
3059
|
const nowrap = cell.wordWrap === false;
|
|
@@ -2865,7 +3091,7 @@ function renderTableSlice(el, section, ctx) {
|
|
|
2865
3091
|
const startRow = section.startRow ?? 0;
|
|
2866
3092
|
const endRow = section.endRow ?? renderRows.length;
|
|
2867
3093
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
2868
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
3094
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }, repeatCount) : "";
|
|
2869
3095
|
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
2870
3096
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
2871
3097
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
|
@@ -2886,9 +3112,15 @@ function renderSubtotalRows(el, section, opts, ctx) {
|
|
|
2886
3112
|
const dataStart = Math.max(startRow, dataStartIdx);
|
|
2887
3113
|
const dataEnd = Math.max(endRow, dataStart);
|
|
2888
3114
|
const pageCtx = dataEnd > dataStartIdx ? dataRowCtx.slice(Math.max(dataStart - dataStartIdx, 0), dataEnd - dataStartIdx) : [];
|
|
3115
|
+
const pageVars = ctx?.pageVars ? pageVarsContext(ctx.pageVars) : {};
|
|
2889
3116
|
const rows = templates.map((tpl) => ({
|
|
2890
3117
|
...tpl,
|
|
2891
|
-
cells: tpl.cells.map((cell) => cell.rawFormatter ? {
|
|
3118
|
+
cells: tpl.cells.map((cell) => cell.rawFormatter ? {
|
|
3119
|
+
...cell,
|
|
3120
|
+
content: evaluateTemplate(cell.rawFormatter, { rows: pageCtx, ...mainData, ...pageVars }),
|
|
3121
|
+
// 已按本页上下文求值,清标记避免渲染时再按页码重算一次(会丢掉 rows)
|
|
3122
|
+
rawFormatter: ""
|
|
3123
|
+
} : cell)
|
|
2892
3124
|
}));
|
|
2893
3125
|
return renderMatrixRows(rows, 0, rows.length, opts, false, ctx, { elementId: el.id, kind: "st" });
|
|
2894
3126
|
}
|
|
@@ -2911,7 +3143,7 @@ function renderFlowGroup(el, section, template, ctx) {
|
|
|
2911
3143
|
if (endRow > startRow || section.subtotal || section.summary) {
|
|
2912
3144
|
const renderRows = opts._renderRows ?? [];
|
|
2913
3145
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
2914
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
3146
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }, repeatCount) : "";
|
|
2915
3147
|
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
2916
3148
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
2917
3149
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
package/dist/browser/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-
|
|
2
|
-
import { P as PrintRuntime, F as FitFontSize } from '../ports-
|
|
1
|
+
import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-Dn_YAzO5.cjs';
|
|
2
|
+
import { P as PrintRuntime, F as FitFontSize } from '../ports-Cf5sjwls.cjs';
|
|
3
3
|
|
|
4
4
|
interface BrowserRenderResult {
|
|
5
5
|
/** 最终多页 HTML 字符串 */
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-
|
|
2
|
-
import { P as PrintRuntime, F as FitFontSize } from '../ports-
|
|
1
|
+
import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-Dn_YAzO5.js';
|
|
2
|
+
import { P as PrintRuntime, F as FitFontSize } from '../ports-BvwlA_km.js';
|
|
3
3
|
|
|
4
4
|
interface BrowserRenderResult {
|
|
5
5
|
/** 最终多页 HTML 字符串 */
|
package/dist/browser/index.js
CHANGED