@worm-vue3-print/core 1.2.1 → 1.3.0
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/README.md +39 -7
- package/dist/browser/index.cjs +3686 -0
- package/dist/browser/index.d.cts +96 -0
- package/dist/browser/index.d.ts +96 -0
- package/dist/browser/index.js +325 -0
- package/dist/chunk-V4A5623C.js +31 -0
- package/dist/chunk-VFEURLAZ.js +3579 -0
- package/dist/designer/index.cjs +2641 -0
- package/dist/designer/index.d.cts +448 -0
- package/dist/designer/index.d.ts +448 -0
- package/dist/designer/index.js +1710 -0
- package/dist/dom-executor.iife.global.js +8 -0
- package/dist/driver-CsWkGK4a.d.cts +932 -0
- package/dist/driver-CsWkGK4a.d.ts +932 -0
- package/dist/index.cjs +1935 -120
- package/dist/index.d.cts +354 -185
- package/dist/index.d.ts +354 -185
- package/dist/index.js +197 -1765
- package/dist/node/index.cjs +41 -0
- package/dist/node/index.d.cts +6 -0
- package/dist/node/index.d.ts +6 -0
- package/dist/node/index.js +10 -0
- package/dist/ports-B63x7kCX.d.ts +102 -0
- package/dist/ports-q934kIC7.d.cts +102 -0
- package/package.json +26 -3
package/dist/index.cjs
CHANGED
|
@@ -20,38 +20,118 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
DEFAULT_READINESS_MS: () => DEFAULT_READINESS_MS,
|
|
24
|
+
DEFAULT_SHRINK_MIN_FONT_SIZE_PT: () => DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
|
|
25
|
+
DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
|
|
26
|
+
EXECUTOR_TARGETS: () => EXECUTOR_TARGETS,
|
|
27
|
+
FALLBACK_FONT_STACK: () => FALLBACK_FONT_STACK,
|
|
28
|
+
MAX_BATCH_COPIES: () => MAX_BATCH_COPIES,
|
|
29
|
+
MICROMETERS_PER_INCH: () => MICROMETERS_PER_INCH,
|
|
30
|
+
MICROMETERS_PER_MM: () => MICROMETERS_PER_MM,
|
|
31
|
+
MIN_CONTINUOUS_HEIGHT_MM: () => MIN_CONTINUOUS_HEIGHT_MM,
|
|
32
|
+
MIN_SHRINK_FONT_SIZE_PT: () => MIN_SHRINK_FONT_SIZE_PT,
|
|
33
|
+
MM_PER_INCH: () => MM_PER_INCH,
|
|
34
|
+
MM_PER_PX: () => MM_PER_PX,
|
|
23
35
|
PAPER_DIMENSIONS: () => PAPER_DIMENSIONS,
|
|
36
|
+
PX_PER_MM: () => PX_PER_MM,
|
|
37
|
+
PrintFailure: () => PrintFailure,
|
|
38
|
+
TILE_DEFAULTS: () => TILE_DEFAULTS,
|
|
24
39
|
TemplateEngine: () => TemplateEngine,
|
|
40
|
+
TilingError: () => TilingError,
|
|
41
|
+
WATERMARK_DEFAULTS: () => WATERMARK_DEFAULTS,
|
|
42
|
+
WATERMARK_DENSITY_PRESETS: () => WATERMARK_DENSITY_PRESETS,
|
|
43
|
+
applyTextFitSizes: () => applyTextFitSizes,
|
|
25
44
|
avg: () => avg,
|
|
26
45
|
bindData: () => bindData,
|
|
46
|
+
buildBasePageCss: () => buildBasePageCss,
|
|
47
|
+
buildFontFaceCss: () => buildFontFaceCss,
|
|
27
48
|
buildPageCss: () => buildPageCss,
|
|
49
|
+
buildPageGeometryCss: () => buildPageGeometryCss,
|
|
50
|
+
buildPageRuleCss: () => buildPageRuleCss,
|
|
51
|
+
buildPdfTargetSpec: () => buildPdfTargetSpec,
|
|
52
|
+
buildScreenshotTargetSpec: () => buildScreenshotTargetSpec,
|
|
53
|
+
cellFitCapMm: () => cellFitCapMm,
|
|
54
|
+
cellFitKey: () => cellFitKey,
|
|
55
|
+
codeSpecKey: () => codeSpecKey,
|
|
28
56
|
compileTemplate: () => compileTemplate,
|
|
57
|
+
composeBatchHtml: () => composeBatchHtml,
|
|
58
|
+
composeContinuousHeight: () => composeContinuousHeight,
|
|
59
|
+
composeMultiPageDocument: () => composeMultiPageDocument,
|
|
60
|
+
composeTiledHtml: () => composeTiledHtml,
|
|
61
|
+
computeMaxColumns: () => computeMaxColumns,
|
|
62
|
+
computeTileLayout: () => computeTileLayout,
|
|
29
63
|
count: () => count,
|
|
64
|
+
createCollectingCodeRenderer: () => createCollectingCodeRenderer,
|
|
65
|
+
createDomHostRuntime: () => createDomHostRuntime,
|
|
66
|
+
createMapCodeRenderer: () => createMapCodeRenderer,
|
|
30
67
|
elementPositionStyle: () => elementPositionStyle,
|
|
68
|
+
escapeHeightMm: () => escapeHeightMm,
|
|
69
|
+
escapeInlineStyleValue: () => escapeInlineStyleValue,
|
|
31
70
|
evaluate: () => evaluate,
|
|
32
71
|
evaluateTemplate: () => evaluateTemplate,
|
|
72
|
+
floorFontSize: () => floorFontSize,
|
|
33
73
|
formatDate: () => formatDate,
|
|
34
74
|
formatMoney: () => formatMoney,
|
|
75
|
+
formatTimestamp: () => formatTimestamp,
|
|
35
76
|
generateHtml: () => generateHtml,
|
|
36
77
|
getByPath: () => getByPath,
|
|
37
78
|
getPaperDimensions: () => getPaperDimensions,
|
|
38
79
|
ifFn: () => ifFn,
|
|
39
80
|
injectSystemVariables: () => injectSystemVariables,
|
|
81
|
+
isContinuousPaper: () => isContinuousPaper,
|
|
82
|
+
isContinuousPaperSize: () => isContinuousPaperSize,
|
|
83
|
+
isMultiPageTemplate: () => isMultiPageTemplate,
|
|
84
|
+
isWatermarkVisible: () => isWatermarkVisible,
|
|
40
85
|
max: () => max,
|
|
86
|
+
mergeCodeMaps: () => mergeCodeMaps,
|
|
87
|
+
mergeFontDeclarations: () => mergeFontDeclarations,
|
|
88
|
+
micrometersToMillimeters: () => micrometersToMillimeters,
|
|
89
|
+
millimetersToInches: () => millimetersToInches,
|
|
90
|
+
millimetersToMicrometers: () => millimetersToMicrometers,
|
|
41
91
|
min: () => min,
|
|
42
92
|
mm: () => mm,
|
|
93
|
+
mmToPx: () => mmToPx,
|
|
94
|
+
normalizeMeasurements: () => normalizeMeasurements,
|
|
95
|
+
normalizePrintData: () => normalizePrintData,
|
|
96
|
+
normalizeTemplate: () => normalizeTemplate,
|
|
97
|
+
normalizeTilingOptions: () => normalizeTilingOptions,
|
|
43
98
|
paginate: () => paginate,
|
|
99
|
+
paperViewportPx: () => paperViewportPx,
|
|
44
100
|
parse: () => parse,
|
|
101
|
+
parseCellFitKey: () => parseCellFitKey,
|
|
45
102
|
parseTemplate: () => parseTemplate,
|
|
103
|
+
prepareDocument: () => prepareDocument,
|
|
104
|
+
pxToMm: () => pxToMm,
|
|
105
|
+
renderPdf: () => renderPdf,
|
|
106
|
+
renderScreenshot: () => renderScreenshot,
|
|
46
107
|
renderTemplate: () => renderTemplate,
|
|
108
|
+
renderWatermarkLayerHtml: () => renderWatermarkLayerHtml,
|
|
109
|
+
renderWatermarkTileSvg: () => renderWatermarkTileSvg,
|
|
110
|
+
resolveCellTextFit: () => resolveCellTextFit,
|
|
111
|
+
resolveElementTextFit: () => resolveElementTextFit,
|
|
112
|
+
resolvePaperMm: () => resolvePaperMm,
|
|
113
|
+
resolveSheetMm: () => resolveSheetMm,
|
|
114
|
+
resolveShrinkMinFontSize: () => resolveShrinkMinFontSize,
|
|
115
|
+
resolveSystemVariables: () => resolveSystemVariables,
|
|
116
|
+
resolveWatermarkLayout: () => resolveWatermarkLayout,
|
|
117
|
+
resolveWatermarkText: () => resolveWatermarkText,
|
|
118
|
+
roundFontSize: () => roundFontSize,
|
|
119
|
+
roundMm: () => roundMm,
|
|
47
120
|
safeEval: () => safeEval,
|
|
48
121
|
setPageIndex: () => setPageIndex,
|
|
49
122
|
setTotalPages: () => setTotalPages,
|
|
50
123
|
sum: () => sum,
|
|
51
124
|
systemVars: () => systemVars,
|
|
52
125
|
tableDesignBottom: () => tableDesignBottom,
|
|
126
|
+
tilePosition: () => tilePosition,
|
|
127
|
+
toElectronPrintToPdfOptions: () => toElectronPrintToPdfOptions,
|
|
128
|
+
toFontFamilyStack: () => toFontFamilyStack,
|
|
129
|
+
toPlaywrightPdfOptions: () => toPlaywrightPdfOptions,
|
|
130
|
+
toPrintFailure: () => toPrintFailure,
|
|
53
131
|
toUpperCaseAmount: () => toUpperCaseAmount,
|
|
54
|
-
tokenize: () => tokenize
|
|
132
|
+
tokenize: () => tokenize,
|
|
133
|
+
validateTiling: () => validateTiling,
|
|
134
|
+
withTimeout: () => withTimeout
|
|
55
135
|
});
|
|
56
136
|
module.exports = __toCommonJS(index_exports);
|
|
57
137
|
|
|
@@ -641,8 +721,8 @@ function formatDate(value, fmt) {
|
|
|
641
721
|
return String(value);
|
|
642
722
|
}
|
|
643
723
|
if (isNaN(date.getTime())) return String(value);
|
|
644
|
-
const
|
|
645
|
-
return fmt.replace("YYYY", String(date.getFullYear())).replace("MM",
|
|
724
|
+
const pad3 = (n) => String(n).padStart(2, "0");
|
|
725
|
+
return fmt.replace("YYYY", String(date.getFullYear())).replace("MM", pad3(date.getMonth() + 1)).replace("DD", pad3(date.getDate())).replace("HH", pad3(date.getHours())).replace("mm", pad3(date.getMinutes())).replace("ss", pad3(date.getSeconds()));
|
|
646
726
|
}
|
|
647
727
|
function toUpperCaseAmount(value) {
|
|
648
728
|
const num = Number(value);
|
|
@@ -812,9 +892,8 @@ function evaluateTemplate(text, ctx) {
|
|
|
812
892
|
}
|
|
813
893
|
|
|
814
894
|
// src/render/data-binder.ts
|
|
815
|
-
function bindData(template, printData, baseUrl) {
|
|
816
|
-
const
|
|
817
|
-
const data = Array.isArray(raw) ? raw[0] ?? {} : raw;
|
|
895
|
+
function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
896
|
+
const data = printData ?? {};
|
|
818
897
|
const bound = JSON.parse(JSON.stringify(template));
|
|
819
898
|
if (bound.header?.elements) {
|
|
820
899
|
bound.header.elements = bound.header.elements.map((el) => bindElement(el, data, baseUrl));
|
|
@@ -826,6 +905,18 @@ function bindData(template, printData, baseUrl) {
|
|
|
826
905
|
bound.firstPageOverlay.elements = bound.firstPageOverlay.elements.map((el) => bindElement(el, data, baseUrl));
|
|
827
906
|
}
|
|
828
907
|
bound.elements = bound.elements.map((el) => bindElement(el, data, baseUrl));
|
|
908
|
+
const fontBase = fontBaseUrl ?? baseUrl;
|
|
909
|
+
if (fontBase && bound.fonts?.length) {
|
|
910
|
+
const prefix = fontBase.replace(/\/+$/, "");
|
|
911
|
+
bound.fonts = bound.fonts.map((font) => ({
|
|
912
|
+
...font,
|
|
913
|
+
files: (font.files ?? []).map((file) => ({
|
|
914
|
+
...file,
|
|
915
|
+
// 绝对 URL(含协议相对 //)原样使用
|
|
916
|
+
url: file.url?.startsWith("/") && !file.url.startsWith("//") ? prefix + file.url : file.url
|
|
917
|
+
}))
|
|
918
|
+
}));
|
|
919
|
+
}
|
|
829
920
|
return bound;
|
|
830
921
|
}
|
|
831
922
|
function bindElement(el, data, baseUrl) {
|
|
@@ -931,6 +1022,7 @@ function makeRenderRow(row, resolve, keepRaw = false) {
|
|
|
931
1022
|
barcodeType: cell.barcodeType,
|
|
932
1023
|
qrCodeLevel: cell.qrCodeLevel,
|
|
933
1024
|
showBarcodeText: cell.showBarcodeText,
|
|
1025
|
+
printerDpi: cell.printerDpi,
|
|
934
1026
|
fit: cell.fit,
|
|
935
1027
|
maxWidth: cell.maxWidth,
|
|
936
1028
|
maxHeight: cell.maxHeight,
|
|
@@ -940,12 +1032,15 @@ function makeRenderRow(row, resolve, keepRaw = false) {
|
|
|
940
1032
|
align: cell.align,
|
|
941
1033
|
valign: cell.valign,
|
|
942
1034
|
fontSize: cell.fontSize,
|
|
1035
|
+
fontFamily: cell.fontFamily,
|
|
943
1036
|
fontWeight: cell.fontWeight,
|
|
944
1037
|
color: cell.color,
|
|
945
1038
|
backgroundColor: cell.backgroundColor,
|
|
946
1039
|
borders: cell.borders,
|
|
947
1040
|
padding: cell.padding,
|
|
948
|
-
wordWrap: cell.wordWrap
|
|
1041
|
+
wordWrap: cell.wordWrap,
|
|
1042
|
+
textFit: cell.textFit,
|
|
1043
|
+
shrinkMinFontSize: cell.shrinkMinFontSize
|
|
949
1044
|
}))
|
|
950
1045
|
};
|
|
951
1046
|
}
|
|
@@ -960,10 +1055,63 @@ function countRepeatHeader(rows) {
|
|
|
960
1055
|
}
|
|
961
1056
|
return n;
|
|
962
1057
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1058
|
+
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1059
|
+
function resolveSystemVariables(now = /* @__PURE__ */ new Date(), page = {}) {
|
|
1060
|
+
return {
|
|
1061
|
+
printDate: `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`,
|
|
1062
|
+
printTime: `${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`,
|
|
1063
|
+
pageIndex: page.pageIndex ?? 1,
|
|
1064
|
+
totalPages: page.totalPages ?? 1
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
function injectSystemVariables(html, now = /* @__PURE__ */ new Date()) {
|
|
1068
|
+
const { printDate, printTime } = resolveSystemVariables(now);
|
|
1069
|
+
return html.replace(/\{printDate\}/g, printDate).replace(/\{printTime\}/g, printTime);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// src/print/fonts.ts
|
|
1073
|
+
function buildFontFaceCss(fonts) {
|
|
1074
|
+
const blocks = [];
|
|
1075
|
+
for (const font of fonts ?? []) {
|
|
1076
|
+
const family = font?.family?.trim();
|
|
1077
|
+
if (!family) continue;
|
|
1078
|
+
const quoted = `"${family.replace(/"/g, "")}"`;
|
|
1079
|
+
for (const file of font.files ?? []) {
|
|
1080
|
+
const url = file?.url?.trim();
|
|
1081
|
+
if (!url) continue;
|
|
1082
|
+
const weight = Number.isFinite(file.weight) ? Number(file.weight) : 400;
|
|
1083
|
+
const style = file.style === "italic" ? "italic" : "normal";
|
|
1084
|
+
blocks.push(
|
|
1085
|
+
`@font-face{font-family:${quoted};src:url("${url}")${fontFormatHint(url)};font-weight:${weight};font-style:${style};font-display:block;}`
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
return blocks.length ? `${blocks.join("")}
|
|
1090
|
+
` : "";
|
|
1091
|
+
}
|
|
1092
|
+
function fontFormatHint(url) {
|
|
1093
|
+
const path = url.split(/[?#]/)[0].toLowerCase();
|
|
1094
|
+
if (path.endsWith(".woff2")) return ' format("woff2")';
|
|
1095
|
+
if (path.endsWith(".woff")) return ' format("woff")';
|
|
1096
|
+
if (path.endsWith(".ttf")) return ' format("truetype")';
|
|
1097
|
+
if (path.endsWith(".otf")) return ' format("opentype")';
|
|
1098
|
+
return "";
|
|
1099
|
+
}
|
|
1100
|
+
var FALLBACK_FONT_STACK = [
|
|
1101
|
+
'"Microsoft YaHei"',
|
|
1102
|
+
'"PingFang SC"',
|
|
1103
|
+
'"Helvetica Neue"',
|
|
1104
|
+
"Arial",
|
|
1105
|
+
"sans-serif"
|
|
1106
|
+
];
|
|
1107
|
+
function escapeInlineStyleValue(cssValue) {
|
|
1108
|
+
return cssValue.replace(/&/g, "&").replace(/"/g, """);
|
|
1109
|
+
}
|
|
1110
|
+
function toFontFamilyStack(family) {
|
|
1111
|
+
const name = family?.trim();
|
|
1112
|
+
if (!name) return FALLBACK_FONT_STACK.join(", ");
|
|
1113
|
+
const head = name.includes(",") ? name : `"${name.replace(/"/g, "")}"`;
|
|
1114
|
+
return [head, ...FALLBACK_FONT_STACK].join(", ");
|
|
967
1115
|
}
|
|
968
1116
|
|
|
969
1117
|
// src/render/types.ts
|
|
@@ -973,38 +1121,81 @@ var PAPER_DIMENSIONS = {
|
|
|
973
1121
|
A5: { width: 148, height: 210 },
|
|
974
1122
|
Letter: { width: 216, height: 279 },
|
|
975
1123
|
Legal: { width: 216, height: 356 },
|
|
976
|
-
|
|
1124
|
+
// 针式打印纸(241 系列等分):11 英寸整张 279.4mm 按等分取整
|
|
1125
|
+
DOT_FULL: { width: 241, height: 279.4 },
|
|
1126
|
+
DOT_HALF: { width: 241, height: 139.7 },
|
|
1127
|
+
DOT_THIRD: { width: 241, height: 93.1 },
|
|
1128
|
+
// 标签纸
|
|
1129
|
+
LABEL_80X60: { width: 80, height: 60 },
|
|
1130
|
+
LABEL_60X40: { width: 60, height: 40 },
|
|
1131
|
+
LABEL_40X30: { width: 40, height: 30 },
|
|
1132
|
+
// 小票纸(热敏卷纸):高度仅为设计画布高度,出纸按内容推导
|
|
1133
|
+
THERMAL_57: { width: 57, height: 297 },
|
|
1134
|
+
THERMAL_80: { width: 80, height: 297 },
|
|
1135
|
+
THERMAL_110: { width: 110, height: 297 },
|
|
1136
|
+
CUSTOM: { width: 210, height: 297 },
|
|
1137
|
+
// 连续纸:默认 80mm 热敏;高度仅为设计画布高度,出纸按内容推导
|
|
1138
|
+
CONTINUOUS: { width: 80, height: 297 }
|
|
977
1139
|
};
|
|
1140
|
+
var CONTINUOUS_PAPER_SIZES = /* @__PURE__ */ new Set([
|
|
1141
|
+
"CONTINUOUS",
|
|
1142
|
+
"THERMAL_57",
|
|
1143
|
+
"THERMAL_80",
|
|
1144
|
+
"THERMAL_110"
|
|
1145
|
+
]);
|
|
1146
|
+
function isContinuousPaperSize(paperSize) {
|
|
1147
|
+
return CONTINUOUS_PAPER_SIZES.has(paperSize);
|
|
1148
|
+
}
|
|
978
1149
|
function getPaperDimensions(template) {
|
|
979
|
-
const
|
|
980
|
-
|
|
1150
|
+
const continuous = isContinuousPaperSize(template.paperSize);
|
|
1151
|
+
const base = template.paperSize === "CUSTOM" || continuous ? {
|
|
1152
|
+
width: template.customWidth ?? PAPER_DIMENSIONS[template.paperSize].width,
|
|
1153
|
+
height: template.customHeight ?? PAPER_DIMENSIONS[template.paperSize].height
|
|
1154
|
+
} : PAPER_DIMENSIONS[template.paperSize];
|
|
1155
|
+
if (template.orientation === "landscape" && !continuous) {
|
|
981
1156
|
return { width: base.height, height: base.width };
|
|
982
1157
|
}
|
|
983
1158
|
return { ...base };
|
|
984
1159
|
}
|
|
1160
|
+
function getOutputPaperDimensions(template) {
|
|
1161
|
+
const continuous = isContinuousPaperSize(template.paperSize);
|
|
1162
|
+
if (continuous || template.tiling?.enabled === true) {
|
|
1163
|
+
return getPaperDimensions(template);
|
|
1164
|
+
}
|
|
1165
|
+
const design = getPaperDimensions(template);
|
|
1166
|
+
const swap = template.outputRotation === 90 || template.outputRotation === 270;
|
|
1167
|
+
return swap ? { width: design.height, height: design.width } : design;
|
|
1168
|
+
}
|
|
1169
|
+
function getOutputRotationAngle(template) {
|
|
1170
|
+
const continuous = isContinuousPaperSize(template.paperSize);
|
|
1171
|
+
if (continuous || template.tiling?.enabled === true) return 0;
|
|
1172
|
+
return template.outputRotation ?? 0;
|
|
1173
|
+
}
|
|
1174
|
+
function isContinuousPaper(template) {
|
|
1175
|
+
return isContinuousPaperSize(template.paperSize);
|
|
1176
|
+
}
|
|
985
1177
|
|
|
986
1178
|
// src/render/css-builder.ts
|
|
987
1179
|
function mm(value) {
|
|
988
1180
|
return `${value}mm`;
|
|
989
1181
|
}
|
|
990
|
-
function
|
|
991
|
-
const
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
const
|
|
996
|
-
|
|
1182
|
+
function resolveOuterPaper(template, pageHeightMm) {
|
|
1183
|
+
const out = getOutputPaperDimensions(template);
|
|
1184
|
+
return pageHeightMm && pageHeightMm > 0 && isContinuousPaper(template) ? { width: out.width, height: pageHeightMm } : out;
|
|
1185
|
+
}
|
|
1186
|
+
function resolveAreaPaper(template, pageHeightMm) {
|
|
1187
|
+
const design = getPaperDimensions(template);
|
|
1188
|
+
return pageHeightMm && pageHeightMm > 0 && isContinuousPaper(template) ? { width: design.width, height: pageHeightMm } : design;
|
|
1189
|
+
}
|
|
1190
|
+
function screenBlock() {
|
|
997
1191
|
return `
|
|
998
|
-
/* \u2500\u2500 \u6253\u5370\u7EB8\u5F20\uFF1A\u6D4F\u89C8\u5668\u539F\u751F\u6253\u5370\u6309\u6B64\u5C3A\u5BF8\u5206\u9875\uFF08Playwright page.pdf \u4EE5\u663E\u5F0F\u5BBD\u9AD8\u4E3A\u51C6\uFF0C\u65E0\u526F\u4F5C\u7528\uFF09 \u2500\u2500 */
|
|
999
|
-
@page { size: ${mm(paper.width)} ${mm(paper.height)}; margin: 0; }
|
|
1000
|
-
|
|
1001
1192
|
/* \u2500\u2500 \u5168\u5C40\u91CD\u7F6E \u2500\u2500 */
|
|
1002
1193
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
1003
1194
|
|
|
1004
1195
|
/* \u6253\u5370\u5FC5\u987B\u4FDD\u7559\u5143\u7D20\u80CC\u666F\u8272\uFF08Chromium \u9ED8\u8BA4\u5254\u9664\u80CC\u666F\uFF0C\u9700\u663E\u5F0F\u58F0\u660E\uFF09 */
|
|
1005
1196
|
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1006
1197
|
|
|
1007
|
-
body { font-family: "
|
|
1198
|
+
body { font-family: ${FALLBACK_FONT_STACK.join(", ")}; }
|
|
1008
1199
|
|
|
1009
1200
|
/* \u2500\u2500 \u5C4F\u5E55\u9884\u89C8\uFF1A\u7070\u5E95 + \u7EB8\u5F20\u9634\u5F71/\u9875\u95F4\u8DDD\uFF1B\u6253\u5370\u65F6\u53BB\u9664 \u2500\u2500 */
|
|
1010
1201
|
@media screen {
|
|
@@ -1015,13 +1206,110 @@ body { font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, s
|
|
|
1015
1206
|
body { background: #fff; }
|
|
1016
1207
|
.print-page { margin: 0; box-shadow: none; }
|
|
1017
1208
|
}
|
|
1209
|
+
`;
|
|
1210
|
+
}
|
|
1211
|
+
function watermarkBlock() {
|
|
1212
|
+
return `
|
|
1213
|
+
/* \u2500\u2500 \u6C34\u5370\u5C42\uFF1A\u8986\u76D6\u6574\u9875\u3001\u4F4D\u4E8E\u6240\u6709\u5185\u5BB9\u4E4B\u4E0B\uFF08\u663E\u5F0F\u77E2\u91CF\u74E6\u7247\uFF0C\u7981\u6B62\u7528 CSS \u5E73\u94FA\u80CC\u666F\uFF1A
|
|
1214
|
+
Chromium \u4F1A\u628A\u5B83\u7F16\u8BD1\u6210 PDF \u5E73\u94FA\u56FE\u6848\uFF0C\u51FA\u7EB8\u94FE\u8DEF\u7684 RIP \u4F1A\u5FFD\u7565\u56FE\u6848\u77E9\u9635\u5BFC\u81F4\u6C34\u5370\u653E\u5927/\u9519\u4F4D\uFF09 \u2500\u2500 */
|
|
1215
|
+
.watermark-layer {
|
|
1216
|
+
position: absolute;
|
|
1217
|
+
top: 0;
|
|
1218
|
+
left: 0;
|
|
1219
|
+
width: 100%;
|
|
1220
|
+
height: 100%;
|
|
1221
|
+
z-index: 0;
|
|
1222
|
+
pointer-events: none;
|
|
1223
|
+
overflow: hidden;
|
|
1224
|
+
}
|
|
1225
|
+
/* \u5355\u5757\u6C34\u5370\u74E6\u7247\uFF1A\u4F4D\u7F6E/\u5C3A\u5BF8\u7531 core \u7684\u74E6\u7247\u7F51\u683C\u7ED9\u51FA\uFF08mm\uFF09 */
|
|
1226
|
+
.watermark-tile {
|
|
1227
|
+
position: absolute;
|
|
1228
|
+
pointer-events: none;
|
|
1229
|
+
}
|
|
1230
|
+
`;
|
|
1231
|
+
}
|
|
1232
|
+
function elementBlock() {
|
|
1233
|
+
return `
|
|
1234
|
+
/* \u2500\u2500 \u5143\u7D20\u901A\u7528\u5B9A\u4F4D \u2500\u2500 */
|
|
1235
|
+
.print-element {
|
|
1236
|
+
position: absolute;
|
|
1237
|
+
overflow: hidden;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/* \u2500\u2500 \u8868\u683C\u6837\u5F0F \u2500\u2500 */
|
|
1241
|
+
.print-table {
|
|
1242
|
+
width: 100%;
|
|
1243
|
+
border-collapse: collapse;
|
|
1244
|
+
table-layout: fixed;
|
|
1245
|
+
}
|
|
1246
|
+
.print-table th,
|
|
1247
|
+
.print-table td {
|
|
1248
|
+
border: 1px solid #ccc;
|
|
1249
|
+
padding: 2mm 3mm;
|
|
1250
|
+
word-break: break-all;
|
|
1251
|
+
overflow: hidden;
|
|
1252
|
+
}
|
|
1253
|
+
.print-table thead th {
|
|
1254
|
+
background-color: #f5f5f5;
|
|
1255
|
+
font-weight: bold;
|
|
1256
|
+
}
|
|
1018
1257
|
|
|
1258
|
+
/* \u2500\u2500 \u6D4B\u91CF\u6A21\u5F0F \u2500\u2500 */
|
|
1259
|
+
.measure-mode .print-page {
|
|
1260
|
+
height: auto;
|
|
1261
|
+
min-height: auto;
|
|
1262
|
+
overflow: visible;
|
|
1263
|
+
}
|
|
1264
|
+
.measure-mode .content-area {
|
|
1265
|
+
height: auto;
|
|
1266
|
+
overflow: visible;
|
|
1267
|
+
}
|
|
1268
|
+
`;
|
|
1269
|
+
}
|
|
1270
|
+
function pageRuleBlock(paper) {
|
|
1271
|
+
return `
|
|
1272
|
+
/* \u2500\u2500 \u6253\u5370\u7EB8\u5F20\uFF1A\u6D4F\u89C8\u5668\u539F\u751F\u6253\u5370\u6309\u6B64\u5C3A\u5BF8\u5206\u9875\uFF08Playwright page.pdf \u4EE5\u663E\u5F0F\u5BBD\u9AD8\u4E3A\u51C6\uFF0C\u65E0\u526F\u4F5C\u7528\uFF09 \u2500\u2500 */
|
|
1273
|
+
@page { size: ${mm(paper.width)} ${mm(paper.height)}; margin: 0; }
|
|
1274
|
+
`;
|
|
1275
|
+
}
|
|
1276
|
+
function buildRotorCss(area, margins, angle) {
|
|
1277
|
+
const base = `
|
|
1278
|
+
/* \u2500\u2500 \u51FA\u7EB8\u8F6C\u5B50\uFF1A\u8BBE\u8BA1\u7A3F\u6574\u9875\u65CB\u8F6C ${angle}\xB0 \u586B\u5165\u51FA\u7EB8\u7EB8\u5F20 \u2500\u2500 */
|
|
1279
|
+
.print-page-rotor {
|
|
1280
|
+
position: absolute;
|
|
1281
|
+
top: 0;
|
|
1282
|
+
left: 0;
|
|
1283
|
+
width: ${mm(area.width)};
|
|
1284
|
+
height: ${mm(area.height)};
|
|
1285
|
+
padding: ${mm(margins.top)} ${mm(margins.right)} ${mm(margins.bottom)} ${mm(margins.left)};
|
|
1286
|
+
box-sizing: border-box;
|
|
1287
|
+
transform-origin: 0 0;
|
|
1288
|
+
}`;
|
|
1289
|
+
if (angle === 0) return base.trim();
|
|
1290
|
+
const transforms = {
|
|
1291
|
+
90: `translate(${mm(area.height)}, 0mm) rotate(90deg)`,
|
|
1292
|
+
180: `translate(${mm(area.width)}, ${mm(area.height)}) rotate(180deg)`,
|
|
1293
|
+
270: `translate(0mm, ${mm(area.width)}) rotate(270deg)`
|
|
1294
|
+
};
|
|
1295
|
+
const tf = transforms[angle];
|
|
1296
|
+
return [
|
|
1297
|
+
base.trim(),
|
|
1298
|
+
`.print-page-rotor-${angle} {
|
|
1299
|
+
transform: ${tf};
|
|
1300
|
+
}`
|
|
1301
|
+
].join("\n");
|
|
1302
|
+
}
|
|
1303
|
+
function pageGeometryBlock(template, outerPaper, pageSel, rotated) {
|
|
1304
|
+
const { top: mt, right: mr, bottom: mb, left: ml } = template.margins;
|
|
1305
|
+
const padding = rotated ? "0" : `${mm(mt)} ${mm(mr)} ${mm(mb)} ${mm(ml)}`;
|
|
1306
|
+
return `
|
|
1019
1307
|
/* \u2500\u2500 \u7EB8\u5F20\u9875\u9762 \u2500\u2500 */
|
|
1020
|
-
|
|
1021
|
-
width: ${mm(
|
|
1022
|
-
min-height: ${mm(
|
|
1308
|
+
${pageSel} {
|
|
1309
|
+
width: ${mm(outerPaper.width)};
|
|
1310
|
+
min-height: ${mm(outerPaper.height)};
|
|
1023
1311
|
background: ${template.pageBackground ?? "#fff"};
|
|
1024
|
-
padding: ${
|
|
1312
|
+
padding: ${padding};
|
|
1025
1313
|
position: relative;
|
|
1026
1314
|
page-break-after: always;
|
|
1027
1315
|
overflow: hidden;
|
|
@@ -1029,9 +1317,18 @@ body { font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, s
|
|
|
1029
1317
|
.print-page:last-child {
|
|
1030
1318
|
page-break-after: auto;
|
|
1031
1319
|
}
|
|
1032
|
-
|
|
1320
|
+
`;
|
|
1321
|
+
}
|
|
1322
|
+
function areaGeometryBlock(template, paper, desc) {
|
|
1323
|
+
const { right: mr, left: ml } = template.margins;
|
|
1324
|
+
const { bottom: mb } = template.margins;
|
|
1325
|
+
const headerH = template.header?.height ?? 0;
|
|
1326
|
+
const footerH = template.footer?.height ?? 0;
|
|
1327
|
+
const overlayH = template.firstPageOverlay?.height ?? 0;
|
|
1328
|
+
const contentWidth = paper.width - ml - mr;
|
|
1329
|
+
return `
|
|
1033
1330
|
/* \u2500\u2500 \u9875\u7709 \u2500\u2500 */
|
|
1034
|
-
.page-header {
|
|
1331
|
+
${desc}.page-header {
|
|
1035
1332
|
width: ${mm(contentWidth)};
|
|
1036
1333
|
height: ${mm(headerH)};
|
|
1037
1334
|
position: relative;
|
|
@@ -1040,7 +1337,7 @@ body { font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, s
|
|
|
1040
1337
|
/* \u2500\u2500 \u9875\u811A\uFF1A\u7EDD\u5BF9\u5B9A\u4F4D\u56FA\u5B9A\u5728\u9875\u9762\u5E95\u90E8\uFF08\u5185\u5BB9\u4E0D\u8DB3\u65F6\u4E0D\u968F\u6587\u6863\u6D41\u4E0A\u6D6E\uFF09 \u2500\u2500
|
|
1041
1338
|
\u7528\u663E\u5F0F top \u5B9A\u4F4D\u5230\u300C\u7EB8\u9AD8 - \u4E0B\u8FB9\u8DDD - \u9875\u811A\u9AD8\u300D\uFF0C\u4FDD\u8BC1\u4E0B\u8FB9\u8DDD\u751F\u6548\u3001
|
|
1042
1339
|
\u4E0E\u8BBE\u8BA1\u5668 CanvasPaper \u7684\u4E09\u533A\u51E0\u4F55\u4E00\u81F4\u3002 */
|
|
1043
|
-
.page-footer {
|
|
1340
|
+
${desc}.page-footer {
|
|
1044
1341
|
width: ${mm(contentWidth)};
|
|
1045
1342
|
height: ${mm(footerH)};
|
|
1046
1343
|
position: absolute;
|
|
@@ -1049,54 +1346,115 @@ body { font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, s
|
|
|
1049
1346
|
}
|
|
1050
1347
|
|
|
1051
1348
|
/* \u2500\u2500 \u5185\u5BB9\u533A \u2500\u2500 */
|
|
1052
|
-
.content-area {
|
|
1349
|
+
${desc}.content-area {
|
|
1053
1350
|
width: ${mm(contentWidth)};
|
|
1054
1351
|
position: relative;
|
|
1055
1352
|
overflow: visible;
|
|
1056
1353
|
}
|
|
1057
1354
|
|
|
1058
1355
|
/* \u2500\u2500 \u9996\u9875\u53E0\u52A0\u533A\u57DF \u2500\u2500 */
|
|
1059
|
-
.first-page-overlay {
|
|
1356
|
+
${desc}.first-page-overlay {
|
|
1060
1357
|
width: ${mm(contentWidth)};
|
|
1061
1358
|
height: ${mm(overlayH)};
|
|
1062
1359
|
position: relative;
|
|
1063
1360
|
}
|
|
1361
|
+
`;
|
|
1362
|
+
}
|
|
1363
|
+
function buildBasePageCss() {
|
|
1364
|
+
return [screenBlock(), watermarkBlock(), elementBlock()].join("").trim();
|
|
1365
|
+
}
|
|
1366
|
+
function buildPageRuleCss(template, pageHeightMm) {
|
|
1367
|
+
return pageRuleBlock(resolveOuterPaper(template, pageHeightMm)).trim();
|
|
1368
|
+
}
|
|
1369
|
+
function buildPageGeometryCss(template, scope, pageHeightMm) {
|
|
1370
|
+
const angle = getOutputRotationAngle(template);
|
|
1371
|
+
const rotated = angle !== 0;
|
|
1372
|
+
const outer = resolveOuterPaper(template, pageHeightMm);
|
|
1373
|
+
const area = resolveAreaPaper(template, pageHeightMm);
|
|
1374
|
+
const pageSel = scope ? `${scope}.print-page` : ".print-page";
|
|
1375
|
+
const desc = scope ? `${scope} ` : "";
|
|
1376
|
+
return [
|
|
1377
|
+
pageGeometryBlock(template, outer, pageSel, rotated),
|
|
1378
|
+
areaGeometryBlock(template, area, desc),
|
|
1379
|
+
...rotated ? [buildRotorCss(area, template.margins, angle)] : []
|
|
1380
|
+
].join("").trim();
|
|
1381
|
+
}
|
|
1382
|
+
function buildPageCss(template, pageHeightMm) {
|
|
1383
|
+
const angle = getOutputRotationAngle(template);
|
|
1384
|
+
const rotated = angle !== 0;
|
|
1385
|
+
const outer = resolveOuterPaper(template, pageHeightMm);
|
|
1386
|
+
const area = resolveAreaPaper(template, pageHeightMm);
|
|
1387
|
+
return [
|
|
1388
|
+
pageRuleBlock(outer),
|
|
1389
|
+
screenBlock(),
|
|
1390
|
+
pageGeometryBlock(template, outer, ".print-page", rotated),
|
|
1391
|
+
watermarkBlock(),
|
|
1392
|
+
areaGeometryBlock(template, area, ""),
|
|
1393
|
+
elementBlock(),
|
|
1394
|
+
...rotated ? [buildRotorCss(area, template.margins, angle)] : []
|
|
1395
|
+
].join("").trim();
|
|
1396
|
+
}
|
|
1397
|
+
var COPY_BREAK_CSS = ".print-copy:not(:last-child){break-after:page;page-break-after:always;}";
|
|
1398
|
+
function buildBatchPageCss(template, copies) {
|
|
1399
|
+
if (!isContinuousPaper(template)) {
|
|
1400
|
+
return `${buildPageCss(template)}
|
|
1401
|
+
${COPY_BREAK_CSS}`;
|
|
1402
|
+
}
|
|
1403
|
+
const { bottom: mb } = template.margins;
|
|
1404
|
+
const footerH = template.footer?.height ?? 0;
|
|
1405
|
+
const width = getPaperDimensions(template).width;
|
|
1406
|
+
const base = buildPageCss(template, copies[0]?.heightMm);
|
|
1407
|
+
const scoped = copies.map((copy, i) => {
|
|
1408
|
+
const h = copy.heightMm;
|
|
1409
|
+
const rules = [
|
|
1410
|
+
`@page copy${i} { size: ${mm(width)} ${h ? mm(h) : "auto"}; margin: 0; }`,
|
|
1411
|
+
`.print-copy-${i} { page: copy${i}; }`
|
|
1412
|
+
];
|
|
1413
|
+
if (h) {
|
|
1414
|
+
rules.push(`.print-copy-${i} .print-page { min-height: ${mm(h)}; }`);
|
|
1415
|
+
rules.push(`.print-copy-${i} .page-footer { top: ${mm(h - mb - footerH)}; }`);
|
|
1416
|
+
}
|
|
1417
|
+
return rules.join("\n");
|
|
1418
|
+
}).join("\n");
|
|
1419
|
+
return `${base}
|
|
1420
|
+
${scoped}
|
|
1421
|
+
${COPY_BREAK_CSS}`;
|
|
1422
|
+
}
|
|
1423
|
+
function buildSheetPageCss(layout) {
|
|
1424
|
+
return `
|
|
1425
|
+
/* \u2500\u2500 \u62FC\u7248\u7EB8\u5F20\uFF1A@page \u5C3A\u5BF8 = \u76EE\u6807\u7EB8\u3002\u670D\u52A1\u7AEF/\u5BA2\u6237\u7AEF\u94FE\u8DEF\u4EE5 paperMm \u663E\u5F0F\u5B9A\u5C3A\u5BF8\u3001\u4E0D\u770B\u8FD9\u91CC\uFF0C
|
|
1426
|
+
\u4F46\u6D4F\u89C8\u5668\u94FE\u8DEF\u53EA\u770B @page\uFF0C\u6545\u8FD9\u6761\u662F\u786C\u9700\u6C42 \u2500\u2500 */
|
|
1427
|
+
@page { size: ${mm(layout.sheet.width)} ${mm(layout.sheet.height)}; margin: 0; }
|
|
1064
1428
|
|
|
1065
|
-
/* \u2500\u2500 \
|
|
1066
|
-
.print-
|
|
1067
|
-
|
|
1429
|
+
/* \u2500\u2500 \u4E00\u5F20\u76EE\u6807\u7EB8 \u2500\u2500 */
|
|
1430
|
+
.print-sheet {
|
|
1431
|
+
width: ${mm(layout.sheet.width)};
|
|
1432
|
+
height: ${mm(layout.sheet.height)};
|
|
1433
|
+
position: relative;
|
|
1068
1434
|
overflow: hidden;
|
|
1435
|
+
break-after: page;
|
|
1436
|
+
page-break-after: always;
|
|
1069
1437
|
}
|
|
1438
|
+
.print-sheet:last-child { break-after: auto; page-break-after: auto; }
|
|
1070
1439
|
|
|
1071
|
-
/* \u2500\u2500 \
|
|
1072
|
-
.print-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
}
|
|
1077
|
-
.print-table th,
|
|
1078
|
-
.print-table td {
|
|
1079
|
-
border: 1px solid #ccc;
|
|
1080
|
-
padding: 2mm 3mm;
|
|
1081
|
-
word-break: break-all;
|
|
1440
|
+
/* \u2500\u2500 \u4E00\u683C\uFF1A\u7EDD\u5BF9\u5B9A\u4F4D\uFF0C\u4F4D\u7F6E\u7531 tilePosition() \u4EE5\u884C\u5185 style \u7ED9\u51FA \u2500\u2500 */
|
|
1441
|
+
.print-tile {
|
|
1442
|
+
position: absolute;
|
|
1443
|
+
width: ${mm(layout.tile.width)};
|
|
1444
|
+
height: ${mm(layout.tile.height)};
|
|
1082
1445
|
overflow: hidden;
|
|
1083
1446
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
}
|
|
1447
|
+
/* \u9632\u5FA1\u6027\u58F0\u660E\uFF1A\u7EDD\u5BF9\u5B9A\u4F4D + overflow:hidden \u5BB9\u5668\u5185\u7684\u540E\u4EE3\u4E0D\u4EA7\u751F\u5206\u9875\u70B9\uFF0C\u5F53\u524D\u5E03\u5C40\u4E0B\u65E0\u5B9E\u9645\u4F5C\u7528\uFF1B
|
|
1448
|
+
\u82E5\u5C06\u6765\u6539\u7528 flex/grid \u5E03\u5C40\uFF0C\u683C\u5185\u6574\u9875\u4F1A\u91CD\u65B0\u53C2\u4E0E\u5206\u9875\uFF0C\u6545\u4FDD\u7559 */
|
|
1449
|
+
.print-tile > .print-page { break-after: auto; page-break-after: auto; }
|
|
1088
1450
|
|
|
1089
|
-
|
|
1090
|
-
.
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
1095
|
-
.measure-mode .content-area {
|
|
1096
|
-
height: auto;
|
|
1097
|
-
overflow: visible;
|
|
1451
|
+
@media screen {
|
|
1452
|
+
.print-sheet { margin: 12px auto; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.18); }
|
|
1453
|
+
/* \u5FC5\u9700\uFF1A\u62B5\u6D88\u6807\u7B7E CSS \u7684 @media screen{.print-page{margin:12px auto}}\uFF0C
|
|
1454
|
+
\u5426\u5219\u8BBE\u8BA1\u5668\u9884\u89C8\u9519\u4F4D 3.17mm\u3001\u4E0E\u51FA\u7EB8\u4E0D\u4E00\u81F4 */
|
|
1455
|
+
.print-tile > .print-page { margin: 0; box-shadow: none; }
|
|
1098
1456
|
}
|
|
1099
|
-
|
|
1457
|
+
`;
|
|
1100
1458
|
}
|
|
1101
1459
|
function elementPositionStyle(left, top, width, height, zIndex) {
|
|
1102
1460
|
const parts = [
|
|
@@ -1114,6 +1472,223 @@ function elementPositionStyle(left, top, width, height, zIndex) {
|
|
|
1114
1472
|
return parts.join(";") + ";";
|
|
1115
1473
|
}
|
|
1116
1474
|
|
|
1475
|
+
// src/designer/utils/units.ts
|
|
1476
|
+
function ptToMm(pt) {
|
|
1477
|
+
return pt / 2.83464566929;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// src/render/text-fit.ts
|
|
1481
|
+
var DEFAULT_SHRINK_MIN_FONT_SIZE_PT = 6;
|
|
1482
|
+
var MIN_SHRINK_FONT_SIZE_PT = 1;
|
|
1483
|
+
var VALID_FITS = ["clip", "shrink", "autoHeight"];
|
|
1484
|
+
function normalizeFit(value) {
|
|
1485
|
+
return typeof value === "string" && VALID_FITS.includes(value) ? value : void 0;
|
|
1486
|
+
}
|
|
1487
|
+
var ELEMENT_DEFAULT_FIT = {
|
|
1488
|
+
text: "clip",
|
|
1489
|
+
longText: "autoHeight"
|
|
1490
|
+
};
|
|
1491
|
+
function resolveElementTextFit(type, opts) {
|
|
1492
|
+
return normalizeFit(opts?.textFit) ?? ELEMENT_DEFAULT_FIT[type] ?? "clip";
|
|
1493
|
+
}
|
|
1494
|
+
function resolveCellTextFit(cell) {
|
|
1495
|
+
return normalizeFit(cell?.textFit) ?? (cell?.wordWrap === false ? "clip" : "autoHeight");
|
|
1496
|
+
}
|
|
1497
|
+
function resolveShrinkMinFontSize(pt) {
|
|
1498
|
+
if (typeof pt !== "number" || !Number.isFinite(pt) || pt <= 0) return DEFAULT_SHRINK_MIN_FONT_SIZE_PT;
|
|
1499
|
+
return Math.max(pt, MIN_SHRINK_FONT_SIZE_PT);
|
|
1500
|
+
}
|
|
1501
|
+
function roundFontSize(pt) {
|
|
1502
|
+
return Math.round(pt * 100) / 100;
|
|
1503
|
+
}
|
|
1504
|
+
function floorFontSize(pt) {
|
|
1505
|
+
return Math.floor(pt * 100) / 100;
|
|
1506
|
+
}
|
|
1507
|
+
function cellFitKey(elementId, kind, rowIndex, colIndex) {
|
|
1508
|
+
return `${elementId}#${kind}#${rowIndex}:${colIndex}`;
|
|
1509
|
+
}
|
|
1510
|
+
function parseCellFitKey(key) {
|
|
1511
|
+
const first = key.indexOf("#");
|
|
1512
|
+
if (first < 0) return void 0;
|
|
1513
|
+
const last = key.lastIndexOf("#");
|
|
1514
|
+
const kind = key.slice(first + 1, last);
|
|
1515
|
+
if (kind !== "b" && kind !== "st" && kind !== "sm") return void 0;
|
|
1516
|
+
const [rowIndex, colIndex] = key.slice(last + 1).split(":").map(Number);
|
|
1517
|
+
if (!Number.isFinite(rowIndex) || !Number.isFinite(colIndex)) return void 0;
|
|
1518
|
+
return { elementId: key.slice(0, first), kind, rowIndex, colIndex };
|
|
1519
|
+
}
|
|
1520
|
+
function cellFitWidthMm(colWidths, colIndex, cell, defaultPadding = 1) {
|
|
1521
|
+
const span = Math.max(cell?.colspan ?? 1, 1);
|
|
1522
|
+
let width = 0;
|
|
1523
|
+
for (let i = 0; i < span; i++) {
|
|
1524
|
+
width += colWidths[colIndex + i] ?? 0;
|
|
1525
|
+
}
|
|
1526
|
+
if (width <= 0) return 0;
|
|
1527
|
+
const padding = cell?.padding ?? defaultPadding;
|
|
1528
|
+
const borderMm = (ptToMm(cell?.borders?.left?.width ?? 0) + ptToMm(cell?.borders?.right?.width ?? 0)) / 2;
|
|
1529
|
+
return Math.max(width - padding * 2 - borderMm, 0.5);
|
|
1530
|
+
}
|
|
1531
|
+
function cellFitCapMm(rows, rowIndex, cell, defaultPadding = 1) {
|
|
1532
|
+
const span = Math.max(cell?.rowspan ?? 1, 1);
|
|
1533
|
+
let height = 0;
|
|
1534
|
+
for (let i = 0; i < span; i++) {
|
|
1535
|
+
height += rows[rowIndex + i]?.height ?? 8;
|
|
1536
|
+
}
|
|
1537
|
+
const padding = cell?.padding ?? defaultPadding;
|
|
1538
|
+
const borderMm = (ptToMm(cell?.borders?.top?.width ?? 0) + ptToMm(cell?.borders?.bottom?.width ?? 0)) / 2;
|
|
1539
|
+
return Math.max(height - padding * 2 - borderMm, 0.5);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// src/render/watermark.ts
|
|
1543
|
+
var PX_PER_MM = 96 / 25.4;
|
|
1544
|
+
var MM_PER_PX = 25.4 / 96;
|
|
1545
|
+
var WATERMARK_DEFAULTS = {
|
|
1546
|
+
color: "#cccccc",
|
|
1547
|
+
opacity: 0.15,
|
|
1548
|
+
rotate: -30,
|
|
1549
|
+
/** 瓦片默认尺寸(px):决定平铺疏密,默认 260×180 */
|
|
1550
|
+
tileWidth: 260,
|
|
1551
|
+
tileHeight: 180,
|
|
1552
|
+
/** 瓦片下限(px),防止文字裁剪/异常平铺 */
|
|
1553
|
+
minTileWidth: 140,
|
|
1554
|
+
minTileHeight: 100,
|
|
1555
|
+
/** 瓦片字号固定 16px:密度只改变平铺疏密,不改字体大小 */
|
|
1556
|
+
fontSize: 16
|
|
1557
|
+
};
|
|
1558
|
+
var WATERMARK_DENSITY_PRESETS = {
|
|
1559
|
+
dense: { width: 200, height: 120, label: "\u5BC6" },
|
|
1560
|
+
medium: { width: 260, height: 180, label: "\u4E2D\uFF08\u9ED8\u8BA4\uFF09" },
|
|
1561
|
+
loose: { width: 340, height: 260, label: "\u758F" }
|
|
1562
|
+
};
|
|
1563
|
+
function clampTile(value, fallback, min2) {
|
|
1564
|
+
const n = typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1565
|
+
return Math.max(min2, Math.round(n));
|
|
1566
|
+
}
|
|
1567
|
+
function resolveTileSize(wm) {
|
|
1568
|
+
return {
|
|
1569
|
+
width: clampTile(wm?.tileWidth, WATERMARK_DEFAULTS.tileWidth, WATERMARK_DEFAULTS.minTileWidth),
|
|
1570
|
+
height: clampTile(wm?.tileHeight, WATERMARK_DEFAULTS.tileHeight, WATERMARK_DEFAULTS.minTileHeight)
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
function isWatermarkVisible(wm) {
|
|
1574
|
+
if (!wm) return false;
|
|
1575
|
+
if (!wm.mode || wm.mode === "fixed") {
|
|
1576
|
+
return !!wm.content && wm.content.trim().length > 0;
|
|
1577
|
+
}
|
|
1578
|
+
return !!wm.binding && wm.binding.trim().length > 0;
|
|
1579
|
+
}
|
|
1580
|
+
function resolveWatermarkText(wm, printData, systemVars2) {
|
|
1581
|
+
if (!wm) return "";
|
|
1582
|
+
let text = "";
|
|
1583
|
+
if (!wm.mode || wm.mode === "fixed") {
|
|
1584
|
+
text = wm.content ?? "";
|
|
1585
|
+
} else if (typeof wm.binding === "string" && wm.binding.trim()) {
|
|
1586
|
+
const binding = wm.binding.trim();
|
|
1587
|
+
const data = Array.isArray(printData) ? printData[0] ?? {} : printData ?? {};
|
|
1588
|
+
const ctx = { ...resolveSystemVariables(), ...systemVars2, ...data };
|
|
1589
|
+
let resolved;
|
|
1590
|
+
if (binding.includes("{")) {
|
|
1591
|
+
resolved = evaluateTemplate(binding, ctx);
|
|
1592
|
+
} else {
|
|
1593
|
+
try {
|
|
1594
|
+
resolved = safeEval(binding, ctx);
|
|
1595
|
+
} catch {
|
|
1596
|
+
resolved = void 0;
|
|
1597
|
+
}
|
|
1598
|
+
if (resolved == null || typeof resolved === "object") {
|
|
1599
|
+
resolved = getByPath(data, binding);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
if (resolved != null && typeof resolved !== "object" && String(resolved) !== binding) {
|
|
1603
|
+
text = String(resolved);
|
|
1604
|
+
} else {
|
|
1605
|
+
text = wm.testData ?? `[${wm.binding}]`;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
if (wm.timestamp && text) {
|
|
1609
|
+
text = `${text} ${formatTimestamp(wm.format)}`;
|
|
1610
|
+
}
|
|
1611
|
+
return text;
|
|
1612
|
+
}
|
|
1613
|
+
function pad(n) {
|
|
1614
|
+
return String(n).padStart(2, "0");
|
|
1615
|
+
}
|
|
1616
|
+
function formatTimestamp(format) {
|
|
1617
|
+
const fmt = format && format.trim() ? format : "YYYY-MM-DD HH:mm";
|
|
1618
|
+
const d = /* @__PURE__ */ new Date();
|
|
1619
|
+
const map = {
|
|
1620
|
+
YYYY: String(d.getFullYear()),
|
|
1621
|
+
MM: pad(d.getMonth() + 1),
|
|
1622
|
+
DD: pad(d.getDate()),
|
|
1623
|
+
HH: pad(d.getHours()),
|
|
1624
|
+
mm: pad(d.getMinutes()),
|
|
1625
|
+
ss: pad(d.getSeconds())
|
|
1626
|
+
};
|
|
1627
|
+
return fmt.replace(/YYYY|MM|DD|HH|mm|ss/g, (k) => map[k] ?? k);
|
|
1628
|
+
}
|
|
1629
|
+
function round4(n) {
|
|
1630
|
+
return Math.round(n * 1e4) / 1e4;
|
|
1631
|
+
}
|
|
1632
|
+
function escXml(text) {
|
|
1633
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1634
|
+
}
|
|
1635
|
+
function resolveWatermarkLayout(wm, printData, paperMm, systemVars2) {
|
|
1636
|
+
if (!isWatermarkVisible(wm)) return null;
|
|
1637
|
+
const text = resolveWatermarkText(wm, printData, systemVars2);
|
|
1638
|
+
if (!text) return null;
|
|
1639
|
+
const tile = resolveTileSize(wm);
|
|
1640
|
+
const tileWidthMm = round4(tile.width * MM_PER_PX);
|
|
1641
|
+
const tileHeightMm = round4(tile.height * MM_PER_PX);
|
|
1642
|
+
const paper = {
|
|
1643
|
+
width: Math.max(0, Number.isFinite(paperMm?.width) ? paperMm.width : 0),
|
|
1644
|
+
height: Math.max(0, Number.isFinite(paperMm?.height) ? paperMm.height : 0)
|
|
1645
|
+
};
|
|
1646
|
+
const columns = Math.max(1, Math.ceil(paper.width / tileWidthMm));
|
|
1647
|
+
const rows = Math.max(1, Math.ceil(paper.height / tileHeightMm));
|
|
1648
|
+
const tiles = [];
|
|
1649
|
+
for (let r = 0; r < rows; r++) {
|
|
1650
|
+
for (let c = 0; c < columns; c++) {
|
|
1651
|
+
tiles.push({
|
|
1652
|
+
leftMm: round4(c * tileWidthMm),
|
|
1653
|
+
topMm: round4(r * tileHeightMm),
|
|
1654
|
+
widthMm: tileWidthMm,
|
|
1655
|
+
heightMm: tileHeightMm
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return {
|
|
1660
|
+
text,
|
|
1661
|
+
color: wm?.color || WATERMARK_DEFAULTS.color,
|
|
1662
|
+
rotate: wm?.rotate ?? WATERMARK_DEFAULTS.rotate,
|
|
1663
|
+
opacity: wm?.opacity ?? WATERMARK_DEFAULTS.opacity,
|
|
1664
|
+
fontSizePx: WATERMARK_DEFAULTS.fontSize,
|
|
1665
|
+
tileWidthPx: tile.width,
|
|
1666
|
+
tileHeightPx: tile.height,
|
|
1667
|
+
tileWidthMm,
|
|
1668
|
+
tileHeightMm,
|
|
1669
|
+
columns,
|
|
1670
|
+
rows,
|
|
1671
|
+
tiles
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
function renderWatermarkTileSvg(layout, tile) {
|
|
1675
|
+
const tileWidthPx = layout.tileWidthPx;
|
|
1676
|
+
const tileHeightPx = layout.tileHeightPx;
|
|
1677
|
+
const cx = tileWidthPx / 2;
|
|
1678
|
+
const cy = tileHeightPx / 2;
|
|
1679
|
+
const style = `left:${tile.leftMm}mm;top:${tile.topMm}mm;width:${tile.widthMm}mm;height:${tile.heightMm}mm`;
|
|
1680
|
+
return `<svg class="watermark-tile" style="${style}" viewBox="0 0 ${tileWidthPx} ${tileHeightPx}" xmlns="http://www.w3.org/2000/svg"><text x="${cx}" y="${cy}" font-size="${layout.fontSizePx}" fill="${layout.color}" text-anchor="middle" dominant-baseline="middle" transform="rotate(${layout.rotate},${cx},${cy})">${escXml(layout.text)}</text></svg>`;
|
|
1681
|
+
}
|
|
1682
|
+
function renderWatermarkLayerHtml(wm, printData, paperMm, systemVars2) {
|
|
1683
|
+
const layout = resolveWatermarkLayout(wm, printData, paperMm, systemVars2);
|
|
1684
|
+
if (!layout) return "";
|
|
1685
|
+
const tiles = layout.tiles.map((t) => renderWatermarkTileSvg(layout, t)).join("\n");
|
|
1686
|
+
return `
|
|
1687
|
+
<div class="watermark-layer" style="opacity:${layout.opacity}">
|
|
1688
|
+
${tiles}
|
|
1689
|
+
</div>`;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1117
1692
|
// src/render/pagination-engine.ts
|
|
1118
1693
|
function paginationOf(el) {
|
|
1119
1694
|
return el.options?.pagination ?? el.pagination;
|
|
@@ -1134,7 +1709,7 @@ function tableDesignBottom(el) {
|
|
|
1134
1709
|
}
|
|
1135
1710
|
return top + (opts.height ?? 0);
|
|
1136
1711
|
}
|
|
1137
|
-
function buildFollowMap(sorted) {
|
|
1712
|
+
function buildFollowMap(sorted, excludedIds) {
|
|
1138
1713
|
const map = /* @__PURE__ */ new Map();
|
|
1139
1714
|
let currentTableId = null;
|
|
1140
1715
|
let currentTableBottom = -1;
|
|
@@ -1145,6 +1720,7 @@ function buildFollowMap(sorted) {
|
|
|
1145
1720
|
map.set(el.id, []);
|
|
1146
1721
|
continue;
|
|
1147
1722
|
}
|
|
1723
|
+
if (excludedIds?.has(el.id)) continue;
|
|
1148
1724
|
const top = el.options?.top ?? 0;
|
|
1149
1725
|
if (currentTableId && top >= currentTableBottom) {
|
|
1150
1726
|
map.get(currentTableId).push(el.id);
|
|
@@ -1162,28 +1738,110 @@ function followGroupHeight(el, members, template, _measuredElements) {
|
|
|
1162
1738
|
}
|
|
1163
1739
|
return Math.max(maxBottom - tableBottom, 0);
|
|
1164
1740
|
}
|
|
1741
|
+
function effectiveHeight(el, measured) {
|
|
1742
|
+
return Math.max(el.options?.height ?? 0, measured.get(el.id)?.measuredHeight ?? 0);
|
|
1743
|
+
}
|
|
1744
|
+
function buildPaginationUnits(sorted, measured, groupMap) {
|
|
1745
|
+
const unitOf = /* @__PURE__ */ new Map();
|
|
1746
|
+
for (const members of groupMap.values()) {
|
|
1747
|
+
if (members.length < 2) continue;
|
|
1748
|
+
const unit = {
|
|
1749
|
+
anchorId: members[0].id,
|
|
1750
|
+
ids: members.map((m) => m.id),
|
|
1751
|
+
forceFirstPage: members.some((m) => paginationOf(m)?.pageable === false)
|
|
1752
|
+
};
|
|
1753
|
+
for (const m of members) unitOf.set(m.id, unit);
|
|
1754
|
+
}
|
|
1755
|
+
const eligible = sorted.filter(
|
|
1756
|
+
(el) => !isTableEl(el) && !el.options?.groupId && paginationOf(el)?.pageable !== false
|
|
1757
|
+
);
|
|
1758
|
+
const parent = /* @__PURE__ */ new Map();
|
|
1759
|
+
eligible.forEach((el) => parent.set(el.id, el.id));
|
|
1760
|
+
const find = (id) => {
|
|
1761
|
+
let root = id;
|
|
1762
|
+
while (parent.get(root) !== root) root = parent.get(root);
|
|
1763
|
+
let cur = id;
|
|
1764
|
+
while (parent.get(cur) !== root) {
|
|
1765
|
+
const next = parent.get(cur);
|
|
1766
|
+
parent.set(cur, root);
|
|
1767
|
+
cur = next;
|
|
1768
|
+
}
|
|
1769
|
+
return root;
|
|
1770
|
+
};
|
|
1771
|
+
const union = (a, b) => {
|
|
1772
|
+
const ra = find(a);
|
|
1773
|
+
const rb = find(b);
|
|
1774
|
+
if (ra !== rb) parent.set(rb, ra);
|
|
1775
|
+
};
|
|
1776
|
+
const active = [];
|
|
1777
|
+
for (const el of eligible) {
|
|
1778
|
+
const top = el.options?.top ?? 0;
|
|
1779
|
+
for (let i = active.length - 1; i >= 0; i--) {
|
|
1780
|
+
if (active[i].bottom <= top) active.splice(i, 1);
|
|
1781
|
+
}
|
|
1782
|
+
const bottom = top + effectiveHeight(el, measured);
|
|
1783
|
+
for (const a of active) {
|
|
1784
|
+
if (a.bottom > top) union(el.id, a.id);
|
|
1785
|
+
}
|
|
1786
|
+
active.push({ id: el.id, top, bottom });
|
|
1787
|
+
}
|
|
1788
|
+
const clusters = /* @__PURE__ */ new Map();
|
|
1789
|
+
for (const el of eligible) {
|
|
1790
|
+
const root = find(el.id);
|
|
1791
|
+
const arr = clusters.get(root);
|
|
1792
|
+
if (arr) arr.push(el.id);
|
|
1793
|
+
else clusters.set(root, [el.id]);
|
|
1794
|
+
}
|
|
1795
|
+
for (const ids of clusters.values()) {
|
|
1796
|
+
if (ids.length < 2) continue;
|
|
1797
|
+
const unit = { anchorId: ids[0], ids, forceFirstPage: false };
|
|
1798
|
+
for (const id of ids) unitOf.set(id, unit);
|
|
1799
|
+
}
|
|
1800
|
+
return unitOf;
|
|
1801
|
+
}
|
|
1165
1802
|
function paginate(template, measuredElements) {
|
|
1166
1803
|
const paper = getPaperDimensions(template);
|
|
1167
1804
|
const { top: mt, bottom: mb } = template.margins;
|
|
1168
1805
|
const headerH = template.header?.height ?? 0;
|
|
1169
1806
|
const footerH = template.footer?.height ?? 0;
|
|
1170
1807
|
const overlayH = template.firstPageOverlay?.height ?? 0;
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1808
|
+
const continuous = isContinuousPaper(template);
|
|
1809
|
+
const contentHeight = continuous ? Number.POSITIVE_INFINITY : paper.height - mt - mb - headerH - footerH;
|
|
1810
|
+
if (!continuous && contentHeight <= 0) {
|
|
1173
1811
|
throw new Error(
|
|
1174
1812
|
`\u9875\u9762\u53EF\u7528\u9AD8\u5EA6\u4E0D\u8DB3: paper=${paper.height}mm, margins=${mt + mb}mm, header=${headerH}mm, footer=${footerH}mm`
|
|
1175
1813
|
);
|
|
1176
1814
|
}
|
|
1815
|
+
const orderIndex = /* @__PURE__ */ new Map();
|
|
1816
|
+
template.elements.forEach((e, idx) => orderIndex.set(e.id, idx));
|
|
1177
1817
|
const sorted = [...template.elements].sort((a, b) => {
|
|
1178
1818
|
const topA = a.options?.top ?? 0;
|
|
1179
1819
|
const topB = b.options?.top ?? 0;
|
|
1180
|
-
return topA - topB;
|
|
1820
|
+
if (topA !== topB) return topA - topB;
|
|
1821
|
+
const zA = a.options?.zIndex ?? 0;
|
|
1822
|
+
const zB = b.options?.zIndex ?? 0;
|
|
1823
|
+
if (zA !== zB) return zA - zB;
|
|
1824
|
+
return (orderIndex.get(a.id) ?? 0) - (orderIndex.get(b.id) ?? 0);
|
|
1181
1825
|
});
|
|
1182
|
-
const
|
|
1826
|
+
const explicitGroupIds = /* @__PURE__ */ new Set();
|
|
1827
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
1828
|
+
for (const el of sorted) {
|
|
1829
|
+
if (isTableEl(el)) continue;
|
|
1830
|
+
const gid = el.options?.groupId;
|
|
1831
|
+
if (!gid) continue;
|
|
1832
|
+
explicitGroupIds.add(el.id);
|
|
1833
|
+
const arr = groupMap.get(gid);
|
|
1834
|
+
if (arr) arr.push(el);
|
|
1835
|
+
else groupMap.set(gid, [el]);
|
|
1836
|
+
}
|
|
1837
|
+
const followMap = buildFollowMap(sorted, explicitGroupIds);
|
|
1183
1838
|
const followOwner = /* @__PURE__ */ new Map();
|
|
1184
1839
|
for (const [tableId, members] of followMap) {
|
|
1185
1840
|
for (const m of members) followOwner.set(m, tableId);
|
|
1186
1841
|
}
|
|
1842
|
+
const elById = /* @__PURE__ */ new Map();
|
|
1843
|
+
for (const el of sorted) elById.set(el.id, el);
|
|
1844
|
+
const unitOf = buildPaginationUnits(sorted, measuredElements, groupMap);
|
|
1187
1845
|
const pages = [];
|
|
1188
1846
|
let currentPage = [];
|
|
1189
1847
|
let remaining = contentHeight - overlayH - SAFETY_MARGIN;
|
|
@@ -1195,12 +1853,26 @@ function paginate(template, measuredElements) {
|
|
|
1195
1853
|
function fullPageHeight() {
|
|
1196
1854
|
return isFirstPage ? contentHeight - overlayH - SAFETY_MARGIN : contentHeight - SAFETY_MARGIN;
|
|
1197
1855
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1856
|
+
let overflowOnCurrent = false;
|
|
1857
|
+
function pushPage() {
|
|
1858
|
+
pages.push(
|
|
1859
|
+
overflowOnCurrent ? { pageIndex: pages.length, sections: [...currentPage], overflow: true } : { pageIndex: pages.length, sections: [...currentPage] }
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
function noteOverflow(bottom) {
|
|
1863
|
+
if (bottom > contentHeight) overflowOnCurrent = true;
|
|
1864
|
+
}
|
|
1865
|
+
function finishPage(overflow = false) {
|
|
1866
|
+
if (currentPage.length === 0) {
|
|
1867
|
+
overflowOnCurrent = overflowOnCurrent || overflow;
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
pushPage();
|
|
1200
1871
|
currentPage = [];
|
|
1201
1872
|
remaining = contentHeight - SAFETY_MARGIN;
|
|
1202
1873
|
isFirstPage = false;
|
|
1203
1874
|
pageBroken = true;
|
|
1875
|
+
overflowOnCurrent = false;
|
|
1204
1876
|
}
|
|
1205
1877
|
let i = 0;
|
|
1206
1878
|
while (i < sorted.length) {
|
|
@@ -1209,19 +1881,32 @@ function paginate(template, measuredElements) {
|
|
|
1209
1881
|
i++;
|
|
1210
1882
|
continue;
|
|
1211
1883
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1884
|
+
const unit = unitOf.get(el.id);
|
|
1885
|
+
if (unit && unit.anchorId !== el.id) {
|
|
1886
|
+
i++;
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1889
|
+
if (paginationOf(el)?.pageable === false || unit?.forceFirstPage) {
|
|
1890
|
+
if (unit) {
|
|
1891
|
+
for (const id of unit.ids) {
|
|
1892
|
+
currentPage.push({ elementId: id, type: "element", renderTop: elById.get(id)?.options?.top ?? 0 });
|
|
1893
|
+
}
|
|
1894
|
+
} else {
|
|
1895
|
+
currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
|
|
1896
|
+
}
|
|
1214
1897
|
i++;
|
|
1215
1898
|
continue;
|
|
1216
1899
|
}
|
|
1217
1900
|
if (isTableEl(el)) {
|
|
1218
1901
|
i = paginateTable(el, measuredElements, i);
|
|
1902
|
+
} else if (unit) {
|
|
1903
|
+
i = paginateUnit(unit, i);
|
|
1219
1904
|
} else {
|
|
1220
1905
|
i = paginateNonTable(el, measuredElements, sorted, i);
|
|
1221
1906
|
}
|
|
1222
1907
|
}
|
|
1223
1908
|
if (currentPage.length > 0) {
|
|
1224
|
-
|
|
1909
|
+
pushPage();
|
|
1225
1910
|
}
|
|
1226
1911
|
if (pages.length === 0) {
|
|
1227
1912
|
pages.push({ pageIndex: 0, sections: [] });
|
|
@@ -1230,6 +1915,8 @@ function paginate(template, measuredElements) {
|
|
|
1230
1915
|
function paginateNonTable(el, measured, sortedList, idx) {
|
|
1231
1916
|
const elHeight = measured.get(el.id)?.measuredHeight ?? el.options?.height ?? 0;
|
|
1232
1917
|
if (elHeight <= remaining) {
|
|
1918
|
+
const top2 = pageBroken ? 0 : el.options?.top ?? 0;
|
|
1919
|
+
noteOverflow(top2 + elHeight);
|
|
1233
1920
|
currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
|
|
1234
1921
|
remaining -= elHeight;
|
|
1235
1922
|
if (paginationOf(el)?.keepWithNext && idx + 1 < sortedList.length) {
|
|
@@ -1247,11 +1934,43 @@ function paginate(template, measuredElements) {
|
|
|
1247
1934
|
}
|
|
1248
1935
|
return idx + 1;
|
|
1249
1936
|
}
|
|
1250
|
-
|
|
1937
|
+
const top = pageBroken ? 0 : el.options?.top ?? 0;
|
|
1938
|
+
finishPage(top + elHeight > contentHeight);
|
|
1251
1939
|
currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
|
|
1252
1940
|
remaining -= elHeight;
|
|
1253
1941
|
return idx + 1;
|
|
1254
1942
|
}
|
|
1943
|
+
function paginateUnit(unit, idx) {
|
|
1944
|
+
const members = unit.ids.map((id) => elById.get(id)).filter((m) => !!m);
|
|
1945
|
+
let minTop = Number.POSITIVE_INFINITY;
|
|
1946
|
+
let maxBottom = Number.NEGATIVE_INFINITY;
|
|
1947
|
+
for (const m of members) {
|
|
1948
|
+
const top2 = m.options?.top ?? 0;
|
|
1949
|
+
minTop = Math.min(minTop, top2);
|
|
1950
|
+
maxBottom = Math.max(maxBottom, top2 + effectiveHeight(m, measuredElements));
|
|
1951
|
+
}
|
|
1952
|
+
const unitHeight = Math.max(maxBottom - minTop, 0);
|
|
1953
|
+
const place = () => {
|
|
1954
|
+
const offset = pageBroken ? -minTop : 0;
|
|
1955
|
+
noteOverflow(minTop + offset + unitHeight);
|
|
1956
|
+
for (const m of members) {
|
|
1957
|
+
currentPage.push({
|
|
1958
|
+
elementId: m.id,
|
|
1959
|
+
type: "element",
|
|
1960
|
+
renderTop: (m.options?.top ?? 0) + offset
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
remaining -= unitHeight;
|
|
1964
|
+
};
|
|
1965
|
+
if (unitHeight <= remaining) {
|
|
1966
|
+
place();
|
|
1967
|
+
return idx + 1;
|
|
1968
|
+
}
|
|
1969
|
+
const top = pageBroken ? 0 : minTop;
|
|
1970
|
+
finishPage(top + unitHeight > contentHeight);
|
|
1971
|
+
place();
|
|
1972
|
+
return idx + 1;
|
|
1973
|
+
}
|
|
1255
1974
|
function paginateTable(el, measured, idx) {
|
|
1256
1975
|
const opts = el.options ?? {};
|
|
1257
1976
|
const renderRows = opts._renderRows ?? [];
|
|
@@ -1417,18 +2136,28 @@ function specialRowHeight(renderRows, rowHeights, type) {
|
|
|
1417
2136
|
return h;
|
|
1418
2137
|
}
|
|
1419
2138
|
|
|
2139
|
+
// src/render/barcode-dot.ts
|
|
2140
|
+
function barcodeAvailableBoxMm(boxMm, maxMm) {
|
|
2141
|
+
const box = typeof boxMm === "number" && boxMm > 0 ? boxMm : Number.POSITIVE_INFINITY;
|
|
2142
|
+
const limit = typeof maxMm === "number" && maxMm > 0 ? Math.min(box, maxMm) : box;
|
|
2143
|
+
return Number.isFinite(limit) ? limit : 0;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
1420
2146
|
// src/render/html-generator.ts
|
|
1421
2147
|
function generateHtml(template, pageLayouts, printData, options) {
|
|
1422
|
-
const css = buildPageCss(template);
|
|
2148
|
+
const css = buildFontFaceCss(template.fonts) + buildPageCss(template, options?.pageHeightMm);
|
|
1423
2149
|
const isMeasure = options?.isMeasurementPass === true;
|
|
1424
2150
|
const totalPages = isMeasure ? 1 : pageLayouts.length;
|
|
1425
|
-
const ctx = {
|
|
2151
|
+
const ctx = {
|
|
2152
|
+
codeRenderer: options?.codeRenderer,
|
|
2153
|
+
pageHeightMm: options?.pageHeightMm
|
|
2154
|
+
};
|
|
1426
2155
|
if (isMeasure) {
|
|
1427
|
-
return generateMeasurementHtml(template, css, ctx);
|
|
2156
|
+
return generateMeasurementHtml(template, css, ctx, printData);
|
|
1428
2157
|
}
|
|
1429
|
-
return generateFinalHtml(template, pageLayouts, css, totalPages, ctx);
|
|
2158
|
+
return generateFinalHtml(template, pageLayouts, css, totalPages, ctx, printData);
|
|
1430
2159
|
}
|
|
1431
|
-
function generateMeasurementHtml(template, css, ctx) {
|
|
2160
|
+
function generateMeasurementHtml(template, css, ctx, printData) {
|
|
1432
2161
|
const paper = getPaperDims(template);
|
|
1433
2162
|
const contentWidth = paper.width - template.margins.left - template.margins.right;
|
|
1434
2163
|
const elementsHtml = template.elements.map((el) => renderElement(el, true, void 0, void 0, ctx)).join("\n");
|
|
@@ -1450,6 +2179,7 @@ function generateMeasurementHtml(template, css, ctx) {
|
|
|
1450
2179
|
</head>
|
|
1451
2180
|
<body class="measure-mode">
|
|
1452
2181
|
<section class="print-page" data-measure-page="0">
|
|
2182
|
+
${renderWatermarkLayerHtml(template.watermark, printData, getPaperDims(template))}
|
|
1453
2183
|
<div class="page-header">${headerHtml}</div>
|
|
1454
2184
|
<div class="first-page-overlay">${overlayHtml}</div>
|
|
1455
2185
|
<div class="content-area" style="height:auto;overflow:visible;">
|
|
@@ -1461,26 +2191,42 @@ function generateMeasurementHtml(template, css, ctx) {
|
|
|
1461
2191
|
html = injectSystemVariables(html);
|
|
1462
2192
|
return html;
|
|
1463
2193
|
}
|
|
1464
|
-
function
|
|
2194
|
+
function renderFinalPages(template, pageLayouts, printData, ctx, options) {
|
|
2195
|
+
const pageOffset = options?.pageOffset ?? 0;
|
|
2196
|
+
const totalPages = options?.totalPages ?? pageLayouts.length;
|
|
1465
2197
|
const pagesHtml = pageLayouts.map((page) => {
|
|
1466
|
-
const pageNum = page.pageIndex + 1;
|
|
1467
|
-
return renderPage(template, page, pageNum, totalPages, ctx);
|
|
2198
|
+
const pageNum = page.pageIndex + 1 + pageOffset;
|
|
2199
|
+
return renderPage(template, page, pageNum, totalPages, ctx, printData, options?.pageClass);
|
|
1468
2200
|
}).join("\n");
|
|
1469
|
-
|
|
2201
|
+
return injectSystemVariables(pagesHtml);
|
|
2202
|
+
}
|
|
2203
|
+
function wrapHtmlDocument(css, bodyInnerHtml, bodyClass) {
|
|
2204
|
+
const html = `<!DOCTYPE html>
|
|
1470
2205
|
<html lang="zh-CN">
|
|
1471
2206
|
<head>
|
|
1472
2207
|
<meta charset="UTF-8">
|
|
1473
2208
|
<style>${css}</style>
|
|
1474
2209
|
</head>
|
|
1475
|
-
<body>
|
|
1476
|
-
${
|
|
2210
|
+
<body${bodyClass ? ` class="${bodyClass}"` : ""}>
|
|
2211
|
+
${bodyInnerHtml}
|
|
1477
2212
|
</body>
|
|
1478
2213
|
</html>`;
|
|
1479
|
-
|
|
1480
|
-
|
|
2214
|
+
return injectSystemVariables(html);
|
|
2215
|
+
}
|
|
2216
|
+
function generateFinalHtml(template, pageLayouts, css, _totalPages2, ctx, printData) {
|
|
2217
|
+
const bodyInner = renderFinalPages(template, pageLayouts, printData ?? {}, ctx);
|
|
2218
|
+
return wrapHtmlDocument(
|
|
2219
|
+
css,
|
|
2220
|
+
bodyInner,
|
|
2221
|
+
isContinuousPaper(template) ? "continuous" : void 0
|
|
2222
|
+
);
|
|
1481
2223
|
}
|
|
1482
|
-
function renderPage(template, page, pageNum, totalPages, ctx) {
|
|
2224
|
+
function renderPage(template, page, pageNum, totalPages, ctx, printData, pageClass) {
|
|
1483
2225
|
const paper = getPaperDims(template);
|
|
2226
|
+
const paperMm = {
|
|
2227
|
+
width: paper.width,
|
|
2228
|
+
height: ctx.pageHeightMm && ctx.pageHeightMm > 0 ? ctx.pageHeightMm : paper.height
|
|
2229
|
+
};
|
|
1484
2230
|
const contentWidth = paper.width - template.margins.left - template.margins.right;
|
|
1485
2231
|
const headerHtml = renderAreaElements(
|
|
1486
2232
|
template.header?.elements ?? [],
|
|
@@ -1500,13 +2246,18 @@ function renderPage(template, page, pageNum, totalPages, ctx) {
|
|
|
1500
2246
|
let contentHtml = page.sections.map((section) => renderSection(section, template, ctx)).join("\n");
|
|
1501
2247
|
contentHtml = contentHtml.replace(/\{pageIndex\}/g, String(pageNum));
|
|
1502
2248
|
contentHtml = contentHtml.replace(/\{totalPages\}/g, String(totalPages));
|
|
1503
|
-
|
|
2249
|
+
const pageInner = `
|
|
2250
|
+
${renderWatermarkLayerHtml(template.watermark, printData, paperMm, { pageIndex: pageNum, totalPages })}
|
|
1504
2251
|
<div class="page-header">${headerHtml}</div>
|
|
1505
2252
|
${overlayHtml}
|
|
1506
2253
|
<div class="content-area">
|
|
1507
2254
|
${contentHtml}
|
|
1508
2255
|
</div>
|
|
1509
|
-
<div class="page-footer">${footerHtml}</div
|
|
2256
|
+
<div class="page-footer">${footerHtml}</div>`;
|
|
2257
|
+
const rot = getOutputRotationAngle(template);
|
|
2258
|
+
const pageBody = rot !== 0 ? `<div class="print-page-rotor print-page-rotor-${rot}">${pageInner}</div>` : pageInner;
|
|
2259
|
+
return `<section class="print-page${pageClass ? ` ${pageClass}` : ""}" data-page="${pageNum}">
|
|
2260
|
+
${pageBody}
|
|
1510
2261
|
</section>`;
|
|
1511
2262
|
}
|
|
1512
2263
|
function renderSection(section, template, ctx) {
|
|
@@ -1526,8 +2277,9 @@ var V_ALIGN_FLEX = { top: "flex-start", middle: "center", bottom: "flex-end" };
|
|
|
1526
2277
|
var H_ALIGN_FLEX = { left: "flex-start", center: "center", right: "flex-end" };
|
|
1527
2278
|
function textStyle(opts) {
|
|
1528
2279
|
const parts = [];
|
|
1529
|
-
|
|
1530
|
-
if (
|
|
2280
|
+
const fontSize = opts._fitFontSize === void 0 ? opts.fontSize : roundFontSize(opts._fitFontSize);
|
|
2281
|
+
if (fontSize) parts.push(`font-size:${fontSize}pt`);
|
|
2282
|
+
if (opts.fontFamily) parts.push(`font-family:${escapeInlineStyleValue(toFontFamilyStack(opts.fontFamily))}`);
|
|
1531
2283
|
if (opts.fontWeight) parts.push(`font-weight:${opts.fontWeight}`);
|
|
1532
2284
|
if (opts.color) parts.push(`color:${opts.color}`);
|
|
1533
2285
|
if (opts.backgroundColor) parts.push(`background-color:${opts.backgroundColor}`);
|
|
@@ -1540,15 +2292,28 @@ function textStyle(opts) {
|
|
|
1540
2292
|
if (opts.textAlign) parts.push(`text-align:${opts.textAlign}`);
|
|
1541
2293
|
return parts.length ? parts.join(";") + ";" : "";
|
|
1542
2294
|
}
|
|
2295
|
+
function elementFitStyle(fit, opts) {
|
|
2296
|
+
if (fit === "autoHeight") return "overflow:visible;";
|
|
2297
|
+
if (opts.wordWrap === false) return "white-space:nowrap;text-overflow:ellipsis;";
|
|
2298
|
+
return "";
|
|
2299
|
+
}
|
|
2300
|
+
function fitAttrs(fit, key, baseFontSizePt, opts) {
|
|
2301
|
+
if (fit !== "shrink") return "";
|
|
2302
|
+
const min2 = resolveShrinkMinFontSize(opts.shrinkMinFontSize);
|
|
2303
|
+
return ` data-fit="shrink" data-fit-key="${esc(key)}" data-fit-base="${baseFontSizePt}" data-fit-min="${min2}"`;
|
|
2304
|
+
}
|
|
1543
2305
|
function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
|
|
1544
2306
|
const opts = el.options ?? {};
|
|
1545
2307
|
const left = opts.left ?? 0;
|
|
1546
2308
|
const top = overrideTop ?? opts.top ?? 0;
|
|
1547
2309
|
const width = opts.width ?? 100;
|
|
1548
2310
|
const height = opts.height ?? void 0;
|
|
1549
|
-
const style = containerStyle ?? elementPositionStyle(left, top, width, height, opts.zIndex);
|
|
1550
|
-
const measureAttr = isMeasure ? ` data-measure-id="${el.id}"` : "";
|
|
1551
2311
|
const type = el.type || el.printElementType?.type || "text";
|
|
2312
|
+
const fit = resolveElementTextFit(type, opts);
|
|
2313
|
+
const fitHeight = fit === "autoHeight" ? void 0 : height;
|
|
2314
|
+
const style = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
|
|
2315
|
+
const measureAttr = isMeasure ? ` data-measure-id="${el.id}"` : "";
|
|
2316
|
+
const fitAttr = fitAttrs(fit, el.id, opts.fontSize ?? 12, opts);
|
|
1552
2317
|
switch (type) {
|
|
1553
2318
|
case "table":
|
|
1554
2319
|
return renderTableElement(el, isMeasure, measureAttr, ctx);
|
|
@@ -1559,9 +2324,17 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
|
|
|
1559
2324
|
case "barcode":
|
|
1560
2325
|
case "qrcode": {
|
|
1561
2326
|
const codeValue = String(opts.formatter ?? opts.testData ?? "").trim();
|
|
1562
|
-
const fill = type === "barcode";
|
|
1563
2327
|
return `<div class="print-element" style="${style}"${measureAttr}>
|
|
1564
|
-
${codeImgHtml(codeValue, type, opts,
|
|
2328
|
+
${codeImgHtml(codeValue, type, opts, {
|
|
2329
|
+
fallback: `<span>${esc(codeValue)}</span>`,
|
|
2330
|
+
codeRenderer: ctx?.codeRenderer,
|
|
2331
|
+
fit: opts.fit,
|
|
2332
|
+
maxWidth: opts.maxWidth,
|
|
2333
|
+
maxHeight: opts.maxHeight,
|
|
2334
|
+
printerDpi: opts.printerDpi,
|
|
2335
|
+
targetWidthMm: opts.width,
|
|
2336
|
+
targetHeightMm: opts.height
|
|
2337
|
+
})}
|
|
1565
2338
|
</div>`;
|
|
1566
2339
|
}
|
|
1567
2340
|
case "hline":
|
|
@@ -1573,30 +2346,32 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
|
|
|
1573
2346
|
case "oval":
|
|
1574
2347
|
return `<div class="print-element" style="${style};border:${opts.borderWidth ?? 1}px solid ${opts.borderColor ?? "#000"};border-radius:50%;"${measureAttr}></div>`;
|
|
1575
2348
|
case "longText":
|
|
1576
|
-
return `<div class="print-element" style="${style}${textStyle(opts)}
|
|
2349
|
+
return `<div class="print-element" style="${style}${textStyle(opts)}${elementFitStyle(fit, opts)}"${measureAttr}${fitAttr}>${esc(opts.formatter ?? opts.testData ?? "")}</div>`;
|
|
1577
2350
|
case "html":
|
|
1578
2351
|
return `<div class="print-element" style="${style}"${measureAttr}>${opts.testData ?? opts.title ?? ""}</div>`;
|
|
1579
2352
|
default:
|
|
1580
|
-
return `<div class="print-element" style="${style}${textStyle(opts)}"${measureAttr}>${esc(opts.formatter ?? opts.testData ?? "")}</div>`;
|
|
2353
|
+
return `<div class="print-element" style="${style}${textStyle(opts)}${elementFitStyle(fit, opts)}"${measureAttr}${fitAttr}>${esc(opts.formatter ?? opts.testData ?? "")}</div>`;
|
|
1581
2354
|
}
|
|
1582
2355
|
}
|
|
1583
|
-
function codeImgHtml(value, cellType, opts,
|
|
1584
|
-
if (!value || !codeRenderer) return
|
|
2356
|
+
function codeImgHtml(value, cellType, opts, io) {
|
|
2357
|
+
if (!value || !io.codeRenderer) return io.fallback;
|
|
2358
|
+
const { fallback, codeRenderer, fit, maxWidth, maxHeight } = io;
|
|
2359
|
+
const isBarcode = cellType === "barcode";
|
|
1585
2360
|
try {
|
|
1586
2361
|
const svg = codeRenderer.render(value, cellType, {
|
|
1587
2362
|
barcodeType: opts.barcodeType,
|
|
1588
2363
|
qrCodeLevel: opts.qrCodeLevel != null ? String(opts.qrCodeLevel) : void 0,
|
|
1589
2364
|
showText: opts.hideTitle !== void 0 ? !opts.hideTitle : opts.showBarcodeText,
|
|
1590
2365
|
barWidth: typeof opts.barWidth === "number" ? opts.barWidth : void 0,
|
|
1591
|
-
fontSize: typeof opts.fontSize === "number" ? opts.fontSize : void 0
|
|
2366
|
+
fontSize: typeof opts.fontSize === "number" ? opts.fontSize : void 0,
|
|
2367
|
+
printerDpi: isBarcode ? io.printerDpi : void 0,
|
|
2368
|
+
targetWidthMm: isBarcode ? barcodeAvailableBoxMm(io.targetWidthMm, maxWidth) : void 0,
|
|
2369
|
+
targetHeightMm: isBarcode ? barcodeAvailableBoxMm(io.targetHeightMm, maxHeight) : void 0
|
|
1592
2370
|
});
|
|
2371
|
+
if (isBarcode && /^<svg[\s>]/i.test(svg)) return inlineCodeSvgHtml(svg);
|
|
1593
2372
|
const src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
1594
2373
|
const styleParts = [];
|
|
1595
|
-
|
|
1596
|
-
styleParts.push("width:100%", "height:100%", "object-fit:contain", "display:block", "margin:auto");
|
|
1597
|
-
} else {
|
|
1598
|
-
styleParts.push("max-width:100%", "max-height:100%", "display:block", "margin:auto");
|
|
1599
|
-
}
|
|
2374
|
+
styleParts.push("max-width:100%", "max-height:100%", "display:block", "margin:auto");
|
|
1600
2375
|
if (fit) {
|
|
1601
2376
|
styleParts.push(`object-fit:${fit}`);
|
|
1602
2377
|
}
|
|
@@ -1609,15 +2384,20 @@ function codeImgHtml(value, cellType, opts, fallbackHtml, fill = false, codeRend
|
|
|
1609
2384
|
const style = styleParts.join(";");
|
|
1610
2385
|
return `<img src="${src}" style="${style}" />`;
|
|
1611
2386
|
} catch {
|
|
1612
|
-
return
|
|
2387
|
+
return fallback;
|
|
1613
2388
|
}
|
|
1614
2389
|
}
|
|
2390
|
+
function inlineCodeSvgHtml(svg) {
|
|
2391
|
+
const styled = svg.replace(/<svg\b/, '<svg style="display:block"');
|
|
2392
|
+
return `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;">${styled}</div>`;
|
|
2393
|
+
}
|
|
1615
2394
|
function matrixCellStyle(cell, opts) {
|
|
1616
2395
|
const parts = [];
|
|
1617
|
-
const fontSize = cell.fontSize ?? opts.tableDefaultFontSize;
|
|
2396
|
+
const fontSize = cell.fittedFontSize ?? cell.fontSize ?? opts.tableDefaultFontSize;
|
|
1618
2397
|
const color = cell.color ?? opts.tableDefaultColor;
|
|
1619
2398
|
const padding = cell.padding ?? opts.tableDefaultPadding ?? 1;
|
|
1620
2399
|
if (fontSize) parts.push(`font-size:${fontSize}pt`);
|
|
2400
|
+
if (cell.fontFamily) parts.push(`font-family:${escapeInlineStyleValue(toFontFamilyStack(cell.fontFamily))}`);
|
|
1621
2401
|
if (cell.fontWeight) parts.push(`font-weight:${cell.fontWeight}`);
|
|
1622
2402
|
if (color) parts.push(`color:${color}`);
|
|
1623
2403
|
if (cell.backgroundColor) parts.push(`background-color:${cell.backgroundColor}`);
|
|
@@ -1632,25 +2412,36 @@ function matrixCellStyle(cell, opts) {
|
|
|
1632
2412
|
}
|
|
1633
2413
|
return parts.join(";");
|
|
1634
2414
|
}
|
|
1635
|
-
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx) {
|
|
2415
|
+
function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx, fitOwner = { elementId: "", kind: "b" }) {
|
|
1636
2416
|
const trs = [];
|
|
2417
|
+
const defaultPadding = opts.tableDefaultPadding ?? 1;
|
|
1637
2418
|
for (let r = start; r < end; r++) {
|
|
1638
2419
|
const row = renderRows[r];
|
|
1639
2420
|
if (!row) continue;
|
|
1640
2421
|
const idxAttr = withRowIndex ? ` data-row-index="${r}"` : "";
|
|
1641
|
-
const tds = row.cells.filter((cell) => !cell.merged).map((cell) => {
|
|
2422
|
+
const tds = row.cells.map((cell, ci) => ({ cell, ci })).filter(({ cell }) => !cell.merged).map(({ cell, ci }) => {
|
|
1642
2423
|
const span = `${cell.rowspan > 1 ? ` rowspan="${cell.rowspan}"` : ""}${cell.colspan > 1 ? ` colspan="${cell.colspan}"` : ""}`;
|
|
2424
|
+
const colIndex = ci;
|
|
1643
2425
|
let inner;
|
|
1644
2426
|
if (cell.cellType === "barcode" || cell.cellType === "qrcode") {
|
|
1645
|
-
|
|
1646
|
-
|
|
2427
|
+
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;">${codeImgHtml(cell.content, cell.cellType, cell, {
|
|
2428
|
+
fallback: esc(cell.content),
|
|
2429
|
+
codeRenderer: ctx?.codeRenderer,
|
|
2430
|
+
fit: cell.fit,
|
|
2431
|
+
maxWidth: cell.maxWidth,
|
|
2432
|
+
maxHeight: cell.maxHeight,
|
|
2433
|
+
printerDpi: cell.printerDpi,
|
|
2434
|
+
// 可用框 = 单元格内容区(列宽/行高扣除内边距与塌陷边框);列宽缺失时宽度为 0 → 不约束宽度
|
|
2435
|
+
targetWidthMm: cellFitWidthMm(opts.tableColWidths ?? [], ci, cell, defaultPadding),
|
|
2436
|
+
targetHeightMm: cellFitCapMm(renderRows, r, cell, defaultPadding)
|
|
2437
|
+
})}</div>`;
|
|
1647
2438
|
} else if (cell.cellType === "image") {
|
|
1648
2439
|
const fit = cell.fit || "contain";
|
|
1649
2440
|
const maxWidth = cell.maxWidth ? `max-width:${cell.maxWidth}mm;` : "max-width:100%;";
|
|
1650
2441
|
const maxHeight = cell.maxHeight ? `max-height:${cell.maxHeight}mm;` : "max-height:100%;";
|
|
1651
2442
|
inner = `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;overflow:hidden;"><img src="${esc(cell.content)}" style="object-fit:${fit};${maxWidth}${maxHeight}display:block;" /></div>`;
|
|
1652
2443
|
} else {
|
|
1653
|
-
inner =
|
|
2444
|
+
inner = renderTextCellInner(renderRows, r, colIndex, cell, opts, fitOwner, defaultPadding);
|
|
1654
2445
|
}
|
|
1655
2446
|
return `<td${span} style="${matrixCellStyle(cell, opts)}">${inner}</td>`;
|
|
1656
2447
|
}).join("");
|
|
@@ -1658,6 +2449,20 @@ function renderMatrixRows(renderRows, start, end, opts, withRowIndex, ctx) {
|
|
|
1658
2449
|
}
|
|
1659
2450
|
return trs.join("\n");
|
|
1660
2451
|
}
|
|
2452
|
+
function renderTextCellInner(renderRows, rowIndex, colIndex, cell, opts, fitOwner, defaultPadding) {
|
|
2453
|
+
const fit = resolveCellTextFit(cell);
|
|
2454
|
+
const text = esc(cell.content);
|
|
2455
|
+
if (fit === "autoHeight") return text;
|
|
2456
|
+
const capMm = cellFitCapMm(renderRows, rowIndex, cell, defaultPadding);
|
|
2457
|
+
const nowrap = cell.wordWrap === false;
|
|
2458
|
+
const style = [
|
|
2459
|
+
`max-height:${capMm}mm`,
|
|
2460
|
+
"overflow:hidden",
|
|
2461
|
+
...nowrap ? ["white-space:nowrap", "text-overflow:ellipsis"] : []
|
|
2462
|
+
].join(";");
|
|
2463
|
+
const attrs = fit === "shrink" && fitOwner.elementId ? ` data-fit="shrink" data-fit-key="${esc(cellFitKey(fitOwner.elementId, fitOwner.kind, rowIndex, colIndex))}" data-fit-base="${cell.fontSize ?? opts.tableDefaultFontSize ?? 12}" data-fit-min="${resolveShrinkMinFontSize(cell.shrinkMinFontSize)}" data-fit-mm="${capMm}"` : "";
|
|
2464
|
+
return `<div class="cell-fit" style="${style}"${attrs}>${text}</div>`;
|
|
2465
|
+
}
|
|
1661
2466
|
function matrixTableHtml(el, bodyHtml) {
|
|
1662
2467
|
const opts = el.options;
|
|
1663
2468
|
const colWidths = opts.tableColWidths ?? [];
|
|
@@ -1672,7 +2477,7 @@ function renderTableElement(el, isMeasure, measureAttr, ctx) {
|
|
|
1672
2477
|
const opts = el.options;
|
|
1673
2478
|
const style = elementPositionStyle(opts.left ?? 0, opts.top ?? 0, opts.width ?? 100, void 0, opts.zIndex);
|
|
1674
2479
|
const renderRows = opts._renderRows ?? [];
|
|
1675
|
-
const bodyHtml = renderMatrixRows(renderRows, 0, renderRows.length, opts, isMeasure, ctx);
|
|
2480
|
+
const bodyHtml = renderMatrixRows(renderRows, 0, renderRows.length, opts, isMeasure, ctx, { elementId: el.id, kind: "b" });
|
|
1676
2481
|
return `<div class="print-element" style="${style};overflow:visible;"${measureAttr}>
|
|
1677
2482
|
${matrixTableHtml(el, bodyHtml)}
|
|
1678
2483
|
</div>`;
|
|
@@ -1684,8 +2489,8 @@ function renderTableSlice(el, section, ctx) {
|
|
|
1684
2489
|
const startRow = section.startRow ?? 0;
|
|
1685
2490
|
const endRow = section.endRow ?? renderRows.length;
|
|
1686
2491
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
1687
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx) : "";
|
|
1688
|
-
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx);
|
|
2492
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
2493
|
+
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
1689
2494
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
1690
2495
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
|
1691
2496
|
return `<div class="print-element" style="${style};overflow:visible;">
|
|
@@ -1709,12 +2514,12 @@ function renderSubtotalRows(el, section, opts, ctx) {
|
|
|
1709
2514
|
...tpl,
|
|
1710
2515
|
cells: tpl.cells.map((cell) => cell.rawFormatter ? { ...cell, content: evaluateTemplate(cell.rawFormatter, { rows: pageCtx, ...mainData }) } : cell)
|
|
1711
2516
|
}));
|
|
1712
|
-
return renderMatrixRows(rows, 0, rows.length, opts, false, ctx);
|
|
2517
|
+
return renderMatrixRows(rows, 0, rows.length, opts, false, ctx, { elementId: el.id, kind: "st" });
|
|
1713
2518
|
}
|
|
1714
2519
|
function renderSummaryRows(el, opts, ctx) {
|
|
1715
2520
|
const summaryRows = opts._summaryRows ?? [];
|
|
1716
2521
|
if (summaryRows.length === 0) return "";
|
|
1717
|
-
return renderMatrixRows(summaryRows, 0, summaryRows.length, opts, false, ctx);
|
|
2522
|
+
return renderMatrixRows(summaryRows, 0, summaryRows.length, opts, false, ctx, { elementId: el.id, kind: "sm" });
|
|
1718
2523
|
}
|
|
1719
2524
|
function renderFlowGroup(el, section, template, ctx) {
|
|
1720
2525
|
const opts = el.options ?? {};
|
|
@@ -1730,8 +2535,8 @@ function renderFlowGroup(el, section, template, ctx) {
|
|
|
1730
2535
|
if (endRow > startRow || section.subtotal || section.summary) {
|
|
1731
2536
|
const renderRows = opts._renderRows ?? [];
|
|
1732
2537
|
const repeatCount = opts._repeatHeaderCount ?? 0;
|
|
1733
|
-
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx) : "";
|
|
1734
|
-
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx);
|
|
2538
|
+
const repeatHtml = section.repeatHeader && repeatCount > 0 ? renderMatrixRows(renderRows, 0, repeatCount, opts, false, ctx, { elementId: el.id, kind: "b" }) : "";
|
|
2539
|
+
const bodyHtml = renderMatrixRows(renderRows, startRow, endRow, opts, false, ctx, { elementId: el.id, kind: "b" });
|
|
1735
2540
|
const subtotalHtml = section.subtotal ? renderSubtotalRows(el, section, opts, ctx) : "";
|
|
1736
2541
|
const summaryHtml = section.summary ? renderSummaryRows(el, opts, ctx) : "";
|
|
1737
2542
|
sliceHtml = `<div class="flow-slice" style="position:relative;width:${mm(tableWidth)};overflow:visible;">
|
|
@@ -1799,6 +2604,936 @@ function esc(str) {
|
|
|
1799
2604
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1800
2605
|
}
|
|
1801
2606
|
|
|
2607
|
+
// src/render/continuous-paper.ts
|
|
2608
|
+
var MIN_CONTINUOUS_HEIGHT_MM = 25.4;
|
|
2609
|
+
function composeContinuousHeight(template, contentBottomMm) {
|
|
2610
|
+
const mb = template.margins?.bottom ?? 0;
|
|
2611
|
+
const footerH = template.footer?.height ?? 0;
|
|
2612
|
+
const height = Math.max(contentBottomMm, 0) + footerH + mb;
|
|
2613
|
+
return Math.max(MIN_CONTINUOUS_HEIGHT_MM, Math.round(height * 100) / 100);
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
// src/print/units.ts
|
|
2617
|
+
var PX_PER_MM2 = 3.7795275591;
|
|
2618
|
+
var MICROMETERS_PER_MM = 1e3;
|
|
2619
|
+
var MM_PER_INCH = 25.4;
|
|
2620
|
+
var MICROMETERS_PER_INCH = 25400;
|
|
2621
|
+
function pxToMm(px) {
|
|
2622
|
+
return px / PX_PER_MM2;
|
|
2623
|
+
}
|
|
2624
|
+
function mmToPx(mm2) {
|
|
2625
|
+
return Math.round(mm2 * PX_PER_MM2);
|
|
2626
|
+
}
|
|
2627
|
+
function millimetersToMicrometers(mm2) {
|
|
2628
|
+
return Math.round(mm2 * MICROMETERS_PER_MM);
|
|
2629
|
+
}
|
|
2630
|
+
function micrometersToMillimeters(um) {
|
|
2631
|
+
return um / MICROMETERS_PER_MM;
|
|
2632
|
+
}
|
|
2633
|
+
function millimetersToInches(mm2) {
|
|
2634
|
+
return mm2 / MM_PER_INCH;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
// src/print/errors.ts
|
|
2638
|
+
var PrintFailure = class extends Error {
|
|
2639
|
+
constructor(code, message, cause) {
|
|
2640
|
+
super(message);
|
|
2641
|
+
this.name = "PrintFailure";
|
|
2642
|
+
this.code = code;
|
|
2643
|
+
this.cause = cause;
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
function toPrintFailure(err, fallbackCode, context) {
|
|
2647
|
+
if (err instanceof PrintFailure) return err;
|
|
2648
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2649
|
+
return new PrintFailure(fallbackCode, `${context}\uFF1A${detail}`, err);
|
|
2650
|
+
}
|
|
2651
|
+
async function withTimeout(task, ms, code, message) {
|
|
2652
|
+
let timer;
|
|
2653
|
+
try {
|
|
2654
|
+
return await Promise.race([
|
|
2655
|
+
task,
|
|
2656
|
+
new Promise((_resolve, reject) => {
|
|
2657
|
+
timer = setTimeout(() => reject(new PrintFailure(code, message)), ms);
|
|
2658
|
+
})
|
|
2659
|
+
]);
|
|
2660
|
+
} finally {
|
|
2661
|
+
if (timer) clearTimeout(timer);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
// src/print/paper.ts
|
|
2666
|
+
function positive(value) {
|
|
2667
|
+
return typeof value === "number" && value > 0 ? value : void 0;
|
|
2668
|
+
}
|
|
2669
|
+
function escapeHeightMm(input) {
|
|
2670
|
+
return positive(input.paperHeightMm) ?? positive(input.override?.height);
|
|
2671
|
+
}
|
|
2672
|
+
function resolvePaperMm(input) {
|
|
2673
|
+
const width = positive(input.override?.width) ?? input.paperMm.width;
|
|
2674
|
+
const overrideHeight = positive(input.override?.height);
|
|
2675
|
+
if (input.continuous) {
|
|
2676
|
+
return overrideHeight ? { paperMm: { width, height: overrideHeight }, heightSource: "config" } : { paperMm: { width, height: input.paperMm.height }, heightSource: "derived" };
|
|
2677
|
+
}
|
|
2678
|
+
return { paperMm: { width, height: overrideHeight ?? input.paperMm.height }, heightSource: "config" };
|
|
2679
|
+
}
|
|
2680
|
+
function paperViewportPx(paper) {
|
|
2681
|
+
return { width: mmToPx(paper.width), height: mmToPx(paper.height) };
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// src/print/pdf-spec.ts
|
|
2685
|
+
var ZERO_MARGINS_MM = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2686
|
+
function buildPdfTargetSpec(paperMm) {
|
|
2687
|
+
return {
|
|
2688
|
+
paperMm,
|
|
2689
|
+
marginsMm: { ...ZERO_MARGINS_MM },
|
|
2690
|
+
printBackground: true,
|
|
2691
|
+
scale: 1,
|
|
2692
|
+
preferCSSPageSize: false
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
function toElectronPrintToPdfOptions(spec) {
|
|
2696
|
+
return {
|
|
2697
|
+
margins: { ...spec.marginsMm },
|
|
2698
|
+
pageSize: {
|
|
2699
|
+
width: millimetersToInches(spec.paperMm.width),
|
|
2700
|
+
height: millimetersToInches(spec.paperMm.height)
|
|
2701
|
+
},
|
|
2702
|
+
printBackground: spec.printBackground,
|
|
2703
|
+
scale: spec.scale,
|
|
2704
|
+
preferCSSPageSize: spec.preferCSSPageSize
|
|
2705
|
+
};
|
|
2706
|
+
}
|
|
2707
|
+
function toPlaywrightPdfOptions(spec) {
|
|
2708
|
+
const mm2 = (value) => `${value}mm`;
|
|
2709
|
+
return {
|
|
2710
|
+
width: mm2(spec.paperMm.width),
|
|
2711
|
+
height: mm2(spec.paperMm.height),
|
|
2712
|
+
margin: {
|
|
2713
|
+
top: mm2(spec.marginsMm.top),
|
|
2714
|
+
right: mm2(spec.marginsMm.right),
|
|
2715
|
+
bottom: mm2(spec.marginsMm.bottom),
|
|
2716
|
+
left: mm2(spec.marginsMm.left)
|
|
2717
|
+
},
|
|
2718
|
+
printBackground: spec.printBackground,
|
|
2719
|
+
preferCSSPageSize: spec.preferCSSPageSize
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
function buildScreenshotTargetSpec() {
|
|
2723
|
+
return { type: "png", fullPage: true, omitBackground: false };
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/print/measure.ts
|
|
2727
|
+
function normalizeMeasurements(raw, template) {
|
|
2728
|
+
const index = new Map(template.elements.map((el) => [el.id, el]));
|
|
2729
|
+
const measured = /* @__PURE__ */ new Map();
|
|
2730
|
+
for (const item of raw) {
|
|
2731
|
+
const element = index.get(item.id);
|
|
2732
|
+
const repeatCount = element?.options?._repeatHeaderCount ?? 0;
|
|
2733
|
+
const rowHeights = item.rowHeightsPx?.map(pxToMm);
|
|
2734
|
+
measured.set(item.id, {
|
|
2735
|
+
id: item.id,
|
|
2736
|
+
measuredHeight: pxToMm(item.heightPx),
|
|
2737
|
+
measuredRowHeights: rowHeights,
|
|
2738
|
+
repeatHeaderHeight: rowHeights && rowHeights.length > 0 && repeatCount > 0 ? rowHeights.slice(0, repeatCount).reduce((sum2, h) => sum2 + h, 0) : 0
|
|
2739
|
+
});
|
|
2740
|
+
}
|
|
2741
|
+
return measured;
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
// src/print/apply-text-fit.ts
|
|
2745
|
+
var CELL_ROW_SOURCES = {
|
|
2746
|
+
b: "_renderRows",
|
|
2747
|
+
st: "_subtotalTemplates",
|
|
2748
|
+
sm: "_summaryRows"
|
|
2749
|
+
};
|
|
2750
|
+
function applyTextFitSizes(template, fits) {
|
|
2751
|
+
if (!fits || fits.length === 0) return;
|
|
2752
|
+
const index = /* @__PURE__ */ new Map();
|
|
2753
|
+
const collect = (elements) => {
|
|
2754
|
+
for (const el of elements ?? []) index.set(el.id, el);
|
|
2755
|
+
};
|
|
2756
|
+
collect(template.elements);
|
|
2757
|
+
collect(template.header?.elements);
|
|
2758
|
+
collect(template.footer?.elements);
|
|
2759
|
+
collect(template.firstPageOverlay?.elements);
|
|
2760
|
+
for (const fit of fits) {
|
|
2761
|
+
const parsed = parseCellFitKey(fit.key);
|
|
2762
|
+
if (!parsed) {
|
|
2763
|
+
const el2 = index.get(fit.key);
|
|
2764
|
+
if (el2) el2.options._fitFontSize = roundFontSize(fit.fontSizePt);
|
|
2765
|
+
continue;
|
|
2766
|
+
}
|
|
2767
|
+
const el = index.get(parsed.elementId);
|
|
2768
|
+
const rows = el?.options?.[CELL_ROW_SOURCES[parsed.kind]];
|
|
2769
|
+
const cell = rows?.[parsed.rowIndex]?.cells?.[parsed.colIndex];
|
|
2770
|
+
if (cell) cell.fittedFontSize = roundFontSize(fit.fontSizePt);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
// src/print/codes.ts
|
|
2775
|
+
function codeSpecKey(value, cellType, opts = {}) {
|
|
2776
|
+
return JSON.stringify([
|
|
2777
|
+
value,
|
|
2778
|
+
cellType,
|
|
2779
|
+
opts.barcodeType ?? null,
|
|
2780
|
+
opts.qrCodeLevel ?? null,
|
|
2781
|
+
opts.showText ?? null,
|
|
2782
|
+
opts.barWidth ?? null,
|
|
2783
|
+
opts.fontSize ?? null
|
|
2784
|
+
]);
|
|
2785
|
+
}
|
|
2786
|
+
function createMapCodeRenderer(map) {
|
|
2787
|
+
return {
|
|
2788
|
+
render(value, cellType, opts) {
|
|
2789
|
+
const svg = map.get(codeSpecKey(value, cellType, opts));
|
|
2790
|
+
if (!svg) throw new Error(`\u7801\u503C\u672A\u6E32\u67D3\uFF1A${value}`);
|
|
2791
|
+
return svg;
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
}
|
|
2795
|
+
function createCollectingCodeRenderer(base) {
|
|
2796
|
+
const collected = /* @__PURE__ */ new Map();
|
|
2797
|
+
return {
|
|
2798
|
+
renderer: {
|
|
2799
|
+
render(value, cellType, opts = {}) {
|
|
2800
|
+
const key = codeSpecKey(value, cellType, opts);
|
|
2801
|
+
const hit = base?.get(key);
|
|
2802
|
+
if (hit) return hit;
|
|
2803
|
+
collected.set(key, { key, value, cellType, opts });
|
|
2804
|
+
throw new Error("collect");
|
|
2805
|
+
}
|
|
2806
|
+
},
|
|
2807
|
+
takeSpecs() {
|
|
2808
|
+
const specs = [...collected.values()];
|
|
2809
|
+
collected.clear();
|
|
2810
|
+
return specs;
|
|
2811
|
+
}
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
function mergeCodeMaps(...maps) {
|
|
2815
|
+
const merged = /* @__PURE__ */ new Map();
|
|
2816
|
+
for (const map of maps) {
|
|
2817
|
+
for (const [key, svg] of map) merged.set(key, svg);
|
|
2818
|
+
}
|
|
2819
|
+
return merged;
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
// src/print/driver.ts
|
|
2823
|
+
var EXECUTOR_TARGETS = {
|
|
2824
|
+
waitReady: "window",
|
|
2825
|
+
readMeasurements: "document",
|
|
2826
|
+
readContentBottom: "document",
|
|
2827
|
+
renderCodes: "none",
|
|
2828
|
+
applyTextFit: "document"
|
|
2829
|
+
};
|
|
2830
|
+
|
|
2831
|
+
// src/print/ports.ts
|
|
2832
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
2833
|
+
var DEFAULT_READINESS_MS = 5e3;
|
|
2834
|
+
|
|
2835
|
+
// src/print/dom-host-runtime.ts
|
|
2836
|
+
function createDomHostRuntime(factory, bundle) {
|
|
2837
|
+
return {
|
|
2838
|
+
async withSession(options, fn) {
|
|
2839
|
+
const driver = await factory.createDriver();
|
|
2840
|
+
const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
2841
|
+
const readinessMs = options.readinessMs ?? DEFAULT_READINESS_MS;
|
|
2842
|
+
const budget = () => Math.max(1, deadline - Date.now());
|
|
2843
|
+
const fail = (err, code, context) => toPrintFailure(err, code, context);
|
|
2844
|
+
let injected = false;
|
|
2845
|
+
const ensureExecutor = async () => {
|
|
2846
|
+
if (injected) return;
|
|
2847
|
+
if (driver.requiresExecutor === false) {
|
|
2848
|
+
injected = true;
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2851
|
+
if (!bundle) throw new PrintFailure("INTERNAL", "\u7F3A\u5C11 core DOM \u6267\u884C\u5668\u4EA7\u7269");
|
|
2852
|
+
await driver.injectExecutor(bundle);
|
|
2853
|
+
injected = true;
|
|
2854
|
+
};
|
|
2855
|
+
const load = async (html, viewport) => {
|
|
2856
|
+
await driver.open(viewport);
|
|
2857
|
+
await driver.setContent(html);
|
|
2858
|
+
injected = false;
|
|
2859
|
+
await ensureExecutor();
|
|
2860
|
+
await driver.evaluate("waitReady", [readinessMs]);
|
|
2861
|
+
};
|
|
2862
|
+
const session = {
|
|
2863
|
+
async renderCodes(specs) {
|
|
2864
|
+
if (specs.length === 0) return /* @__PURE__ */ new Map();
|
|
2865
|
+
const ms = budget();
|
|
2866
|
+
return withTimeout(
|
|
2867
|
+
(async () => {
|
|
2868
|
+
try {
|
|
2869
|
+
await ensureExecutor();
|
|
2870
|
+
const map = await driver.evaluate("renderCodes", [specs]);
|
|
2871
|
+
return new Map(Object.entries(map));
|
|
2872
|
+
} catch (err) {
|
|
2873
|
+
throw fail(err, "INTERNAL", "\u7801\u503C\u6E32\u67D3\u5931\u8D25");
|
|
2874
|
+
}
|
|
2875
|
+
})(),
|
|
2876
|
+
ms,
|
|
2877
|
+
"RENDER_TIMEOUT",
|
|
2878
|
+
`\u7801\u503C\u6E32\u67D3\u8D85\u8FC7 ${ms}ms`
|
|
2879
|
+
);
|
|
2880
|
+
},
|
|
2881
|
+
async measure(html, viewport) {
|
|
2882
|
+
const ms = budget();
|
|
2883
|
+
return withTimeout(
|
|
2884
|
+
(async () => {
|
|
2885
|
+
try {
|
|
2886
|
+
await load(html, viewport);
|
|
2887
|
+
const fits = await driver.evaluate("applyTextFit") ?? [];
|
|
2888
|
+
const measurements = await driver.evaluate("readMeasurements");
|
|
2889
|
+
return { measurements, fits };
|
|
2890
|
+
} catch (err) {
|
|
2891
|
+
throw fail(err, "MEASURE_FAILED", "\u6D4B\u91CF\u5931\u8D25");
|
|
2892
|
+
}
|
|
2893
|
+
})(),
|
|
2894
|
+
ms,
|
|
2895
|
+
"RENDER_TIMEOUT",
|
|
2896
|
+
`\u6D4B\u91CF\u8D85\u8FC7 ${ms}ms`
|
|
2897
|
+
);
|
|
2898
|
+
},
|
|
2899
|
+
async probeContentBottom(html, viewport) {
|
|
2900
|
+
const ms = budget();
|
|
2901
|
+
return withTimeout(
|
|
2902
|
+
(async () => {
|
|
2903
|
+
try {
|
|
2904
|
+
await load(html, viewport);
|
|
2905
|
+
return await driver.evaluate("readContentBottom");
|
|
2906
|
+
} catch (err) {
|
|
2907
|
+
throw fail(err, "MEASURE_FAILED", "\u8FDE\u7EED\u7EB8\u63A2\u9488\u5931\u8D25");
|
|
2908
|
+
}
|
|
2909
|
+
})(),
|
|
2910
|
+
ms,
|
|
2911
|
+
"RENDER_TIMEOUT",
|
|
2912
|
+
`\u8FDE\u7EED\u7EB8\u63A2\u9488\u8D85\u8FC7 ${ms}ms`
|
|
2913
|
+
);
|
|
2914
|
+
},
|
|
2915
|
+
async toPdf(html, spec, viewport) {
|
|
2916
|
+
if (!driver.pdf) throw new PrintFailure("UNSUPPORTED_RUNTIME", "\u5F53\u524D\u5BBF\u4E3B\u4E0D\u652F\u6301\u751F\u6210 PDF");
|
|
2917
|
+
const ms = budget();
|
|
2918
|
+
return withTimeout(
|
|
2919
|
+
(async () => {
|
|
2920
|
+
try {
|
|
2921
|
+
await load(html, viewport);
|
|
2922
|
+
return await driver.pdf(html, spec);
|
|
2923
|
+
} catch (err) {
|
|
2924
|
+
throw fail(err, "PDF_FAILED", "PDF \u751F\u6210\u5931\u8D25");
|
|
2925
|
+
}
|
|
2926
|
+
})(),
|
|
2927
|
+
ms,
|
|
2928
|
+
"RENDER_TIMEOUT",
|
|
2929
|
+
`PDF \u751F\u6210\u8D85\u8FC7 ${ms}ms`
|
|
2930
|
+
);
|
|
2931
|
+
},
|
|
2932
|
+
async toScreenshot(html, spec, viewport) {
|
|
2933
|
+
if (!driver.screenshot) throw new PrintFailure("UNSUPPORTED_RUNTIME", "\u5F53\u524D\u5BBF\u4E3B\u4E0D\u652F\u6301\u622A\u56FE");
|
|
2934
|
+
const ms = budget();
|
|
2935
|
+
return withTimeout(
|
|
2936
|
+
(async () => {
|
|
2937
|
+
try {
|
|
2938
|
+
await load(html, viewport);
|
|
2939
|
+
return await driver.screenshot(html, spec);
|
|
2940
|
+
} catch (err) {
|
|
2941
|
+
throw fail(err, "SCREENSHOT_FAILED", "\u622A\u56FE\u5931\u8D25");
|
|
2942
|
+
}
|
|
2943
|
+
})(),
|
|
2944
|
+
ms,
|
|
2945
|
+
"RENDER_TIMEOUT",
|
|
2946
|
+
`\u622A\u56FE\u8D85\u8FC7 ${ms}ms`
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2949
|
+
};
|
|
2950
|
+
try {
|
|
2951
|
+
return await fn(session);
|
|
2952
|
+
} finally {
|
|
2953
|
+
try {
|
|
2954
|
+
await driver.close();
|
|
2955
|
+
} catch {
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
// src/print/normalize-print-data.ts
|
|
2963
|
+
var MAX_BATCH_COPIES = 500;
|
|
2964
|
+
function isPlainRecord(v) {
|
|
2965
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2966
|
+
}
|
|
2967
|
+
function normalizePrintData(raw) {
|
|
2968
|
+
if (raw === void 0) return { mode: "single", data: {} };
|
|
2969
|
+
if (!Array.isArray(raw)) return { mode: "single", data: raw };
|
|
2970
|
+
if (raw.length === 0) {
|
|
2971
|
+
throw new Error("\u6279\u91CF\u6253\u5370\u6570\u636E\u5FC5\u987B\u662F\u975E\u7A7A\u5BF9\u8C61\u6570\u7EC4");
|
|
2972
|
+
}
|
|
2973
|
+
if (raw.length > MAX_BATCH_COPIES) {
|
|
2974
|
+
throw new Error(`\u6279\u91CF\u6253\u5370\u6700\u591A\u652F\u6301 ${MAX_BATCH_COPIES} \u4EFD\uFF0C\u5F53\u524D ${raw.length} \u4EFD`);
|
|
2975
|
+
}
|
|
2976
|
+
for (let i = 0; i < raw.length; i++) {
|
|
2977
|
+
if (!isPlainRecord(raw[i])) {
|
|
2978
|
+
throw new Error(`\u6279\u91CF\u6253\u5370\u6570\u636E\u7B2C ${i + 1} \u9879\u5FC5\u987B\u662F\u5BF9\u8C61`);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
return { mode: "batch", dataList: raw };
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
// src/print/batch-compose.ts
|
|
2985
|
+
function composeBatchHtml(copies) {
|
|
2986
|
+
const bound = copies[0].bound;
|
|
2987
|
+
const continuous = isContinuousPaper(bound);
|
|
2988
|
+
const bodyInner = copies.map((copy, i) => {
|
|
2989
|
+
const cls = continuous ? `print-copy print-copy-${i}` : "print-copy";
|
|
2990
|
+
const pages = renderFinalPages(copy.bound, copy.pageLayouts, copy.data, {
|
|
2991
|
+
codeRenderer: copy.codeRenderer,
|
|
2992
|
+
pageHeightMm: copy.derivedHeightMm
|
|
2993
|
+
});
|
|
2994
|
+
return `<section class="${cls}">
|
|
2995
|
+
${pages}
|
|
2996
|
+
</section>`;
|
|
2997
|
+
}).join("\n");
|
|
2998
|
+
const pageCss = continuous ? buildBatchPageCss(bound, copies.map((c) => ({ heightMm: c.derivedHeightMm }))) : `${buildPageCss(bound)}
|
|
2999
|
+
.print-copy:not(:last-child){break-after:page;page-break-after:always;}`;
|
|
3000
|
+
const css = buildFontFaceCss(bound.fonts) + pageCss;
|
|
3001
|
+
return {
|
|
3002
|
+
html: wrapHtmlDocument(
|
|
3003
|
+
css,
|
|
3004
|
+
bodyInner,
|
|
3005
|
+
continuous ? "continuous" : void 0
|
|
3006
|
+
),
|
|
3007
|
+
pageCount: copies.reduce((sum2, c) => sum2 + c.pageLayouts.length, 0),
|
|
3008
|
+
copyPaperMm: copies.map((c) => c.paperMm)
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
// src/print/tiling.ts
|
|
3013
|
+
var TILE_DEFAULTS = {
|
|
3014
|
+
enabled: true,
|
|
3015
|
+
sheetPaperSize: "A4",
|
|
3016
|
+
sheetOrientation: "portrait",
|
|
3017
|
+
sheetMargin: { top: 10, right: 10, bottom: 10, left: 10 },
|
|
3018
|
+
gapX: 2,
|
|
3019
|
+
gapY: 2,
|
|
3020
|
+
columns: 2
|
|
3021
|
+
};
|
|
3022
|
+
var TilingError = class extends Error {
|
|
3023
|
+
constructor(code, message) {
|
|
3024
|
+
super(message);
|
|
3025
|
+
this.name = "TilingError";
|
|
3026
|
+
this.code = code;
|
|
3027
|
+
}
|
|
3028
|
+
};
|
|
3029
|
+
function roundMm(value) {
|
|
3030
|
+
return Math.round(value * 10) / 10;
|
|
3031
|
+
}
|
|
3032
|
+
function normalizeTilingOptions(t) {
|
|
3033
|
+
const raw = t.tiling;
|
|
3034
|
+
return {
|
|
3035
|
+
...TILE_DEFAULTS,
|
|
3036
|
+
...raw,
|
|
3037
|
+
sheetMargin: { ...TILE_DEFAULTS.sheetMargin, ...raw?.sheetMargin ?? {} }
|
|
3038
|
+
};
|
|
3039
|
+
}
|
|
3040
|
+
function resolveSheetMm(t, opts) {
|
|
3041
|
+
const cfg = normalizeTilingOptions(t);
|
|
3042
|
+
const ov = opts?.paperOverride;
|
|
3043
|
+
if (ov && typeof ov.width === "number" && ov.width > 0 && typeof ov.height === "number" && ov.height > 0) {
|
|
3044
|
+
return { width: ov.width, height: ov.height };
|
|
3045
|
+
}
|
|
3046
|
+
if (cfg.sheetPaperSize === "CUSTOM") {
|
|
3047
|
+
return {
|
|
3048
|
+
width: cfg.sheetCustomWidth ?? PAPER_DIMENSIONS.A4.width,
|
|
3049
|
+
height: cfg.sheetCustomHeight ?? PAPER_DIMENSIONS.A4.height
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
const preset = cfg.sheetPaperSize ?? "A4";
|
|
3053
|
+
const base = PAPER_DIMENSIONS[preset] ?? PAPER_DIMENSIONS.A4;
|
|
3054
|
+
return cfg.sheetOrientation === "landscape" ? { width: base.height, height: base.width } : { ...base };
|
|
3055
|
+
}
|
|
3056
|
+
function availableArea(sheet, margin) {
|
|
3057
|
+
return {
|
|
3058
|
+
w: sheet.width - margin.left - margin.right,
|
|
3059
|
+
h: sheet.height - margin.top - margin.bottom
|
|
3060
|
+
};
|
|
3061
|
+
}
|
|
3062
|
+
function calcMaxColumns(availW, labelW, gapX) {
|
|
3063
|
+
return Math.max(0, Math.floor((availW + gapX) / (labelW + gapX)));
|
|
3064
|
+
}
|
|
3065
|
+
function computeTileLayout(t, opts) {
|
|
3066
|
+
const issues = validateTiling(t, opts);
|
|
3067
|
+
if (issues.length) throw new TilingError(issues[0].code, issues[0].message);
|
|
3068
|
+
const cfg = normalizeTilingOptions(t);
|
|
3069
|
+
const sheet = resolveSheetMm(t, opts);
|
|
3070
|
+
const label = getPaperDimensions(t);
|
|
3071
|
+
const avail = availableArea(sheet, cfg.sheetMargin);
|
|
3072
|
+
const rows = Math.floor((avail.h + cfg.gapY) / (label.height + cfg.gapY));
|
|
3073
|
+
return {
|
|
3074
|
+
tile: { width: label.width, height: label.height },
|
|
3075
|
+
sheet,
|
|
3076
|
+
columns: cfg.columns,
|
|
3077
|
+
rows,
|
|
3078
|
+
perSheet: cfg.columns * rows,
|
|
3079
|
+
maxColumns: calcMaxColumns(avail.w, label.width, cfg.gapX),
|
|
3080
|
+
margin: { ...cfg.sheetMargin },
|
|
3081
|
+
gapX: cfg.gapX,
|
|
3082
|
+
gapY: cfg.gapY
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function tilePosition(layout, index) {
|
|
3086
|
+
const slot = index % layout.perSheet;
|
|
3087
|
+
const col = slot % layout.columns;
|
|
3088
|
+
const row = Math.floor(slot / layout.columns);
|
|
3089
|
+
return {
|
|
3090
|
+
left: roundMm(layout.margin.left + col * (layout.tile.width + layout.gapX)),
|
|
3091
|
+
top: roundMm(layout.margin.top + row * (layout.tile.height + layout.gapY))
|
|
3092
|
+
};
|
|
3093
|
+
}
|
|
3094
|
+
function computeMaxColumns(t, opts) {
|
|
3095
|
+
const cfg = normalizeTilingOptions(t);
|
|
3096
|
+
const sheet = resolveSheetMm(t, opts);
|
|
3097
|
+
const label = getPaperDimensions(t);
|
|
3098
|
+
const availW = sheet.width - cfg.sheetMargin.left - cfg.sheetMargin.right;
|
|
3099
|
+
return calcMaxColumns(availW, label.width, cfg.gapX);
|
|
3100
|
+
}
|
|
3101
|
+
function validateTiling(t, opts) {
|
|
3102
|
+
const issues = [];
|
|
3103
|
+
const cfg = normalizeTilingOptions(t);
|
|
3104
|
+
if (isContinuousPaper(t)) {
|
|
3105
|
+
issues.push({
|
|
3106
|
+
code: "CONTINUOUS_UNSUPPORTED",
|
|
3107
|
+
message: "\u8FDE\u7EED\u7EB8\u4E0D\u652F\u6301\u62FC\u7248\u6253\u5370\uFF0C\u8BF7\u5C06\u6A21\u677F\u7EB8\u5F20\u6539\u4E3A\u56FA\u5B9A\u7EB8\u5F20\u6216\u5173\u95ED\u62FC\u7248"
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3110
|
+
const sheetPaperSize = cfg.sheetPaperSize;
|
|
3111
|
+
const sheetContinuous = isContinuousPaperSize(sheetPaperSize ?? "");
|
|
3112
|
+
if (sheetContinuous) {
|
|
3113
|
+
issues.push({ code: "SHEET_CONTINUOUS", message: "\u62FC\u7248\u76EE\u6807\u7EB8\u5F20\u4E0D\u80FD\u662F\u8FDE\u7EED\u7EB8" });
|
|
3114
|
+
}
|
|
3115
|
+
const customSizeInvalid = cfg.sheetPaperSize === "CUSTOM" && !((cfg.sheetCustomWidth ?? 0) > 0 && (cfg.sheetCustomHeight ?? 0) > 0);
|
|
3116
|
+
if (customSizeInvalid) {
|
|
3117
|
+
issues.push({
|
|
3118
|
+
code: "SHEET_SIZE_INVALID",
|
|
3119
|
+
message: "\u62FC\u7248\u81EA\u5B9A\u4E49\u7EB8\u5F20\u5BBD\u9AD8\u5FC5\u987B\u662F\u5927\u4E8E 0 \u7684\u6570\u503C\uFF08mm\uFF09"
|
|
3120
|
+
});
|
|
3121
|
+
}
|
|
3122
|
+
if (customSizeInvalid || sheetContinuous) return issues;
|
|
3123
|
+
const sheet = resolveSheetMm(t, opts);
|
|
3124
|
+
const label = getPaperDimensions(t);
|
|
3125
|
+
const avail = availableArea(sheet, cfg.sheetMargin);
|
|
3126
|
+
const marginLR = roundMm(cfg.sheetMargin.left + cfg.sheetMargin.right);
|
|
3127
|
+
if (!Number.isInteger(cfg.columns) || cfg.columns < 1) {
|
|
3128
|
+
issues.push({ code: "COLUMNS_INVALID", message: "\u62FC\u7248\u5217\u6570\u5FC5\u987B\u662F\u5927\u4E8E 0 \u7684\u6574\u6570" });
|
|
3129
|
+
return issues;
|
|
3130
|
+
}
|
|
3131
|
+
const maxColumns = calcMaxColumns(avail.w, label.width, cfg.gapX);
|
|
3132
|
+
if (cfg.columns > maxColumns) {
|
|
3133
|
+
const needW = roundMm(cfg.columns * label.width + (cfg.columns - 1) * cfg.gapX);
|
|
3134
|
+
issues.push({
|
|
3135
|
+
code: "COLUMNS_OVERFLOW",
|
|
3136
|
+
message: "\u62FC\u7248\u5217\u6570 " + cfg.columns + " \u8D85\u51FA\u7EB8\u9762\u53EF\u7528\u5BBD\u5EA6\uFF1A" + roundMm(sheet.width) + "mm \u2212 \u5DE6\u53F3\u7559\u767D " + marginLR + "mm = " + roundMm(avail.w) + "mm\uFF0C\u6700\u591A\u53EF\u653E " + maxColumns + " \u5217\uFF1B\u5F53\u524D " + cfg.columns + " \u5217 " + label.width + "mm \u6807\u7B7E\u542B\u95F4\u8DDD\u9700\u8981 " + needW + "mm"
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
if (Math.floor((avail.h + cfg.gapY) / (label.height + cfg.gapY)) < 1) {
|
|
3140
|
+
issues.push({
|
|
3141
|
+
code: "LABEL_TOO_TALL",
|
|
3142
|
+
message: "\u6807\u7B7E\u9AD8\u5EA6 " + label.height + "mm \u8D85\u51FA\u7EB8\u9762\u53EF\u7528\u9AD8\u5EA6 " + roundMm(avail.h) + "mm\uFF0C\u62FC\u7248\u6BCF\u5F20 0 \u884C\uFF1B\u8BF7\u7F29\u5C0F\u6807\u7B7E\u9AD8\u5EA6\u6216\u6539\u7528\u6A2A\u5411\u7EB8"
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3145
|
+
return issues;
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
// src/print/tile-compose.ts
|
|
3149
|
+
function composeTiledHtml(input) {
|
|
3150
|
+
const { copies, layout } = input;
|
|
3151
|
+
const bound = copies[0].bound;
|
|
3152
|
+
const sheets = [];
|
|
3153
|
+
for (let start = 0; start < copies.length; start += layout.perSheet) {
|
|
3154
|
+
const tiles = copies.slice(start, start + layout.perSheet).map((copy, i) => {
|
|
3155
|
+
const pos = tilePosition(layout, i);
|
|
3156
|
+
const page = renderFinalPages(copy.bound, copy.pageLayouts, copy.data, {
|
|
3157
|
+
codeRenderer: copy.codeRenderer
|
|
3158
|
+
});
|
|
3159
|
+
return `<div class="print-tile" style="left:${pos.left}mm;top:${pos.top}mm">
|
|
3160
|
+
${page}
|
|
3161
|
+
</div>`;
|
|
3162
|
+
}).join("\n");
|
|
3163
|
+
sheets.push(`<section class="print-sheet">
|
|
3164
|
+
${tiles}
|
|
3165
|
+
</section>`);
|
|
3166
|
+
}
|
|
3167
|
+
const css = buildFontFaceCss(bound.fonts) + buildPageCss(bound) + "\n" + buildSheetPageCss(layout);
|
|
3168
|
+
return {
|
|
3169
|
+
html: wrapHtmlDocument(css, sheets.join("\n")),
|
|
3170
|
+
sheetCount: sheets.length,
|
|
3171
|
+
perSheet: layout.perSheet
|
|
3172
|
+
};
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
// src/print/multi-template.ts
|
|
3176
|
+
function pageLabel(p, index) {
|
|
3177
|
+
return p.name ? `\u7B2C ${index + 1} \u9875\u300C${p.name}\u300D` : `\u7B2C ${index + 1} \u9875`;
|
|
3178
|
+
}
|
|
3179
|
+
function normalizeTemplate(templateJson) {
|
|
3180
|
+
const pages = isMultiPageTemplate(templateJson) ? templateJson.pages : [templateJson];
|
|
3181
|
+
if (pages.length === 0) {
|
|
3182
|
+
throw new Error("\u591A\u9875\u9762\u6A21\u677F\u81F3\u5C11\u9700\u8981\u4E00\u9875");
|
|
3183
|
+
}
|
|
3184
|
+
if (pages.length === 1) return pages;
|
|
3185
|
+
const firstPaper = getPaperDimensions(pages[0]);
|
|
3186
|
+
pages.forEach((p, i) => {
|
|
3187
|
+
if (isContinuousPaper(p)) {
|
|
3188
|
+
throw new Error(`\u591A\u9875\u9762\u6A21\u677F\u4E0D\u652F\u6301\u8FDE\u7EED\u7EB8\uFF08${pageLabel(p, i)}\uFF09`);
|
|
3189
|
+
}
|
|
3190
|
+
if (p.tiling?.enabled === true) {
|
|
3191
|
+
throw new Error(`\u591A\u9875\u9762\u6A21\u677F\u4E0D\u652F\u6301\u6807\u7B7E\u62FC\u7248\uFF08${pageLabel(p, i)}\uFF09`);
|
|
3192
|
+
}
|
|
3193
|
+
const d = getPaperDimensions(p);
|
|
3194
|
+
if (d.width !== firstPaper.width || d.height !== firstPaper.height) {
|
|
3195
|
+
throw new Error(
|
|
3196
|
+
`\u591A\u9875\u9762\u6A21\u677F\u5404\u9875\u7EB8\u5F20\u5C3A\u5BF8\u5FC5\u987B\u4E00\u81F4\uFF08${pageLabel(p, i)} ${d.width}\xD7${d.height}mm \u4E0E\u9996\u9875 ${firstPaper.width}\xD7${firstPaper.height}mm \u4E0D\u540C\uFF09`
|
|
3197
|
+
);
|
|
3198
|
+
}
|
|
3199
|
+
});
|
|
3200
|
+
return pages;
|
|
3201
|
+
}
|
|
3202
|
+
function isMultiPageTemplate(templateJson) {
|
|
3203
|
+
return Array.isArray(templateJson.pages);
|
|
3204
|
+
}
|
|
3205
|
+
function mergeFontDeclarations(pages) {
|
|
3206
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3207
|
+
const merged = [];
|
|
3208
|
+
for (const p of pages) {
|
|
3209
|
+
for (const f of p.fonts ?? []) {
|
|
3210
|
+
const key = f.family;
|
|
3211
|
+
if (seen.has(key)) continue;
|
|
3212
|
+
seen.add(key);
|
|
3213
|
+
merged.push(f);
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
return merged;
|
|
3217
|
+
}
|
|
3218
|
+
function composeMultiPageDocument(copies) {
|
|
3219
|
+
if (copies.length === 0) {
|
|
3220
|
+
throw new Error("\u591A\u9875\u9762\u6A21\u677F\u81F3\u5C11\u9700\u8981\u4E00\u4EFD\u6570\u636E");
|
|
3221
|
+
}
|
|
3222
|
+
const templates = copies[0].boundPages;
|
|
3223
|
+
const css = buildFontFaceCss(mergeFontDeclarations(templates)) + [
|
|
3224
|
+
buildPageRuleCss(templates[0]),
|
|
3225
|
+
buildBasePageCss(),
|
|
3226
|
+
...templates.map((t, i) => buildPageGeometryCss(t, `.mt-${i}`)),
|
|
3227
|
+
...copies.length > 1 ? [COPY_BREAK_CSS] : []
|
|
3228
|
+
].join("\n\n");
|
|
3229
|
+
const bodyInner = copies.map((copy) => {
|
|
3230
|
+
const totalPages = copy.layoutsPerPage.reduce((s, ls) => s + ls.length, 0);
|
|
3231
|
+
let offset = 0;
|
|
3232
|
+
const fragments = copy.layoutsPerPage.map((layouts, i) => {
|
|
3233
|
+
const html = renderFinalPages(
|
|
3234
|
+
copy.boundPages[i],
|
|
3235
|
+
layouts,
|
|
3236
|
+
copy.data,
|
|
3237
|
+
{ codeRenderer: copy.codeRenderers?.[i] },
|
|
3238
|
+
{
|
|
3239
|
+
pageOffset: offset,
|
|
3240
|
+
totalPages,
|
|
3241
|
+
pageClass: `mt-${i}`
|
|
3242
|
+
}
|
|
3243
|
+
);
|
|
3244
|
+
offset += layouts.length;
|
|
3245
|
+
return html;
|
|
3246
|
+
});
|
|
3247
|
+
const pages = fragments.join("\n");
|
|
3248
|
+
return copies.length > 1 ? `<section class="print-copy">
|
|
3249
|
+
${pages}
|
|
3250
|
+
</section>` : pages;
|
|
3251
|
+
}).join("\n");
|
|
3252
|
+
const pageCount = copies.reduce(
|
|
3253
|
+
(sum2, c) => sum2 + c.layoutsPerPage.reduce((s, ls) => s + ls.length, 0),
|
|
3254
|
+
0
|
|
3255
|
+
);
|
|
3256
|
+
const pageLayouts = [];
|
|
3257
|
+
let g = 0;
|
|
3258
|
+
for (const c of copies) {
|
|
3259
|
+
for (const ls of c.layoutsPerPage) {
|
|
3260
|
+
for (const p of ls) pageLayouts.push({ ...p, pageIndex: g++ });
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
return {
|
|
3264
|
+
html: wrapHtmlDocument(css, bodyInner),
|
|
3265
|
+
pageCount,
|
|
3266
|
+
pageLayouts
|
|
3267
|
+
};
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
// src/print/pipeline.ts
|
|
3271
|
+
async function prepareDocument(job, runtime) {
|
|
3272
|
+
return runtime.withSession(job, (session) => prepareWithSession(job, session));
|
|
3273
|
+
}
|
|
3274
|
+
async function renderPdf(job, runtime) {
|
|
3275
|
+
return runtime.withSession(job, async (session) => {
|
|
3276
|
+
const prepared = await prepareWithSession(job, session);
|
|
3277
|
+
const viewport = paperViewportPx(prepared.paperMm);
|
|
3278
|
+
const pdf = await session.toPdf(prepared.html, buildPdfTargetSpec(prepared.paperMm), viewport);
|
|
3279
|
+
return { pdf, prepared };
|
|
3280
|
+
});
|
|
3281
|
+
}
|
|
3282
|
+
async function renderScreenshot(job, runtime) {
|
|
3283
|
+
return runtime.withSession(job, async (session) => {
|
|
3284
|
+
const pageTemplates = normalizeTemplate(job.templateJson);
|
|
3285
|
+
if (pageTemplates.length > 1) {
|
|
3286
|
+
const normalized2 = normalizePrintData(job.printData);
|
|
3287
|
+
const data2 = normalized2.mode === "batch" ? normalized2.dataList[0] : normalized2.data;
|
|
3288
|
+
const copy = await prepareMultiCopy(job, session, data2);
|
|
3289
|
+
const doc = composeMultiPageDocument([copy]);
|
|
3290
|
+
const viewport2 = paperViewportPx(getPaperDimensions(pageTemplates[0]));
|
|
3291
|
+
return session.toScreenshot(doc.html, buildScreenshotTargetSpec(), viewport2);
|
|
3292
|
+
}
|
|
3293
|
+
const singleJob = pageTemplates[0] !== job.templateJson ? { ...job, templateJson: pageTemplates[0] } : job;
|
|
3294
|
+
const normalized = normalizePrintData(singleJob.printData);
|
|
3295
|
+
const data = normalized.mode === "batch" ? normalized.dataList[0] : normalized.data;
|
|
3296
|
+
const bound = bindData(singleJob.templateJson, data, singleJob.baseUrl, singleJob.fontBaseUrl);
|
|
3297
|
+
const built = await buildHtmlWithCodes({
|
|
3298
|
+
bound,
|
|
3299
|
+
job: singleJob,
|
|
3300
|
+
session,
|
|
3301
|
+
data,
|
|
3302
|
+
pageLayouts: [],
|
|
3303
|
+
isMeasurementPass: true
|
|
3304
|
+
});
|
|
3305
|
+
const viewport = paperViewportPx(getPaperDimensions(bound));
|
|
3306
|
+
return session.toScreenshot(built.html, buildScreenshotTargetSpec(), viewport);
|
|
3307
|
+
});
|
|
3308
|
+
}
|
|
3309
|
+
async function prepareWithSession(job, session) {
|
|
3310
|
+
const pageTemplates = normalizeTemplate(job.templateJson);
|
|
3311
|
+
if (pageTemplates.length > 1) {
|
|
3312
|
+
const normalized2 = normalizePrintData(job.printData);
|
|
3313
|
+
const rows = normalized2.mode === "batch" ? normalized2.dataList : [normalized2.data];
|
|
3314
|
+
const copies2 = [];
|
|
3315
|
+
for (let i = 0; i < rows.length; i++) {
|
|
3316
|
+
try {
|
|
3317
|
+
copies2.push(await prepareMultiCopy(job, session, rows[i]));
|
|
3318
|
+
} catch (err) {
|
|
3319
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
3320
|
+
throw new Error(`\u7B2C ${i + 1} \u4EFD\u6E32\u67D3\u5931\u8D25\uFF1A${reason}`);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
const doc = composeMultiPageDocument(copies2);
|
|
3324
|
+
return {
|
|
3325
|
+
html: doc.html,
|
|
3326
|
+
pageCount: doc.pageCount,
|
|
3327
|
+
paperMm: getOutputPaperDimensions(pageTemplates[0]),
|
|
3328
|
+
continuous: false,
|
|
3329
|
+
heightSource: "config",
|
|
3330
|
+
pageLayouts: doc.pageLayouts,
|
|
3331
|
+
copies: copies2.length
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
const singleJob = pageTemplates[0] !== job.templateJson ? { ...job, templateJson: pageTemplates[0] } : job;
|
|
3335
|
+
const template = pageTemplates[0];
|
|
3336
|
+
const normalized = normalizePrintData(singleJob.printData);
|
|
3337
|
+
if (normalized.mode === "single") {
|
|
3338
|
+
const single = await prepareSingleWithSession(singleJob, session, normalized.data);
|
|
3339
|
+
if (template.tiling?.enabled === true) {
|
|
3340
|
+
return composeTiledPrepared(singleJob, [{
|
|
3341
|
+
bound: single.bound,
|
|
3342
|
+
pageLayouts: single.pageLayouts,
|
|
3343
|
+
data: normalized.data,
|
|
3344
|
+
codeRenderer: single.codeRenderer,
|
|
3345
|
+
derivedHeightMm: single.derivedHeightMm,
|
|
3346
|
+
paperMm: single.paperMm,
|
|
3347
|
+
heightSource: single.heightSource
|
|
3348
|
+
}]);
|
|
3349
|
+
}
|
|
3350
|
+
return toPreparedDocument(single);
|
|
3351
|
+
}
|
|
3352
|
+
const copies = [];
|
|
3353
|
+
for (let i = 0; i < normalized.dataList.length; i++) {
|
|
3354
|
+
try {
|
|
3355
|
+
const single = await prepareSingleWithSession(singleJob, session, normalized.dataList[i]);
|
|
3356
|
+
copies.push({
|
|
3357
|
+
bound: single.bound,
|
|
3358
|
+
pageLayouts: single.pageLayouts,
|
|
3359
|
+
data: normalized.dataList[i],
|
|
3360
|
+
codeRenderer: single.codeRenderer,
|
|
3361
|
+
derivedHeightMm: single.derivedHeightMm,
|
|
3362
|
+
paperMm: single.paperMm,
|
|
3363
|
+
heightSource: single.heightSource
|
|
3364
|
+
});
|
|
3365
|
+
} catch (err) {
|
|
3366
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
3367
|
+
throw new Error(`\u7B2C ${i + 1} \u4EFD\u6E32\u67D3\u5931\u8D25\uFF1A${reason}`);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
if (template.tiling?.enabled === true) {
|
|
3371
|
+
return composeTiledPrepared(singleJob, copies);
|
|
3372
|
+
}
|
|
3373
|
+
const merged = composeBatchHtml(copies);
|
|
3374
|
+
return {
|
|
3375
|
+
html: merged.html,
|
|
3376
|
+
pageCount: merged.pageCount,
|
|
3377
|
+
paperMm: copies[0].paperMm,
|
|
3378
|
+
continuous: isContinuousPaper(copies[0].bound),
|
|
3379
|
+
// 同模板同参数各份来源必然一致;不能用 derivedHeightMm 是否存在判断——
|
|
3380
|
+
// 连续纸逃生门时该字段有值但来源是 config
|
|
3381
|
+
heightSource: copies[0].heightSource,
|
|
3382
|
+
// 各份 pageIndex 均从 0 开始,批量拼接后该字段仅作调试用途
|
|
3383
|
+
pageLayouts: copies.flatMap((c) => c.pageLayouts),
|
|
3384
|
+
copies: copies.length,
|
|
3385
|
+
copyPaperMm: merged.copyPaperMm
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
function toPreparedDocument(s) {
|
|
3389
|
+
return {
|
|
3390
|
+
html: s.html,
|
|
3391
|
+
pageCount: s.pageCount,
|
|
3392
|
+
paperMm: s.paperMm,
|
|
3393
|
+
continuous: s.continuous,
|
|
3394
|
+
heightSource: s.heightSource,
|
|
3395
|
+
pageLayouts: s.pageLayouts,
|
|
3396
|
+
copies: 1
|
|
3397
|
+
};
|
|
3398
|
+
}
|
|
3399
|
+
function composeTiledPrepared(job, copies) {
|
|
3400
|
+
const bound = copies[0].bound;
|
|
3401
|
+
const layout = computeTileLayout(bound, { paperOverride: job.paperOverride });
|
|
3402
|
+
copies.forEach((copy, i) => {
|
|
3403
|
+
const overflow = copy.pageLayouts[0]?.overflow === true;
|
|
3404
|
+
if (copy.pageLayouts.length !== 1 || overflow) {
|
|
3405
|
+
const detail = overflow ? "\u5185\u5BB9\u8D85\u51FA\u7EB8\u5F20\u9AD8\u5EA6" : `\u6E32\u67D3\u51FA ${copy.pageLayouts.length} \u9875`;
|
|
3406
|
+
throw new Error(
|
|
3407
|
+
`\u62FC\u7248\u8981\u6C42\u6BCF\u4EFD\u6807\u7B7E\u6070\u597D 1 \u9875\uFF0C\u7B2C ${i + 1} \u4EFD${detail}\uFF1B\u8BF7\u7F29\u5C0F\u5185\u5BB9\u6216\u8C03\u6574\u6807\u7B7E\u7EB8\u5F20\u9AD8\u5EA6`
|
|
3408
|
+
);
|
|
3409
|
+
}
|
|
3410
|
+
});
|
|
3411
|
+
const tiled = composeTiledHtml({
|
|
3412
|
+
copies: copies.map((c) => ({
|
|
3413
|
+
bound: c.bound,
|
|
3414
|
+
pageLayouts: c.pageLayouts,
|
|
3415
|
+
data: c.data,
|
|
3416
|
+
codeRenderer: c.codeRenderer
|
|
3417
|
+
})),
|
|
3418
|
+
layout
|
|
3419
|
+
});
|
|
3420
|
+
return {
|
|
3421
|
+
html: tiled.html,
|
|
3422
|
+
// 语义变更:pageCount = 实际输出张数(客户端任务历史、预览「共 N 页」都按此口径)
|
|
3423
|
+
pageCount: tiled.sheetCount,
|
|
3424
|
+
paperMm: { width: layout.sheet.width, height: layout.sheet.height },
|
|
3425
|
+
continuous: false,
|
|
3426
|
+
heightSource: "config",
|
|
3427
|
+
// 调试用途;各份 pageIndex 均从 0 开始
|
|
3428
|
+
pageLayouts: copies.flatMap((c) => c.pageLayouts),
|
|
3429
|
+
copies: copies.length
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
async function prepareSingleWithSession(job, session, data) {
|
|
3433
|
+
const bound = bindData(job.templateJson, data, job.baseUrl, job.fontBaseUrl);
|
|
3434
|
+
const continuous = isContinuousPaper(bound);
|
|
3435
|
+
const designPaper = getPaperDimensions(bound);
|
|
3436
|
+
const viewport = paperViewportPx(designPaper);
|
|
3437
|
+
const heightEscape = escapeHeightMm({ paperHeightMm: job.paperHeightMm, override: job.paperOverride });
|
|
3438
|
+
const measurement = await buildHtmlWithCodes({
|
|
3439
|
+
bound,
|
|
3440
|
+
job,
|
|
3441
|
+
session,
|
|
3442
|
+
data,
|
|
3443
|
+
pageLayouts: [],
|
|
3444
|
+
isMeasurementPass: true
|
|
3445
|
+
});
|
|
3446
|
+
const measurements = await session.measure(measurement.html, viewport);
|
|
3447
|
+
applyTextFitSizes(bound, measurements.fits);
|
|
3448
|
+
const pageLayouts = paginate(bound, normalizeMeasurements(measurements.measurements, bound));
|
|
3449
|
+
const finalBuild = await buildHtmlWithCodes({
|
|
3450
|
+
bound,
|
|
3451
|
+
job,
|
|
3452
|
+
session,
|
|
3453
|
+
data,
|
|
3454
|
+
pageLayouts,
|
|
3455
|
+
isMeasurementPass: false,
|
|
3456
|
+
baseMap: measurement.map
|
|
3457
|
+
});
|
|
3458
|
+
let html = finalBuild.html;
|
|
3459
|
+
let derivedHeightMm;
|
|
3460
|
+
if (continuous) {
|
|
3461
|
+
if (heightEscape && heightEscape > 0) {
|
|
3462
|
+
derivedHeightMm = heightEscape;
|
|
3463
|
+
} else {
|
|
3464
|
+
const bottomPx = await session.probeContentBottom(html, viewport);
|
|
3465
|
+
derivedHeightMm = composeContinuousHeight(bound, pxToMm(bottomPx));
|
|
3466
|
+
}
|
|
3467
|
+
html = generateHtml(bound, pageLayouts, data, {
|
|
3468
|
+
codeRenderer: finalBuild.codeRenderer,
|
|
3469
|
+
pageHeightMm: derivedHeightMm
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
const overrideForPaper = continuous && heightEscape ? { ...job.paperOverride, height: heightEscape } : job.paperOverride;
|
|
3473
|
+
const outputPaper = getOutputPaperDimensions(bound);
|
|
3474
|
+
const { paperMm, heightSource } = resolvePaperMm({
|
|
3475
|
+
paperMm: { width: outputPaper.width, height: derivedHeightMm ?? outputPaper.height },
|
|
3476
|
+
continuous,
|
|
3477
|
+
override: overrideForPaper
|
|
3478
|
+
});
|
|
3479
|
+
return {
|
|
3480
|
+
html,
|
|
3481
|
+
pageCount: pageLayouts.length,
|
|
3482
|
+
paperMm,
|
|
3483
|
+
continuous,
|
|
3484
|
+
heightSource,
|
|
3485
|
+
pageLayouts,
|
|
3486
|
+
copies: 1,
|
|
3487
|
+
bound,
|
|
3488
|
+
codeRenderer: finalBuild.codeRenderer,
|
|
3489
|
+
derivedHeightMm
|
|
3490
|
+
};
|
|
3491
|
+
}
|
|
3492
|
+
async function prepareMultiCopy(job, session, data) {
|
|
3493
|
+
const templates = normalizeTemplate(job.templateJson);
|
|
3494
|
+
const viewport = paperViewportPx(getPaperDimensions(templates[0]));
|
|
3495
|
+
const boundPages = [];
|
|
3496
|
+
const layoutsPerPage = [];
|
|
3497
|
+
const codeRenderers = [];
|
|
3498
|
+
for (const t of templates) {
|
|
3499
|
+
const bound = bindData(t, data, job.baseUrl, job.fontBaseUrl);
|
|
3500
|
+
const measurement = await buildHtmlWithCodes({ bound, job, session, data, pageLayouts: [], isMeasurementPass: true });
|
|
3501
|
+
const measurements = await session.measure(measurement.html, viewport);
|
|
3502
|
+
applyTextFitSizes(bound, measurements.fits);
|
|
3503
|
+
const layouts = paginate(bound, normalizeMeasurements(measurements.measurements, bound));
|
|
3504
|
+
const final = await buildHtmlWithCodes({ bound, job, session, data, pageLayouts: layouts, isMeasurementPass: false, baseMap: measurement.map });
|
|
3505
|
+
boundPages.push(bound);
|
|
3506
|
+
layoutsPerPage.push(layouts);
|
|
3507
|
+
codeRenderers.push(final.codeRenderer);
|
|
3508
|
+
}
|
|
3509
|
+
return { boundPages, layoutsPerPage, data, codeRenderers };
|
|
3510
|
+
}
|
|
3511
|
+
async function buildHtmlWithCodes(input) {
|
|
3512
|
+
const baseMap = input.baseMap ?? /* @__PURE__ */ new Map();
|
|
3513
|
+
if (input.job.codeRenderer) {
|
|
3514
|
+
const html2 = generateHtml(input.bound, input.pageLayouts, input.data, {
|
|
3515
|
+
isMeasurementPass: input.isMeasurementPass,
|
|
3516
|
+
codeRenderer: input.job.codeRenderer
|
|
3517
|
+
});
|
|
3518
|
+
return { html: html2, codeRenderer: input.job.codeRenderer, map: baseMap };
|
|
3519
|
+
}
|
|
3520
|
+
const collector = createCollectingCodeRenderer(baseMap);
|
|
3521
|
+
const draft = generateHtml(input.bound, input.pageLayouts, input.data, {
|
|
3522
|
+
isMeasurementPass: input.isMeasurementPass,
|
|
3523
|
+
codeRenderer: collector.renderer
|
|
3524
|
+
});
|
|
3525
|
+
const extra = collector.takeSpecs();
|
|
3526
|
+
const rendered = extra.length > 0 ? await input.session.renderCodes(extra) : /* @__PURE__ */ new Map();
|
|
3527
|
+
const map = mergeCodeMaps(baseMap, rendered);
|
|
3528
|
+
const codeRenderer = map.size > 0 ? createMapCodeRenderer(map) : void 0;
|
|
3529
|
+
if (extra.length === 0) return { html: draft, codeRenderer, map };
|
|
3530
|
+
const html = generateHtml(input.bound, input.pageLayouts, input.data, {
|
|
3531
|
+
isMeasurementPass: input.isMeasurementPass,
|
|
3532
|
+
codeRenderer
|
|
3533
|
+
});
|
|
3534
|
+
return { html, codeRenderer, map };
|
|
3535
|
+
}
|
|
3536
|
+
|
|
1802
3537
|
// src/index.ts
|
|
1803
3538
|
var TemplateEngine = class {
|
|
1804
3539
|
constructor(options) {
|
|
@@ -1821,36 +3556,116 @@ var TemplateEngine = class {
|
|
|
1821
3556
|
};
|
|
1822
3557
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1823
3558
|
0 && (module.exports = {
|
|
3559
|
+
DEFAULT_READINESS_MS,
|
|
3560
|
+
DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
|
|
3561
|
+
DEFAULT_TIMEOUT_MS,
|
|
3562
|
+
EXECUTOR_TARGETS,
|
|
3563
|
+
FALLBACK_FONT_STACK,
|
|
3564
|
+
MAX_BATCH_COPIES,
|
|
3565
|
+
MICROMETERS_PER_INCH,
|
|
3566
|
+
MICROMETERS_PER_MM,
|
|
3567
|
+
MIN_CONTINUOUS_HEIGHT_MM,
|
|
3568
|
+
MIN_SHRINK_FONT_SIZE_PT,
|
|
3569
|
+
MM_PER_INCH,
|
|
3570
|
+
MM_PER_PX,
|
|
1824
3571
|
PAPER_DIMENSIONS,
|
|
3572
|
+
PX_PER_MM,
|
|
3573
|
+
PrintFailure,
|
|
3574
|
+
TILE_DEFAULTS,
|
|
1825
3575
|
TemplateEngine,
|
|
3576
|
+
TilingError,
|
|
3577
|
+
WATERMARK_DEFAULTS,
|
|
3578
|
+
WATERMARK_DENSITY_PRESETS,
|
|
3579
|
+
applyTextFitSizes,
|
|
1826
3580
|
avg,
|
|
1827
3581
|
bindData,
|
|
3582
|
+
buildBasePageCss,
|
|
3583
|
+
buildFontFaceCss,
|
|
1828
3584
|
buildPageCss,
|
|
3585
|
+
buildPageGeometryCss,
|
|
3586
|
+
buildPageRuleCss,
|
|
3587
|
+
buildPdfTargetSpec,
|
|
3588
|
+
buildScreenshotTargetSpec,
|
|
3589
|
+
cellFitCapMm,
|
|
3590
|
+
cellFitKey,
|
|
3591
|
+
codeSpecKey,
|
|
1829
3592
|
compileTemplate,
|
|
3593
|
+
composeBatchHtml,
|
|
3594
|
+
composeContinuousHeight,
|
|
3595
|
+
composeMultiPageDocument,
|
|
3596
|
+
composeTiledHtml,
|
|
3597
|
+
computeMaxColumns,
|
|
3598
|
+
computeTileLayout,
|
|
1830
3599
|
count,
|
|
3600
|
+
createCollectingCodeRenderer,
|
|
3601
|
+
createDomHostRuntime,
|
|
3602
|
+
createMapCodeRenderer,
|
|
1831
3603
|
elementPositionStyle,
|
|
3604
|
+
escapeHeightMm,
|
|
3605
|
+
escapeInlineStyleValue,
|
|
1832
3606
|
evaluate,
|
|
1833
3607
|
evaluateTemplate,
|
|
3608
|
+
floorFontSize,
|
|
1834
3609
|
formatDate,
|
|
1835
3610
|
formatMoney,
|
|
3611
|
+
formatTimestamp,
|
|
1836
3612
|
generateHtml,
|
|
1837
3613
|
getByPath,
|
|
1838
3614
|
getPaperDimensions,
|
|
1839
3615
|
ifFn,
|
|
1840
3616
|
injectSystemVariables,
|
|
3617
|
+
isContinuousPaper,
|
|
3618
|
+
isContinuousPaperSize,
|
|
3619
|
+
isMultiPageTemplate,
|
|
3620
|
+
isWatermarkVisible,
|
|
1841
3621
|
max,
|
|
3622
|
+
mergeCodeMaps,
|
|
3623
|
+
mergeFontDeclarations,
|
|
3624
|
+
micrometersToMillimeters,
|
|
3625
|
+
millimetersToInches,
|
|
3626
|
+
millimetersToMicrometers,
|
|
1842
3627
|
min,
|
|
1843
3628
|
mm,
|
|
3629
|
+
mmToPx,
|
|
3630
|
+
normalizeMeasurements,
|
|
3631
|
+
normalizePrintData,
|
|
3632
|
+
normalizeTemplate,
|
|
3633
|
+
normalizeTilingOptions,
|
|
1844
3634
|
paginate,
|
|
3635
|
+
paperViewportPx,
|
|
1845
3636
|
parse,
|
|
3637
|
+
parseCellFitKey,
|
|
1846
3638
|
parseTemplate,
|
|
3639
|
+
prepareDocument,
|
|
3640
|
+
pxToMm,
|
|
3641
|
+
renderPdf,
|
|
3642
|
+
renderScreenshot,
|
|
1847
3643
|
renderTemplate,
|
|
3644
|
+
renderWatermarkLayerHtml,
|
|
3645
|
+
renderWatermarkTileSvg,
|
|
3646
|
+
resolveCellTextFit,
|
|
3647
|
+
resolveElementTextFit,
|
|
3648
|
+
resolvePaperMm,
|
|
3649
|
+
resolveSheetMm,
|
|
3650
|
+
resolveShrinkMinFontSize,
|
|
3651
|
+
resolveSystemVariables,
|
|
3652
|
+
resolveWatermarkLayout,
|
|
3653
|
+
resolveWatermarkText,
|
|
3654
|
+
roundFontSize,
|
|
3655
|
+
roundMm,
|
|
1848
3656
|
safeEval,
|
|
1849
3657
|
setPageIndex,
|
|
1850
3658
|
setTotalPages,
|
|
1851
3659
|
sum,
|
|
1852
3660
|
systemVars,
|
|
1853
3661
|
tableDesignBottom,
|
|
3662
|
+
tilePosition,
|
|
3663
|
+
toElectronPrintToPdfOptions,
|
|
3664
|
+
toFontFamilyStack,
|
|
3665
|
+
toPlaywrightPdfOptions,
|
|
3666
|
+
toPrintFailure,
|
|
1854
3667
|
toUpperCaseAmount,
|
|
1855
|
-
tokenize
|
|
3668
|
+
tokenize,
|
|
3669
|
+
validateTiling,
|
|
3670
|
+
withTimeout
|
|
1856
3671
|
});
|