@agile-team/mach-report 0.5.0 → 0.7.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.
Files changed (73) hide show
  1. package/dist/ReportPreview-CrVeTKu1.cjs +6 -0
  2. package/dist/ReportPreview-DgsOdO4y.js +559 -0
  3. package/dist/_commonjsHelpers-DKOUU3wS.cjs +1 -0
  4. package/dist/_commonjsHelpers-DaMA6jEr.js +8 -0
  5. package/dist/builder/template-builder.d.ts +53 -0
  6. package/dist/compat/jh4j-template.d.ts +12 -0
  7. package/dist/defaults.d.ts +27 -0
  8. package/dist/index.cjs +6 -1663
  9. package/dist/index.d.cts +13 -344
  10. package/dist/index.d.ts +13 -344
  11. package/dist/index.js +744 -1415
  12. package/dist/layout/paginate.d.ts +51 -0
  13. package/dist/layout/textwrap.d.ts +36 -0
  14. package/dist/manager/api.d.ts +45 -0
  15. package/dist/manager/index.d.ts +2 -0
  16. package/dist/manager/types.d.ts +50 -0
  17. package/dist/manager.cjs +1 -122
  18. package/dist/manager.d.cts +5 -97
  19. package/dist/manager.d.ts +5 -97
  20. package/dist/manager.js +66 -81
  21. package/dist/pdf/font-loader.d.ts +5 -0
  22. package/dist/pdf/index.d.ts +2 -0
  23. package/dist/pdf/render-pdf.d.ts +25 -0
  24. package/dist/pdf.cjs +84 -52530
  25. package/dist/pdf.d.cts +4 -31
  26. package/dist/pdf.d.ts +4 -31
  27. package/dist/pdf.js +22843 -39218
  28. package/dist/plugin-Cl-IqCqx.cjs +1 -0
  29. package/dist/plugin-Dp3kKWiQ.js +92 -0
  30. package/dist/render/canvas.d.ts +61 -0
  31. package/dist/render/dom.d.ts +10 -0
  32. package/dist/render/grid-geometry.d.ts +41 -0
  33. package/dist/render/style.d.ts +33 -0
  34. package/dist/render/window.d.ts +23 -0
  35. package/dist/schema/render-plan.d.ts +96 -0
  36. package/dist/schema/validate.d.ts +15 -0
  37. package/dist/sql/ast-check.d.ts +14 -0
  38. package/dist/sql/compile.d.ts +31 -0
  39. package/dist/sql/expr.d.ts +21 -0
  40. package/dist/sql/index.d.ts +4 -0
  41. package/dist/sql/tokenizer.d.ts +25 -0
  42. package/dist/sql.cjs +68 -45207
  43. package/dist/sql.d.cts +3 -93
  44. package/dist/sql.d.ts +3 -93
  45. package/dist/sql.js +37213 -41613
  46. package/dist/style-B3vxGDZd.cjs +3 -0
  47. package/dist/style-B7Xfo5I-.js +255 -0
  48. package/dist/style.css +1 -0
  49. package/dist/units.d.ts +11 -0
  50. package/dist/vue/ReportPreview.d.ts +165 -0
  51. package/dist/vue/ReportToolbar.d.ts +25 -0
  52. package/dist/vue/adapters.d.ts +40 -0
  53. package/dist/vue/async.d.cts +275 -0
  54. package/dist/vue/async.d.ts +275 -0
  55. package/dist/vue/composables/usePageWindow.d.ts +28 -0
  56. package/dist/vue/composables/usePrintExport.d.ts +19 -0
  57. package/dist/vue/composables/useZoom.d.ts +15 -0
  58. package/dist/vue/config.d.ts +79 -0
  59. package/dist/vue/controller.d.ts +24 -0
  60. package/dist/vue/errors.d.ts +16 -0
  61. package/dist/vue/index.d.cts +13 -0
  62. package/dist/vue/index.d.ts +13 -0
  63. package/dist/vue/injection-keys.d.ts +14 -0
  64. package/dist/vue/local-adapter.d.ts +12 -0
  65. package/dist/vue/pdf-exporter.d.ts +13 -0
  66. package/dist/vue/plugin.d.ts +294 -0
  67. package/dist/vue-async.cjs +1 -0
  68. package/dist/vue-async.js +17 -0
  69. package/dist/vue.cjs +1 -0
  70. package/dist/vue.js +53 -0
  71. package/package.json +44 -6
  72. package/dist/textwrap-DWzM7pt1.d.cts +0 -135
  73. package/dist/textwrap-DWzM7pt1.d.ts +0 -135
package/dist/index.js CHANGED
@@ -1,61 +1,6 @@
1
- // src/defaults.ts
2
- var LINE_HEIGHT = 1.35;
3
- var DEFAULT_FONT_PT = 10.5;
4
- var DEFAULT_BORDER_PT = 0.75;
5
- var DEFAULT_STROKE_COLOR = "#333333";
6
- var DEFAULT_TEXT_COLOR = "#000000";
7
- var SCHEMA_VERSION_MACH = "1.0.0-mach";
8
- var SCHEMA_VERSION_LOCAL = "mach-local";
9
- var SCHEMA_VERSION_JH4J = "jh4j-compatible";
10
-
11
- // src/units.ts
12
- var MM_PER_INCH = 25.4;
13
- var CSS_DPI = 96;
14
- function mmToPxFactor(dpi = CSS_DPI) {
15
- return dpi / MM_PER_INCH;
16
- }
17
- function mmToPx(value, dpi = CSS_DPI) {
18
- return (value || 0) * mmToPxFactor(dpi);
19
- }
20
- function pxToMm(value, dpi = CSS_DPI) {
21
- return value / mmToPxFactor(dpi);
22
- }
23
- function ptToPx(pt, dpi = CSS_DPI) {
24
- return pt * dpi / 72;
25
- }
26
- function round(value, digits) {
27
- const f = 10 ** digits;
28
- return Math.round(value * f) / f;
29
- }
30
- var PAPER_SIZES = {
31
- a3: { widthMm: 297, heightMm: 420 },
32
- a4: { widthMm: 210, heightMm: 297 },
33
- a5: { widthMm: 148, heightMm: 210 },
34
- b4: { widthMm: 250, heightMm: 353 },
35
- b5: { widthMm: 176, heightMm: 250 }
36
- };
37
-
38
- // src/schema/render-plan.ts
39
- var RENDER_PLAN_SCHEMA_VERSION = SCHEMA_VERSION_MACH;
40
- function toRenderPlan(response) {
41
- if (response && response.code != null && response.code !== 200) {
42
- throw new Error(String(response.message || "\u6E32\u67D3\u8BA1\u5212\u52A0\u8F7D\u5931\u8D25"));
43
- }
44
- const pages = response?.data?.pages;
45
- return {
46
- schemaVersion: RENDER_PLAN_SCHEMA_VERSION,
47
- pages: Array.isArray(pages) ? pages : []
48
- };
49
- }
50
- function isImageBackedComponent(comp) {
51
- return (comp.kind === "image" || comp.kind === "barcode" || comp.kind === "qrcode" || comp.kind === "chart") && !!comp.imageData;
52
- }
53
- function isRichText(comp) {
54
- return comp.kind === "text" && Array.isArray(comp.richParagraphs) && comp.richParagraphs.length > 0;
55
- }
56
-
57
- // src/schema/validate.ts
58
- var KNOWN_KINDS = /* @__PURE__ */ new Set([
1
+ import { h as J, R as se, D as j, w as G, L as q, i as le, r as _, m as de, a as W, b as Z, c as F, d as V, p as O, e as he, f as Q, g as ce, j as me, P as K } from "./style-B7Xfo5I-.js";
2
+ import { C as Ue, k as Ke, l as Ye, M as Xe, S as Ze, n as Qe, o as et, q as tt, s as nt, t as it, u as rt, v as ot, x as at, y as st } from "./style-B7Xfo5I-.js";
3
+ const ge = /* @__PURE__ */ new Set([
59
4
  "text",
60
5
  "image",
61
6
  "barcode",
@@ -65,569 +10,239 @@ var KNOWN_KINDS = /* @__PURE__ */ new Set([
65
10
  "rect",
66
11
  "ellipse"
67
12
  ]);
68
- function isObj(v) {
69
- return typeof v === "object" && v !== null && !Array.isArray(v);
13
+ function L(e) {
14
+ return typeof e == "object" && e !== null && !Array.isArray(e);
70
15
  }
71
- function checkNumber(obj, key, path, errors) {
72
- const v = obj[key];
73
- if (v === void 0 || v === null) return;
74
- if (typeof v !== "number" || !Number.isFinite(v)) {
75
- errors.push({ path: `${path}.${key}`, message: `\u5E94\u4E3A\u6709\u9650\u6570\u5B57\uFF0C\u5B9E\u9645 ${JSON.stringify(v)}` });
76
- }
16
+ function fe(e, n, i, t) {
17
+ const r = e[n];
18
+ r != null && (typeof r != "number" || !Number.isFinite(r)) && t.push({ path: `${i}.${n}`, message: `应为有限数字,实际 ${JSON.stringify(r)}` });
77
19
  }
78
- function validateComponent(comp, path, errors, warnings = []) {
79
- if (!isObj(comp)) {
80
- errors.push({ path, message: "\u7EC4\u4EF6\u5E94\u4E3A\u5BF9\u8C61" });
20
+ function ee(e, n, i, t = []) {
21
+ if (!L(e)) {
22
+ i.push({ path: n, message: "组件应为对象" });
81
23
  return;
82
24
  }
83
- const kind = comp["kind"];
84
- if (typeof kind !== "string") {
85
- errors.push({ path: `${path}.kind`, message: `\u7EC4\u4EF6\u7F3A\u5C11 kind \u5B57\u7B26\u4E32` });
86
- } else if (!KNOWN_KINDS.has(kind)) {
87
- warnings.push({
88
- path: `${path}.kind`,
89
- message: `\u672A\u77E5\u7EC4\u4EF6\u7C7B\u578B ${JSON.stringify(kind)}\uFF0C\u5C06\u4EE5\u515C\u5E95\u65B9\u5F0F\u6E32\u67D3`
90
- });
91
- }
92
- for (const key of ["leftMm", "topMm", "widthMm", "heightMm"]) {
93
- checkNumber(comp, key, path, errors);
94
- }
95
- if (comp["leftMm"] != null && comp["widthMm"] != null) {
96
- if (comp["leftMm"] < -100 || comp["widthMm"] < 0) {
97
- errors.push({ path, message: "\u51E0\u4F55\u6570\u503C\u5F02\u5E38\uFF08leftMm<-100 \u6216 widthMm<0\uFF09" });
98
- }
99
- }
100
- const grid = comp["grid"];
101
- if (grid !== void 0) {
102
- if (!isObj(grid) || !Array.isArray(grid["cells"])) {
103
- errors.push({ path: `${path}.grid.cells`, message: "grid.cells \u5E94\u4E3A\u4E8C\u7EF4\u6570\u7EC4" });
104
- } else {
105
- grid["cells"].forEach((row, ri) => {
106
- if (!Array.isArray(row)) {
107
- errors.push({ path: `${path}.grid.cells.${ri}`, message: "\u884C\u5E94\u4E3A\u6570\u7EC4" });
108
- return;
109
- }
110
- row.forEach((cell, ci) => {
111
- if (cell === void 0 || cell === null) return;
112
- if (isObj(cell) && Array.isArray(cell["children"])) {
113
- cell["children"].forEach((child, ki) => {
114
- validateComponent(child, `${path}.grid.cells.${ri}.${ci}.children.${ki}`, errors, warnings);
115
- });
116
- }
117
- });
118
- });
119
- }
120
- }
121
- const rich = comp["richParagraphs"];
122
- if (rich !== void 0) {
123
- if (!Array.isArray(rich)) {
124
- errors.push({ path: `${path}.richParagraphs`, message: "richParagraphs \u5E94\u4E3A\u6570\u7EC4" });
125
- } else {
126
- rich.forEach((para, i) => {
127
- if (!isObj(para) || !Array.isArray(para["segments"])) {
128
- errors.push({ path: `${path}.richParagraphs.${i}`, message: "\u6BB5\u843D\u7F3A\u5C11 segments \u6570\u7EC4" });
129
- }
25
+ const r = e.kind;
26
+ typeof r != "string" ? i.push({ path: `${n}.kind`, message: "组件缺少 kind 字符串" }) : ge.has(r) || t.push({
27
+ path: `${n}.kind`,
28
+ message: `未知组件类型 ${JSON.stringify(r)},将以兜底方式渲染`
29
+ });
30
+ for (const o of ["leftMm", "topMm", "widthMm", "heightMm"])
31
+ fe(e, o, n, i);
32
+ e.leftMm != null && e.widthMm != null && (e.leftMm < -100 || e.widthMm < 0) && i.push({ path: n, message: "几何数值异常(leftMm<-100 或 widthMm<0)" });
33
+ const s = e.grid;
34
+ s !== void 0 && (!L(s) || !Array.isArray(s.cells) ? i.push({ path: `${n}.grid.cells`, message: "grid.cells 应为二维数组" }) : s.cells.forEach((o, l) => {
35
+ if (!Array.isArray(o)) {
36
+ i.push({ path: `${n}.grid.cells.${l}`, message: "行应为数组" });
37
+ return;
38
+ }
39
+ o.forEach((d, h) => {
40
+ d != null && L(d) && Array.isArray(d.children) && d.children.forEach((c, m) => {
41
+ ee(c, `${n}.grid.cells.${l}.${h}.children.${m}`, i, t);
130
42
  });
131
- }
132
- }
133
- }
134
- function validatePage(page, path, errors, warnings = []) {
135
- if (!isObj(page)) {
136
- errors.push({ path, message: "\u9875\u5E94\u4E3A\u5BF9\u8C61" });
43
+ });
44
+ }));
45
+ const a = e.richParagraphs;
46
+ a !== void 0 && (Array.isArray(a) ? a.forEach((o, l) => {
47
+ (!L(o) || !Array.isArray(o.segments)) && i.push({ path: `${n}.richParagraphs.${l}`, message: "段落缺少 segments 数组" });
48
+ }) : i.push({ path: `${n}.richParagraphs`, message: "richParagraphs 应为数组" }));
49
+ }
50
+ function ue(e, n, i, t = []) {
51
+ if (!L(e)) {
52
+ i.push({ path: n, message: "页应为对象" });
137
53
  return;
138
54
  }
139
- const w = page["pageWidthMm"];
140
- const h = page["pageHeightMm"];
141
- if (typeof w !== "number" || !(w > 0 && w < 3e3)) {
142
- errors.push({ path: `${path}.pageWidthMm`, message: `\u9875\u5BBD\u975E\u6CD5: ${JSON.stringify(w)}` });
143
- }
144
- if (typeof h !== "number" || !(h > 0 && h < 5e3)) {
145
- errors.push({ path: `${path}.pageHeightMm`, message: `\u9875\u9AD8\u975E\u6CD5: ${JSON.stringify(h)}` });
146
- }
147
- const comps = page["components"];
148
- if (comps !== void 0 && !Array.isArray(comps)) {
149
- errors.push({ path: `${path}.components`, message: "components \u5E94\u4E3A\u6570\u7EC4" });
150
- } else if (Array.isArray(comps)) {
151
- comps.forEach(
152
- (comp, i) => validateComponent(comp, `${path}.components.${i}`, errors, warnings)
153
- );
154
- }
55
+ const r = e.pageWidthMm, s = e.pageHeightMm;
56
+ (typeof r != "number" || !(r > 0 && r < 3e3)) && i.push({ path: `${n}.pageWidthMm`, message: `页宽非法: ${JSON.stringify(r)}` }), (typeof s != "number" || !(s > 0 && s < 5e3)) && i.push({ path: `${n}.pageHeightMm`, message: `页高非法: ${JSON.stringify(s)}` });
57
+ const a = e.components;
58
+ a !== void 0 && !Array.isArray(a) ? i.push({ path: `${n}.components`, message: "components 应为数组" }) : Array.isArray(a) && a.forEach(
59
+ (o, l) => ee(o, `${n}.components.${l}`, i, t)
60
+ );
155
61
  }
156
- function validateRenderPlan(input) {
157
- const errors = [];
158
- const warnings = [];
159
- const pages = isObj(input) ? input["pages"] : void 0;
160
- if (!Array.isArray(pages)) {
161
- errors.push({
62
+ function pe(e) {
63
+ const n = [], i = [], t = L(e) ? e.pages : void 0;
64
+ if (!Array.isArray(t))
65
+ n.push({
162
66
  path: "$.pages",
163
- message: input == null ? "\u6E32\u67D3\u8BA1\u5212\u4E3A\u7A7A" : "\u6E32\u67D3\u8BA1\u5212\u7F3A\u5C11 pages \u6570\u7EC4"
67
+ message: e == null ? "渲染计划为空" : "渲染计划缺少 pages 数组"
68
+ });
69
+ else {
70
+ t.forEach((s, a) => ue(s, `$.pages.${a}`, n, i)), t.length > 2e3 && i.push({
71
+ path: "$.pages",
72
+ message: `页数异常大(${t.length} 页),渲染与打印耗时可能显著增加`
73
+ });
74
+ const r = t.reduce(
75
+ (s, a) => s + (L(a) && Array.isArray(a.components) ? a.components.length : 0),
76
+ 0
77
+ );
78
+ r > 5e4 && i.push({
79
+ path: "$.pages",
80
+ message: `组件总数异常大(${r} 个),可能触发浏览器性能限制`
164
81
  });
165
- } else {
166
- pages.forEach((page, i) => validatePage(page, `$.pages.${i}`, errors, warnings));
167
- }
168
- return { ok: errors.length === 0, errors, warnings };
169
- }
170
- function assertRenderPlan(input) {
171
- const result = validateRenderPlan(input);
172
- if (!result.ok) {
173
- const head = result.errors.slice(0, 3).map((e) => `${e.path}: ${e.message}`).join("; ");
174
- throw new Error(`\u6E32\u67D3\u8BA1\u5212\u6821\u9A8C\u5931\u8D25(${result.errors.length} \u5904): ${head}`);
175
- }
176
- return input.pages;
177
- }
178
-
179
- // src/layout/textwrap.ts
180
- var CJK_RE = /[\u3000-\u9fff\uff00-\uffef]/;
181
- var LATIN_CLASS = new Uint8Array(128);
182
- {
183
- for (const ch of "iljtf.,:;'`|!()[]") LATIN_CLASS[ch.charCodeAt(0)] = 1;
184
- for (const ch of "mwMW@") LATIN_CLASS[ch.charCodeAt(0)] = 2;
185
- for (let c = 48; c <= 57; c++) LATIN_CLASS[c] = 3;
186
- for (let c = 65; c <= 90; c++) LATIN_CLASS[c] = 4;
187
- LATIN_CLASS[32] = 5;
188
- }
189
- var LATIN_WIDTH = [0.54, 0.26, 0.95, 0.59, 0.67, 0.3];
190
- function charWidthEm(ch) {
191
- const code = ch.charCodeAt(0);
192
- if (code < 128) return LATIN_WIDTH[LATIN_CLASS[code]];
193
- if (CJK_RE.test(ch)) return 1;
194
- if (/[A-Z]/.test(ch)) return 0.67;
195
- return 0.54;
196
- }
197
- var heuristicMeasurer = {
198
- measureMm(text, options) {
199
- const { fontSizePt, bold = false, letterSpacingPt = 0 } = options;
200
- const ptToMm = 25.4 / 72;
201
- let units = 0;
202
- for (const ch of text) {
203
- units += charWidthEm(ch);
204
- }
205
- if (bold) units *= 1.04;
206
- return (units * fontSizePt + letterSpacingPt * text.length) * ptToMm;
207
- }
208
- };
209
- function createHeuristicMeasurer() {
210
- return heuristicMeasurer;
211
- }
212
- function measureTextMm(text, options) {
213
- return heuristicMeasurer.measureMm(text, options);
214
- }
215
- function createCanvasMeasurer(getCtx2d) {
216
- let ctx;
217
- return {
218
- measureMm(text, options) {
219
- if (ctx === void 0) ctx = getCtx2d();
220
- if (!ctx) return heuristicMeasurer.measureMm(text, options);
221
- const px = options.fontSizePt * 96 / 72;
222
- ctx.font = `${options.bold ? "bold " : ""}${px}px sans-serif`;
223
- return ctx.measureText(text).width * 25.4 / 96;
224
- }
225
- };
226
- }
227
- function tokenize(text, options, measurer) {
228
- const atoms = [];
229
- let word = "";
230
- let wordWidth = 0;
231
- const flush = () => {
232
- if (word) {
233
- atoms.push({ text: word, widthMm: wordWidth, cjk: false });
234
- word = "";
235
- wordWidth = 0;
236
- }
237
- };
238
- for (const ch of text) {
239
- if (ch === "\n") {
240
- flush();
241
- atoms.push({ text: "\n", widthMm: 0, cjk: false, br: true });
242
- continue;
243
- }
244
- if (ch === " ") {
245
- flush();
246
- atoms.push({ text: ch, widthMm: measurer.measureMm(ch, options), cjk: false, space: true });
247
- continue;
248
- }
249
- if (CJK_RE.test(ch)) {
250
- flush();
251
- atoms.push({ text: ch, widthMm: measurer.measureMm(ch, options), cjk: true });
252
- continue;
253
- }
254
- word += ch;
255
- wordWidth += measurer.measureMm(ch, options);
256
82
  }
257
- flush();
258
- return atoms;
83
+ return { ok: n.length === 0, errors: n, warnings: i };
259
84
  }
260
- function wrapText(text, maxWidthMm, options, measurer = heuristicMeasurer) {
261
- if (!text) return [""];
262
- const lines = [];
263
- let current = "";
264
- let currentWidth = 0;
265
- const pushLine = () => {
266
- lines.push(current);
267
- current = "";
268
- currentWidth = 0;
269
- };
270
- for (const atom of tokenize(text, options, measurer)) {
271
- if (atom.br) {
272
- pushLine();
273
- continue;
274
- }
275
- if (currentWidth + atom.widthMm <= maxWidthMm) {
276
- current += atom.text;
277
- currentWidth += atom.widthMm;
278
- continue;
279
- }
280
- if (atom.space) {
281
- pushLine();
282
- continue;
283
- }
284
- if (atom.cjk) {
285
- if (current.length > 0) pushLine();
286
- current = atom.text;
287
- currentWidth = atom.widthMm;
288
- continue;
289
- }
290
- if (current.length > 0) pushLine();
291
- if (atom.widthMm <= maxWidthMm) {
292
- current = atom.text;
293
- currentWidth = atom.widthMm;
294
- continue;
295
- }
296
- for (const ch of atom.text) {
297
- const chWidth = measurer.measureMm(ch, options);
298
- if (currentWidth + chWidth > maxWidthMm && current.length > 0) {
299
- pushLine();
300
- }
301
- current += ch;
302
- currentWidth += chWidth;
303
- }
85
+ function _e(e) {
86
+ const n = pe(e);
87
+ if (!n.ok) {
88
+ const i = n.errors.slice(0, 3).map((t) => `${t.path}: ${t.message}`).join("; ");
89
+ throw new Error(`渲染计划校验失败(${n.errors.length} 处): ${i}`);
304
90
  }
305
- pushLine();
306
- return lines;
91
+ return e.pages;
307
92
  }
308
-
309
- // src/layout/paginate.ts
310
- function makeWorkingPage(page) {
93
+ function Y(e) {
311
94
  return {
312
- widthMm: page.widthMm,
313
- heightMm: page.heightMm,
314
- marginTopMm: page.marginTopMm ?? 0,
315
- marginBottomMm: page.marginBottomMm ?? 0,
316
- marginLeftMm: page.marginLeftMm ?? 0,
317
- marginRightMm: page.marginRightMm ?? 0,
95
+ widthMm: e.widthMm,
96
+ heightMm: e.heightMm,
97
+ marginTopMm: e.marginTopMm ?? 0,
98
+ marginBottomMm: e.marginBottomMm ?? 0,
99
+ marginLeftMm: e.marginLeftMm ?? 0,
100
+ marginRightMm: e.marginRightMm ?? 0,
318
101
  components: []
319
102
  };
320
103
  }
321
- function toContentBottom(page, wp) {
322
- return wp.heightMm - (page.marginBottomMm ?? wp.marginBottomMm);
104
+ function Me(e, n) {
105
+ return n.heightMm - (e.marginBottomMm ?? n.marginBottomMm);
323
106
  }
324
- function estRowHeightMm(list, lines) {
325
- const fontSizePt = list.fontSizePt ?? DEFAULT_FONT_PT;
326
- const lineMm = fontSizePt * LINE_HEIGHT * 25.4 / 72;
327
- const padding = (list.paddingMm ?? 1) * 2;
328
- return Math.max(list.rowHeightMm ?? 0, lines * lineMm + padding);
107
+ function be(e, n) {
108
+ const t = (e.fontSizePt ?? j) * q * 25.4 / 72, r = (e.paddingMm ?? 1) * 2;
109
+ return Math.max(e.rowHeightMm ?? 0, n * t + r);
329
110
  }
330
- function cellText(value) {
331
- if (value == null) return "";
332
- if (typeof value === "string") return value;
333
- if (typeof value === "number") return String(value);
334
- if (typeof value === "boolean") return value ? "\u662F" : "\u5426";
335
- if (value instanceof Date) return value.toISOString().slice(0, 10);
111
+ function ye(e) {
112
+ if (e == null) return "";
113
+ if (typeof e == "string") return e;
114
+ if (typeof e == "number") return String(e);
115
+ if (typeof e == "boolean") return e ? "是" : "否";
116
+ if (e instanceof Date) return e.toISOString().slice(0, 10);
336
117
  try {
337
- return JSON.stringify(value);
118
+ return JSON.stringify(e);
338
119
  } catch {
339
- return String(value);
120
+ return String(e);
340
121
  }
341
122
  }
342
- function interList(list, measurer) {
343
- const fontSizePt = list.fontSizePt ?? DEFAULT_FONT_PT;
344
- const paddingMm = list.paddingMm ?? 1;
345
- const cellStyles = list.columns.map(
346
- (col) => col.style ? { align: "left", verticalAlign: "middle", ...col.style } : { align: "left", verticalAlign: "middle" }
347
- );
348
- const headerCellStyles = list.columns.map(
349
- (col) => ({
350
- bold: list.headerBold ?? true,
123
+ function we(e, n) {
124
+ const i = e.fontSizePt ?? j, t = e.paddingMm ?? 1, r = e.columns.map(
125
+ (m) => m.style ? { align: "left", verticalAlign: "middle", ...m.style } : { align: "left", verticalAlign: "middle" }
126
+ ), s = e.columns.map(
127
+ (m) => ({
128
+ bold: e.headerBold ?? !0,
351
129
  align: "center",
352
130
  verticalAlign: "middle",
353
- backgroundColor: list.headerBackgroundColor,
354
- ...col.style || {}
131
+ backgroundColor: e.headerBackgroundColor,
132
+ ...m.style || {}
355
133
  })
356
- );
357
- const headerTexts = list.columns.map((col) => col.header);
358
- const headerLines = headerTexts.map(
359
- (text, i) => wrapText(
360
- text,
361
- list.columns[i].widthMm - paddingMm * 2,
362
- { fontSizePt, bold: list.headerBold ?? true },
363
- measurer
134
+ ), a = e.columns.map((m) => m.header), o = a.map(
135
+ (m, u) => G(
136
+ m,
137
+ e.columns[u].widthMm - t * 2,
138
+ { fontSizePt: i, bold: e.headerBold ?? !0 },
139
+ n
364
140
  )
365
- );
366
- const maxLines = Math.max(...headerLines.map((l) => l.length), 1);
367
- const headerHeight = estRowHeightMm(list, maxLines);
368
- const headerCells = headerTexts.map((text, i) => ({
369
- text,
370
- style: headerCellStyles[i]
371
- }));
372
- const borderStyle = list.border === false ? { borderTop: false, borderRight: false, borderBottom: false, borderLeft: false } : { borderBottom: true, borderLeft: true, borderRight: true, borderTop: true };
141
+ ), l = Math.max(...o.map((m) => m.length), 1), d = be(e, l), h = a.map((m, u) => ({
142
+ text: m,
143
+ style: s[u]
144
+ })), c = e.border === !1 ? { borderTop: !1, borderRight: !1, borderBottom: !1, borderLeft: !1 } : { borderBottom: !0, borderLeft: !0, borderRight: !0, borderTop: !0 };
373
145
  return {
374
- fontSizePt,
375
- paddingMm,
376
- cellStyles,
377
- borderStyle,
378
- headerHeightMm: headerHeight,
379
- headerGrid: { cells: [headerCells], rowHeightsMm: [headerHeight] },
380
- columns: list.columns
146
+ fontSizePt: i,
147
+ paddingMm: t,
148
+ cellStyles: r,
149
+ borderStyle: c,
150
+ headerHeightMm: d,
151
+ headerGrid: { cells: [h], rowHeightsMm: [d] },
152
+ columns: e.columns
381
153
  };
382
154
  }
383
- function buildRowGridFast(inter, row, measurer) {
384
- const columns = inter.columns;
385
- const texts = new Array(columns.length);
386
- let maxLines = 1;
387
- for (let i = 0; i < columns.length; i++) {
388
- texts[i] = cellText(row[columns[i].field]);
389
- }
390
- const lines = new Array(columns.length);
391
- for (let i = 0; i < columns.length; i++) {
392
- const wrapped = wrapText(
393
- texts[i],
394
- columns[i].widthMm - inter.paddingMm * 2,
395
- { fontSizePt: inter.fontSizePt },
396
- measurer
155
+ function Se(e, n, i) {
156
+ const t = e.columns, r = new Array(t.length);
157
+ let s = 1;
158
+ for (let h = 0; h < t.length; h++)
159
+ r[h] = ye(n[t[h].field]);
160
+ const a = new Array(t.length);
161
+ for (let h = 0; h < t.length; h++) {
162
+ const c = G(
163
+ r[h],
164
+ t[h].widthMm - e.paddingMm * 2,
165
+ { fontSizePt: e.fontSizePt },
166
+ i
397
167
  );
398
- lines[i] = wrapped;
399
- if (wrapped.length > maxLines) maxLines = wrapped.length;
400
- }
401
- const lineMm = inter.fontSizePt * LINE_HEIGHT * 25.4 / 72;
402
- const height = Math.max(
403
- inter.rowHeightFloorMm,
404
- maxLines * lineMm + inter.paddingMm * 2
405
- );
406
- const cells = new Array(columns.length);
407
- for (let i = 0; i < columns.length; i++) {
408
- cells[i] = { text: texts[i], style: inter.cellStyles[i] };
409
- }
410
- return { grid: { cells: [cells], rowHeightsMm: [height] }, heightMm: height };
411
- }
412
- function paginateTemplate(template, datasets, optionsOrMmPerRow = {}) {
413
- const options = typeof optionsOrMmPerRow === "number" ? { mmPerRow: optionsOrMmPerRow } : optionsOrMmPerRow;
414
- const mmPerRow = options.mmPerRow ?? 0;
415
- const measurer = options.measurer ?? heuristicMeasurer;
416
- const warnings = [];
417
- const pages = [];
418
- let seq = 0;
419
- const nextId = (prefix) => `${prefix}_${(++seq).toString(36)}`;
420
- for (const tplPage of template.pages) {
421
- const current = makeWorkingPage(tplPage);
422
- const contentBottom = () => toContentBottom(tplPage, current);
423
- const contentTop = current.marginTopMm;
424
- const pushCurrent = () => {
425
- pages.push({
426
- pageWidthMm: current.widthMm,
427
- pageHeightMm: current.heightMm,
428
- marginTopMm: current.marginTopMm,
429
- marginBottomMm: current.marginBottomMm,
430
- marginLeftMm: current.marginLeftMm,
431
- marginRightMm: current.marginRightMm,
432
- components: current.components
168
+ a[h] = c, c.length > s && (s = c.length);
169
+ }
170
+ const o = e.fontSizePt * q * 25.4 / 72, l = Math.max(
171
+ e.rowHeightFloorMm,
172
+ s * o + e.paddingMm * 2
173
+ ), d = new Array(t.length);
174
+ for (let h = 0; h < t.length; h++)
175
+ d[h] = { text: r[h], style: e.cellStyles[h] };
176
+ return { grid: { cells: [d], rowHeightsMm: [l] }, heightMm: l };
177
+ }
178
+ function We(e, n, i = {}) {
179
+ const t = typeof i == "number" ? { mmPerRow: i } : i, r = t.mmPerRow ?? 0, s = t.measurer ?? J, a = [], o = [];
180
+ let l = 0;
181
+ const d = (h) => `${h}_${(++l).toString(36)}`;
182
+ for (const h of e.pages) {
183
+ const c = Y(h), m = () => Me(h, c), u = c.marginTopMm, g = () => {
184
+ o.push({
185
+ pageWidthMm: c.widthMm,
186
+ pageHeightMm: c.heightMm,
187
+ marginTopMm: c.marginTopMm,
188
+ marginBottomMm: c.marginBottomMm,
189
+ marginLeftMm: c.marginLeftMm,
190
+ marginRightMm: c.marginRightMm,
191
+ components: c.components
433
192
  });
434
193
  };
435
- for (const comp of tplPage.components) {
436
- if (comp.kind !== "list") {
437
- current.components.push(comp);
194
+ for (const M of h.components) {
195
+ if (M.kind !== "list") {
196
+ c.components.push(M);
438
197
  continue;
439
198
  }
440
- const list = comp;
441
- const rows = datasets[list.dataset];
442
- if (!Array.isArray(rows)) {
443
- warnings.push(`\u6570\u636E\u96C6 ${list.dataset} \u672A\u63D0\u4F9B\u6570\u636E\uFF0C\u5217\u8868 ${list.id ?? ""} \u8F93\u51FA\u4E3A\u7A7A`);
444
- }
445
- const dataRows = Array.isArray(rows) ? rows : [];
446
- const columnsWidth = list.columns.reduce((s, c) => s + c.widthMm, 0);
447
- const scale = columnsWidth > list.widthMm ? list.widthMm / columnsWidth : 1;
448
- const scaledList = scale === 1 ? list : { ...list, columns: list.columns.map((c) => ({ ...c, widthMm: c.widthMm * scale })) };
449
- const inter = {
450
- ...interList(scaledList, measurer),
451
- rowHeightFloorMm: scaledList.rowHeightMm ?? 0
452
- };
453
- const headerComp = {
199
+ const p = M, k = n[p.dataset];
200
+ Array.isArray(k) || a.push(`数据集 ${p.dataset} 未提供数据,列表 ${p.id ?? ""} 输出为空`);
201
+ const T = Array.isArray(k) ? k : [], E = p.columns.reduce((f, b) => f + b.widthMm, 0), w = E > p.widthMm ? p.widthMm / E : 1, I = w === 1 ? p : { ...p, columns: p.columns.map((f) => ({ ...f, widthMm: f.widthMm * w })) }, R = {
202
+ ...we(I, s),
203
+ rowHeightFloorMm: I.rowHeightMm ?? 0
204
+ }, D = {
454
205
  kind: "rect",
455
- leftMm: list.leftMm,
206
+ leftMm: p.leftMm,
456
207
  topMm: 0,
457
- widthMm: list.widthMm,
458
- heightMm: inter.headerHeightMm,
459
- grid: inter.headerGrid,
460
- nid: nextId("listh"),
461
- style: inter.borderStyle
208
+ widthMm: p.widthMm,
209
+ heightMm: R.headerHeightMm,
210
+ grid: R.headerGrid,
211
+ nid: d("listh"),
212
+ style: R.borderStyle
462
213
  };
463
- let y = list.topMm;
464
- const placeHeader = (target, topMm) => {
465
- target.components.push({ ...headerComp, topMm });
214
+ let $ = p.topMm;
215
+ const B = (f, b) => {
216
+ f.components.push({ ...D, topMm: b });
466
217
  };
467
- placeHeader(current, y);
468
- y += inter.headerHeightMm + mmPerRow;
469
- for (let i = 0; i < dataRows.length; i++) {
470
- const rowGrid = buildRowGridFast(inter, dataRows[i], measurer);
471
- if (y + rowGrid.heightMm > contentBottom()) {
472
- pushCurrent();
473
- const next = makeWorkingPage(tplPage);
474
- current.components = next.components;
475
- current.heightMm = next.heightMm;
476
- if (scaledList.headerEveryPage !== false) {
477
- placeHeader(current, list.topMm);
478
- y = list.topMm + inter.headerHeightMm;
479
- } else {
480
- y = contentTop;
481
- }
218
+ B(c, $), $ += R.headerHeightMm + r;
219
+ for (let f = 0; f < T.length; f++) {
220
+ const b = Se(R, T[f], s);
221
+ if ($ + b.heightMm > m()) {
222
+ g();
223
+ const P = Y(h);
224
+ c.components = P.components, c.heightMm = P.heightMm, I.headerEveryPage !== !1 ? (B(c, p.topMm), $ = p.topMm + R.headerHeightMm) : $ = u;
482
225
  }
483
- current.components.push({
226
+ c.components.push({
484
227
  kind: "rect",
485
- leftMm: list.leftMm,
486
- topMm: y,
487
- widthMm: list.widthMm,
488
- heightMm: rowGrid.heightMm,
489
- grid: rowGrid.grid,
490
- nid: nextId("listr"),
491
- style: inter.borderStyle
492
- });
493
- y += rowGrid.heightMm;
228
+ leftMm: p.leftMm,
229
+ topMm: $,
230
+ widthMm: p.widthMm,
231
+ heightMm: b.heightMm,
232
+ grid: b.grid,
233
+ nid: d("listr"),
234
+ style: R.borderStyle
235
+ }), $ += b.heightMm;
494
236
  }
495
237
  }
496
- pushCurrent();
238
+ g();
497
239
  }
498
240
  return {
499
- plan: { schemaVersion: RENDER_PLAN_SCHEMA_VERSION, pages },
500
- warnings
241
+ plan: { schemaVersion: se, pages: o },
242
+ warnings: a
501
243
  };
502
244
  }
503
-
504
- // src/render/grid-geometry.ts
505
- function cumulate(sizesMm, totalMm) {
506
- const n = sizesMm.length;
507
- if (n === 0) return [];
508
- const sum = sizesMm.reduce((s, v) => s + v, 0);
509
- const scale = sum > 0 && totalMm > 0 ? totalMm / sum : 1;
510
- const out = [];
511
- let acc = 0;
512
- for (let i = 0; i < n; i++) {
513
- const size = Math.max(0, sizesMm[i] * scale);
514
- out.push({ pos: acc, size });
515
- acc += size;
516
- }
517
- return out;
518
- }
519
- function resolveGridLayout(grid, compWidthMm, compHeightMm) {
520
- const rowsRaw = grid.cells ?? [];
521
- const rowCount = Math.max(rowsRaw.length, 1);
522
- const colCount = grid.colWidthsMm?.length ?? Math.max(1, ...rowsRaw.map((r) => Array.isArray(r) ? r.length : 0));
523
- const widths = grid.colWidthsMm?.length ? cumulate(grid.colWidthsMm, compWidthMm) : Array.from({ length: colCount }, (_, i) => ({
524
- pos: compWidthMm * i / colCount,
525
- size: compWidthMm / colCount
526
- }));
527
- const colPos = (ci) => ci <= 0 ? 0 : ci >= colCount ? widths[widths.length - 1].pos + widths[widths.length - 1].size : widths[ci].pos;
528
- const heights = grid.rowHeightsMm?.length ? cumulate(grid.rowHeightsMm, compHeightMm) : Array.from({ length: rowCount }, (_, i) => ({
529
- pos: compHeightMm * i / rowCount,
530
- size: compHeightMm / rowCount
531
- }));
532
- const rowPos = (ri) => ri <= 0 ? 0 : ri >= rowCount ? heights[heights.length - 1].pos + heights[heights.length - 1].size : heights[ri].pos;
533
- const occupied = /* @__PURE__ */ new Set();
534
- const key = (r, c) => `${r}:${c}`;
535
- const cells = [];
536
- const vBridge = /* @__PURE__ */ new Set();
537
- const hBridge = /* @__PURE__ */ new Set();
538
- const vKey = (c, r) => `v${c}:${r}`;
539
- const hKey = (r, c) => `h${r}:${c}`;
540
- rowsRaw.forEach((row, ri) => {
541
- if (!Array.isArray(row)) return;
542
- let ci = 0;
543
- for (const cell of row) {
544
- while (ci < colCount && occupied.has(key(ri, ci))) ci++;
545
- if (ci >= colCount) break;
546
- const colSpan = Math.max(1, Math.min(cell?.colSpan ?? 1, colCount - ci));
547
- const rowSpan = Math.max(1, cell?.rowSpan ?? 1);
548
- const rowEnd = Math.min(rowCount, ri + rowSpan);
549
- const colEnd = Math.min(colCount, ci + colSpan);
550
- for (let dr = ri; dr < rowEnd; dr++) {
551
- for (let dc = ci; dc < colEnd; dc++) {
552
- occupied.add(key(dr, dc));
553
- }
554
- }
555
- for (let c = ci + 1; c < colEnd; c++) {
556
- for (let r = ri; r < rowEnd; r++) vBridge.add(vKey(c, r));
557
- }
558
- for (let r = ri + 1; r < rowEnd; r++) {
559
- for (let c = ci; c < colEnd; c++) hBridge.add(hKey(r, c));
560
- }
561
- const xMm = colPos(ci);
562
- const yMm = rowPos(ri);
563
- cells.push({
564
- ri,
565
- ci,
566
- cell: cell ?? {},
567
- xMm,
568
- yMm,
569
- widthMm: colPos(colEnd) - xMm,
570
- heightMm: rowPos(rowEnd) - yMm
571
- });
572
- ci = colEnd;
573
- }
574
- });
575
- const edges = [];
576
- for (let c = 1; c < colCount; c++) {
577
- let runStart = -1;
578
- for (let r = 0; r <= rowCount; r++) {
579
- const open = r < rowCount && !vBridge.has(vKey(c, r));
580
- if (open && runStart < 0) runStart = r;
581
- if (!open && runStart >= 0) {
582
- edges.push({ kind: "v", pos: colPos(c), from: rowPos(runStart), to: rowPos(r) });
583
- runStart = -1;
584
- }
585
- }
586
- }
587
- for (let r = 1; r < rowCount; r++) {
588
- let runStart = -1;
589
- for (let c = 0; c <= colCount; c++) {
590
- const open = c < colCount && !hBridge.has(hKey(r, c));
591
- if (open && runStart < 0) runStart = c;
592
- if (!open && runStart >= 0) {
593
- edges.push({ kind: "h", pos: rowPos(r), from: colPos(runStart), to: colPos(c) });
594
- runStart = -1;
595
- }
596
- }
597
- }
598
- return { columns: widths, rows: heights, cells, edges };
599
- }
600
-
601
- // src/render/style.ts
602
- function resolveFontSize(style, dpi = 96, defaultPt = DEFAULT_FONT_PT) {
603
- if (style?.fontSizePx != null) {
604
- return { fontSizePt: style.fontSizePx * 72 / dpi, fontSizePx: style.fontSizePx };
605
- }
606
- const pt = style?.fontSize ?? defaultPt;
607
- return { fontSizePt: pt, fontSizePx: ptToPx(pt, dpi) };
608
- }
609
- function resolveStroke(style, fallbackColor = DEFAULT_STROKE_COLOR) {
610
- return {
611
- color: style?.borderColor ?? style?.lineColor ?? fallbackColor,
612
- widthPt: style?.lineWidthPt ?? DEFAULT_BORDER_PT
613
- };
614
- }
615
- function resolveTextColor(style, fallback = DEFAULT_TEXT_COLOR) {
616
- return style?.color ?? fallback;
617
- }
618
- function resolveLineHeight(style) {
619
- return style?.lineHeight ?? LINE_HEIGHT;
620
- }
621
- function resolveBoxBorders(style) {
622
- const top = style?.borderTop !== false;
623
- const right = style?.borderRight !== false;
624
- const bottom = style?.borderBottom !== false;
625
- const left = style?.borderLeft !== false;
626
- return { top, right, bottom, left, inner: top || right || bottom || left };
627
- }
628
-
629
- // src/render/dom.ts
630
- var CLS = {
245
+ const Te = {
631
246
  root: "mr-root",
632
247
  page: "mr-page",
633
248
  comp: "mr-comp",
@@ -644,848 +259,528 @@ var CLS = {
644
259
  cell: "mr-cell",
645
260
  unknown: "mr-unknown"
646
261
  };
647
- function classOf(key, options) {
648
- return options?.classNames?.[key] ?? CLS[key];
262
+ function C(e, n) {
263
+ return n?.classNames?.[e] ?? Te[e];
649
264
  }
650
- var StyleBag = class {
265
+ class H {
651
266
  constructor() {
652
267
  this.props = [];
653
268
  }
654
- add(prop, value) {
655
- if (value === void 0 || value === null || value === false || value === "") return this;
656
- this.props.push([prop, String(value)]);
657
- return this;
269
+ add(n, i) {
270
+ return i == null || i === !1 || i === "" ? this : (this.props.push([n, String(i)]), this);
658
271
  }
659
- mm(prop, valueMm, dpi, digits = 2) {
660
- return this.add(prop, `${round(mmToPx(valueMm, dpi), digits)}px`);
272
+ mm(n, i, t, r = 2) {
273
+ return this.add(n, `${_(de(i, t), r)}px`);
661
274
  }
662
275
  toString() {
663
- let css = "";
664
- for (const [prop, value] of this.props) {
665
- css += `${prop}:${value};`;
666
- }
667
- return css;
668
- }
669
- applyTo(el) {
670
- const css = this.toString();
671
- if (css) el.style.cssText = css;
672
- }
673
- };
674
- function applyComponentStyle(bag, comp, dpi) {
675
- const s = comp.style || {};
676
- bag.add("color", s.color).add("background-color", s.backgroundColor).add("font-family", s.fontFamily).add("font-weight", s.bold ? "700" : void 0).add("font-style", s.italic ? "italic" : void 0).add("text-decoration", s.underline ? "underline" : void 0).add("letter-spacing", s.letterSpacing != null ? `${s.letterSpacing}pt` : void 0).add("opacity", s.opacity != null ? String(s.opacity) : void 0).add("transform", s.rotateDeg ? `rotate(${s.rotateDeg}deg)` : void 0);
677
- const font = resolveFontSize(s, dpi);
678
- bag.add("font-size", `${round(font.fontSizePx, 2)}px`);
679
- }
680
- function renderGrid(grid, comp, dpi, options, doc) {
681
- const table = doc.createElement("table");
682
- table.className = classOf("grid", options);
683
- new StyleBag().add("width", "100%").add("height", "100%").add("border-collapse", "collapse").add("table-layout", grid.colWidthsMm ? "fixed" : "auto").applyTo(table);
684
- if (grid.colWidthsMm) {
685
- const colGroup = doc.createElement("colgroup");
686
- for (const w of grid.colWidthsMm) {
687
- const col = doc.createElement("col");
688
- new StyleBag().mm("width", w, dpi).applyTo(col);
689
- colGroup.appendChild(col);
690
- }
691
- table.appendChild(colGroup);
692
- }
693
- const borders = resolveBoxBorders(comp.style);
694
- const stroke = resolveStroke(comp.style);
695
- const border = borders.inner ? `${round(stroke.widthPt * dpi / 72, 2)}px solid ${stroke.color}` : "";
696
- grid.cells.forEach((row, ri) => {
697
- const rowEl = doc.createElement("tr");
698
- rowEl.className = classOf("row", options);
699
- if (grid.rowHeightsMm?.[ri] != null) {
700
- new StyleBag().mm("height", grid.rowHeightsMm[ri], dpi).applyTo(rowEl);
701
- }
702
- (row || []).forEach((cell) => {
703
- const cellEl = doc.createElement("td");
704
- cellEl.className = classOf("cell", options);
705
- if (cell?.colSpan) cellEl.colSpan = cell.colSpan;
706
- if (cell?.rowSpan) cellEl.rowSpan = cell.rowSpan;
707
- const cellBag = new StyleBag();
708
- if (border) cellBag.add("border", border);
709
- if (cell?.style) {
710
- const st = cell.style;
711
- cellBag.add("text-align", st.align).add("vertical-align", st.verticalAlign).add("background-color", st.backgroundColor).add("color", st.color).add("font-weight", st.bold ? "700" : void 0);
712
- cellBag.add("font-size", `${round(resolveFontSize(st, dpi).fontSizePx, 2)}px`);
713
- }
714
- cellBag.applyTo(cellEl);
715
- if (cell?.text != null) cellEl.textContent = cell.text;
716
- if (cell?.children?.length) {
717
- for (const child of cell.children) {
718
- cellEl.appendChild(renderComponent(child, dpi, options, doc));
719
- }
276
+ let n = "";
277
+ for (const [i, t] of this.props)
278
+ n += `${i}:${t};`;
279
+ return n;
280
+ }
281
+ applyTo(n) {
282
+ const i = this.toString();
283
+ i && (n.style.cssText = i);
284
+ }
285
+ }
286
+ function te(e, n, i) {
287
+ const t = n.style || {};
288
+ e.add("color", t.color).add("background-color", t.backgroundColor).add("font-family", t.fontFamily).add("font-weight", t.bold ? "700" : void 0).add("font-style", t.italic ? "italic" : void 0).add("text-decoration", t.underline ? "underline" : void 0).add("letter-spacing", t.letterSpacing != null ? `${t.letterSpacing}pt` : void 0).add("opacity", t.opacity != null ? String(t.opacity) : void 0).add("transform", t.rotateDeg ? `rotate(${t.rotateDeg}deg)` : void 0);
289
+ const r = W(t, i);
290
+ e.add("font-size", `${_(r.fontSizePx, 2)}px`);
291
+ }
292
+ function ve(e, n, i, t, r) {
293
+ const s = r.createElement("table");
294
+ if (s.className = C("grid", t), new H().add("width", "100%").add("height", "100%").add("border-collapse", "collapse").add("table-layout", e.colWidthsMm ? "fixed" : "auto").applyTo(s), e.colWidthsMm) {
295
+ const d = r.createElement("colgroup");
296
+ for (const h of e.colWidthsMm) {
297
+ const c = r.createElement("col");
298
+ new H().mm("width", h, i).applyTo(c), d.appendChild(c);
299
+ }
300
+ s.appendChild(d);
301
+ }
302
+ const a = V(n.style), o = F(n.style), l = a.inner ? `${_(o.widthPt * i / 72, 2)}px solid ${o.color}` : "";
303
+ return e.cells.forEach((d, h) => {
304
+ const c = r.createElement("tr");
305
+ c.className = C("row", t), e.rowHeightsMm?.[h] != null && new H().mm("height", e.rowHeightsMm[h], i).applyTo(c), (d || []).forEach((m) => {
306
+ const u = r.createElement("td");
307
+ u.className = C("cell", t), m?.colSpan && (u.colSpan = m.colSpan), m?.rowSpan && (u.rowSpan = m.rowSpan);
308
+ const g = new H();
309
+ if (l && g.add("border", l), m?.style) {
310
+ const M = m.style;
311
+ g.add("text-align", M.align).add("vertical-align", M.verticalAlign).add("background-color", M.backgroundColor).add("color", M.color).add("font-weight", M.bold ? "700" : void 0), g.add("font-size", `${_(W(M, i).fontSizePx, 2)}px`);
720
312
  }
721
- rowEl.appendChild(cellEl);
722
- });
723
- table.appendChild(rowEl);
724
- });
725
- return table;
726
- }
727
- function renderText(comp, dpi, options, doc) {
728
- const el = doc.createElement("div");
729
- el.className = classOf("text", options);
730
- const s = comp.style || {};
731
- const bag = new StyleBag().add("text-align", s.align).add("display", "flex").add("flex-direction", "column").add(
313
+ if (g.applyTo(u), m?.text != null && (u.textContent = m.text), m?.children?.length)
314
+ for (const M of m.children)
315
+ u.appendChild(ne(M, i, t, r));
316
+ c.appendChild(u);
317
+ }), s.appendChild(c);
318
+ }), s;
319
+ }
320
+ function Ce(e, n, i, t) {
321
+ const r = t.createElement("div");
322
+ r.className = C("text", i);
323
+ const s = e.style || {}, a = new H().add("text-align", s.align).add("display", "flex").add("flex-direction", "column").add(
732
324
  "justify-content",
733
325
  s.verticalAlign === "middle" ? "center" : s.verticalAlign === "bottom" ? "flex-end" : "flex-start"
734
326
  ).add("overflow", "hidden");
735
- applyComponentStyle(bag, comp, dpi);
736
- bag.applyTo(el);
737
- if (isRichText(comp)) {
738
- const richBox = doc.createElement("div");
739
- richBox.className = classOf("rich", options);
740
- for (const para of comp.richParagraphs) {
741
- const p = doc.createElement("div");
742
- p.className = classOf("paragraph", options);
743
- const pBag = new StyleBag().add("text-align", para.align).add("line-height", para.lineHeight != null ? String(para.lineHeight) : void 0).mm("margin-top", para.spaceBeforeMm ?? 0, dpi).mm("margin-bottom", para.spaceAfterMm ?? 0, dpi).mm("text-indent", para.indentMm ?? 0, dpi);
744
- pBag.applyTo(p);
745
- for (const seg of para.segments || []) {
746
- const segEl = doc.createElement("span");
747
- segEl.className = classOf("segment", options);
748
- segEl.textContent = seg.kind === "field" ? seg.field ?? "" : seg.text ?? "";
749
- if (seg.style) {
750
- const segBag = new StyleBag().add("color", seg.style.color).add("font-weight", seg.style.bold ? "700" : void 0);
751
- segBag.add("font-size", `${round(resolveFontSize(seg.style, dpi).fontSizePx, 2)}px`);
752
- segBag.applyTo(segEl);
327
+ if (te(a, e, n), a.applyTo(r), Z(e)) {
328
+ const o = t.createElement("div");
329
+ o.className = C("rich", i);
330
+ for (const l of e.richParagraphs) {
331
+ const d = t.createElement("div");
332
+ d.className = C("paragraph", i), new H().add("text-align", l.align).add("line-height", l.lineHeight != null ? String(l.lineHeight) : void 0).mm("margin-top", l.spaceBeforeMm ?? 0, n).mm("margin-bottom", l.spaceAfterMm ?? 0, n).mm("text-indent", l.indentMm ?? 0, n).applyTo(d);
333
+ for (const c of l.segments || []) {
334
+ const m = t.createElement("span");
335
+ if (m.className = C("segment", i), m.textContent = c.kind === "field" ? c.field ?? "" : c.text ?? "", c.style) {
336
+ const u = new H().add("color", c.style.color).add("font-weight", c.style.bold ? "700" : void 0);
337
+ u.add("font-size", `${_(W(c.style, n).fontSizePx, 2)}px`), u.applyTo(m);
753
338
  }
754
- p.appendChild(segEl);
339
+ d.appendChild(m);
755
340
  }
756
- richBox.appendChild(p);
757
- }
758
- el.appendChild(richBox);
759
- return el;
760
- }
761
- if (Array.isArray(comp.lines) && comp.lines.length > 0) {
762
- const box = doc.createElement("div");
763
- box.className = classOf("lines", options);
764
- if (s.lineHeight != null) new StyleBag().add("line-height", String(s.lineHeight)).applyTo(box);
765
- for (const line of comp.lines) {
766
- const lineEl = doc.createElement("div");
767
- lineEl.className = classOf("line", options);
768
- lineEl.textContent = line;
769
- box.appendChild(lineEl);
770
- }
771
- el.appendChild(box);
772
- return el;
773
- }
774
- el.textContent = comp.text ?? "";
775
- return el;
776
- }
777
- function renderImage(comp, options, doc) {
778
- const img = doc.createElement("img");
779
- img.className = classOf("image", options);
780
- img.src = comp.imageData;
781
- new StyleBag().add("width", "100%").add("height", "100%").add("object-fit", "contain").add("display", "block").applyTo(img);
782
- img.alt = comp.kind;
783
- return img;
784
- }
785
- function renderShape(comp, dpi, options, doc) {
786
- const el = doc.createElement("div");
787
- el.className = classOf("shape", options);
788
- const s = comp.style || {};
789
- const stroke = resolveStroke(s);
790
- const borders = resolveBoxBorders(s);
791
- const border = `${round(stroke.widthPt * dpi / 72, 2)}px solid ${stroke.color}`;
792
- const bag = new StyleBag();
793
- if (comp.grid) {
794
- if (borders.top) bag.add("border-top", border);
795
- if (borders.right) bag.add("border-right", border);
796
- if (borders.bottom) bag.add("border-bottom", border);
797
- if (borders.left) bag.add("border-left", border);
798
- } else if (comp.kind === "rect") {
799
- if (borders.top) bag.add("border-top", border);
800
- if (borders.right) bag.add("border-right", border);
801
- if (borders.bottom) bag.add("border-bottom", border);
802
- if (borders.left) bag.add("border-left", border);
803
- } else if (comp.kind === "ellipse") {
804
- if (borders.inner) bag.add("border", border).add("border-radius", "50%");
805
- if (s.backgroundColor) bag.add("background-color", s.backgroundColor);
806
- } else if (comp.kind === "line") {
807
- bag.add("height", "0").add("border-top", border);
808
- }
809
- bag.add("box-sizing", "border-box").add("width", "100%").add("height", "100%");
810
- bag.applyTo(el);
811
- return el;
812
- }
813
- function renderComponent(comp, dpi, options, doc) {
814
- const wrap = doc.createElement("div");
815
- wrap.className = `${classOf("comp", options)} mr-kind-${comp.kind}`;
816
- const bag = new StyleBag().add("position", "absolute").mm("left", comp.leftMm, dpi).mm("top", comp.topMm, dpi).mm("width", comp.widthMm, dpi).mm("height", comp.heightMm, dpi).add("box-sizing", "border-box");
817
- applyComponentStyle(bag, comp, dpi);
818
- bag.applyTo(wrap);
819
- if (isImageBackedComponent(comp)) {
820
- wrap.appendChild(renderImage(comp, options, doc));
821
- return wrap;
822
- }
823
- if (comp.kind === "text") {
824
- wrap.appendChild(renderText(comp, dpi, options, doc));
825
- return wrap;
826
- }
827
- if (comp.grid) {
828
- const shape = renderShape(comp, dpi, options, doc);
829
- shape.appendChild(renderGrid(comp.grid, comp, dpi, options, doc));
830
- wrap.appendChild(shape);
831
- return wrap;
832
- }
833
- if (comp.kind === "line" || comp.kind === "rect" || comp.kind === "ellipse" || comp.kind === "chart") {
834
- wrap.appendChild(renderShape(comp, dpi, options, doc));
835
- return wrap;
836
- }
837
- const ph = doc.createElement("div");
838
- ph.className = classOf("unknown", options);
839
- ph.textContent = comp.fallbackText ?? "";
840
- wrap.appendChild(ph);
841
- return wrap;
842
- }
843
- function renderPage(page, dpi, options, doc) {
844
- const el = doc.createElement("div");
845
- el.className = classOf("page", options);
846
- new StyleBag().add("position", "relative").mm("width", page.pageWidthMm, dpi).mm("height", page.pageHeightMm, dpi).add("background-color", "#fff").add("overflow", "hidden").add("box-sizing", "border-box").applyTo(el);
847
- for (const comp of page.components) {
848
- el.appendChild(renderComponent(comp, dpi, options, doc));
849
- }
850
- return el;
851
- }
852
- function renderPlan(plan, doc, options = {}) {
853
- const dpi = options.dpi ?? 96;
854
- const root = doc.createElement("div");
855
- root.className = classOf("root", options);
856
- root.dataset.schemaVersion = plan.schemaVersion;
857
- plan.pages.forEach((page) => {
858
- root.appendChild(renderPage(page, dpi, options, doc));
859
- });
860
- return root;
861
- }
862
-
863
- // src/render/window.ts
864
- function computePageWindow(input) {
865
- const { pageHeightsPx, viewportHeightPx, scrollTopPx, overscan = 1, gapPx = 0 } = input;
866
- const n = pageHeightsPx.length;
867
- if (n === 0) {
341
+ o.appendChild(d);
342
+ }
343
+ return r.appendChild(o), r;
344
+ }
345
+ if (Array.isArray(e.lines) && e.lines.length > 0) {
346
+ const o = t.createElement("div");
347
+ o.className = C("lines", i), s.lineHeight != null && new H().add("line-height", String(s.lineHeight)).applyTo(o);
348
+ for (const l of e.lines) {
349
+ const d = t.createElement("div");
350
+ d.className = C("line", i), d.textContent = l, o.appendChild(d);
351
+ }
352
+ return r.appendChild(o), r;
353
+ }
354
+ return r.textContent = e.text ?? "", r;
355
+ }
356
+ function ke(e, n, i) {
357
+ const t = i.createElement("img");
358
+ return t.className = C("image", n), t.src = e.imageData, new H().add("width", "100%").add("height", "100%").add("object-fit", "contain").add("display", "block").applyTo(t), t.alt = e.kind, t;
359
+ }
360
+ function X(e, n, i, t) {
361
+ const r = t.createElement("div");
362
+ r.className = C("shape", i);
363
+ const s = e.style || {}, a = F(s), o = V(s), l = `${_(a.widthPt * n / 72, 2)}px solid ${a.color}`, d = new H();
364
+ return e.grid || e.kind === "rect" ? (o.top && d.add("border-top", l), o.right && d.add("border-right", l), o.bottom && d.add("border-bottom", l), o.left && d.add("border-left", l)) : e.kind === "ellipse" ? (o.inner && d.add("border", l).add("border-radius", "50%"), s.backgroundColor && d.add("background-color", s.backgroundColor)) : e.kind === "line" && d.add("height", "0").add("border-top", l), d.add("box-sizing", "border-box").add("width", "100%").add("height", "100%"), d.applyTo(r), r;
365
+ }
366
+ function ne(e, n, i, t) {
367
+ const r = t.createElement("div");
368
+ r.className = `${C("comp", i)} mr-kind-${e.kind}`;
369
+ const s = new H().add("position", "absolute").mm("left", e.leftMm, n).mm("top", e.topMm, n).mm("width", e.widthMm, n).mm("height", e.heightMm, n).add("box-sizing", "border-box");
370
+ if (te(s, e, n), s.applyTo(r), le(e))
371
+ return r.appendChild(ke(e, i, t)), r;
372
+ if (e.kind === "text")
373
+ return r.appendChild(Ce(e, n, i, t)), r;
374
+ if (e.grid) {
375
+ const o = X(e, n, i, t);
376
+ return o.appendChild(ve(e.grid, e, n, i, t)), r.appendChild(o), r;
377
+ }
378
+ if (e.kind === "line" || e.kind === "rect" || e.kind === "ellipse" || e.kind === "chart")
379
+ return r.appendChild(X(e, n, i, t)), r;
380
+ const a = t.createElement("div");
381
+ return a.className = C("unknown", i), a.textContent = e.fallbackText ?? "", r.appendChild(a), r;
382
+ }
383
+ function xe(e, n, i, t) {
384
+ const r = t.createElement("div");
385
+ r.className = C("page", i), new H().add("position", "relative").mm("width", e.pageWidthMm, n).mm("height", e.pageHeightMm, n).add("background-color", "#fff").add("overflow", "hidden").add("box-sizing", "border-box").applyTo(r);
386
+ for (const s of e.components)
387
+ r.appendChild(ne(s, n, i, t));
388
+ return r;
389
+ }
390
+ function Ie(e, n, i = {}) {
391
+ const t = i.dpi ?? 96, r = n.createElement("div");
392
+ return r.className = C("root", i), r.dataset.schemaVersion = e.schemaVersion, e.pages.forEach((s) => {
393
+ r.appendChild(xe(s, t, i, n));
394
+ }), r;
395
+ }
396
+ function Pe(e) {
397
+ const { pageHeightsPx: n, viewportHeightPx: i, scrollTopPx: t, overscan: r = 1, gapPx: s = 0 } = e, a = n.length;
398
+ if (a === 0)
868
399
  return { start: 0, end: -1, padTopPx: 0, padBottomPx: 0 };
869
- }
870
- const gap = Math.max(0, gapPx);
871
- const offsets = new Array(n + 1);
872
- offsets[0] = 0;
873
- for (let i = 0; i < n; i++) {
874
- offsets[i + 1] = offsets[i] + Math.max(0, pageHeightsPx[i] ?? 0) + gap;
875
- }
876
- const total = offsets[n];
877
- const top = Math.max(0, scrollTopPx);
878
- let cover = 0;
879
- let lo = 0;
880
- let hi = n - 1;
881
- while (lo <= hi) {
882
- const mid = lo + hi >> 1;
883
- if (offsets[mid] <= top) {
884
- cover = mid;
885
- lo = mid + 1;
886
- } else {
887
- hi = mid - 1;
888
- }
889
- }
890
- const start = Math.max(0, Math.min(n - 1, cover - overscan));
891
- const target = offsets[cover] + Math.max(0, viewportHeightPx);
892
- let visibleEnd = n - 1;
893
- lo = 0;
894
- hi = n - 1;
895
- while (lo <= hi) {
896
- const mid = lo + hi >> 1;
897
- if (offsets[mid + 1] < target) {
898
- lo = mid + 1;
899
- } else {
900
- visibleEnd = mid;
901
- hi = mid - 1;
902
- }
903
- }
904
- const end = Math.min(n - 1, visibleEnd + overscan);
905
- const padTopPx = offsets[start];
906
- const padBottomPx = Math.max(0, total - offsets[end + 1]);
907
- return { start, end, padTopPx, padBottomPx };
908
- }
909
-
910
- // src/render/canvas.ts
911
- var PX_PER_MM_BASE = 96 / 25.4;
912
- function measurePageSizePx(page, dpi = 96) {
913
- const pxPerMm = dpi / 96 * PX_PER_MM_BASE;
400
+ const o = Math.max(0, s), l = new Array(a + 1);
401
+ l[0] = 0;
402
+ for (let w = 0; w < a; w++)
403
+ l[w + 1] = l[w] + Math.max(0, n[w] ?? 0) + o;
404
+ const d = l[a], h = Math.max(0, t);
405
+ let c = 0, m = 0, u = a - 1;
406
+ for (; m <= u; ) {
407
+ const w = m + u >> 1;
408
+ l[w] <= h ? (c = w, m = w + 1) : u = w - 1;
409
+ }
410
+ const g = Math.max(0, Math.min(a - 1, c - r)), M = l[c] + Math.max(0, i);
411
+ let p = a - 1;
412
+ for (m = 0, u = a - 1; m <= u; ) {
413
+ const w = m + u >> 1;
414
+ l[w + 1] < M ? m = w + 1 : (p = w, u = w - 1);
415
+ }
416
+ const k = Math.min(a - 1, p + r), T = l[g], E = Math.max(0, d - l[k + 1]);
417
+ return { start: g, end: k, padTopPx: T, padBottomPx: E };
418
+ }
419
+ const U = 96 / 25.4;
420
+ function ie(e, n = 96) {
421
+ const i = n / 96 * U;
914
422
  return {
915
- widthPx: Math.max(1, Math.round(page.pageWidthMm * pxPerMm)),
916
- heightPx: Math.max(1, Math.round(page.pageHeightMm * pxPerMm))
423
+ widthPx: Math.max(1, Math.round(e.pageWidthMm * i)),
424
+ heightPx: Math.max(1, Math.round(e.pageHeightMm * i))
917
425
  };
918
426
  }
919
- function createPageCanvas(page, dpr, dpi) {
920
- const canvas = document.createElement("canvas");
921
- const { widthPx: w, heightPx: h } = measurePageSizePx(page, dpi);
922
- canvas.width = Math.round(w * dpr);
923
- canvas.height = Math.round(h * dpr);
924
- canvas.style.width = `${w}px`;
925
- canvas.style.height = `${h}px`;
926
- const ctx = canvas.getContext("2d");
927
- if (!ctx) {
928
- throw new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 Canvas 2D\uFF08\u6D4B\u8BD5\u9700\u771F\u6D4F\u89C8\u5668\uFF0C\u89C1 e2e/canvas.spec.ts\uFF09");
929
- }
930
- ctx.scale(dpr, dpr);
931
- ctx.fillStyle = "#ffffff";
932
- ctx.fillRect(0, 0, w, h);
933
- return { canvas, ctx };
934
- }
935
- function planFontSizePx(style, dpi = 96) {
936
- return resolveFontSize(style, dpi).fontSizePx;
937
- }
938
- function drawTextBlock(ctx, spec, x, y, w, h, fontFamily, verticalAlign = "top") {
939
- ctx.font = `${spec.bold ? "bold " : ""}${spec.fontSizePx}px ${fontFamily}`;
940
- ctx.fillStyle = spec.color;
941
- ctx.textBaseline = "alphabetic";
942
- const lineH = spec.fontSizePx * spec.lineHeight;
943
- const lines = spec.text === "" ? [""] : spec.text.split("\n");
944
- const totalH = lines.length * lineH;
945
- let topY = y;
946
- if (verticalAlign === "middle") topY = y + (h - totalH) / 2;
947
- else if (verticalAlign === "bottom") topY = y + h - totalH;
948
- lines.forEach((line, i) => {
949
- ctx.textAlign = spec.align === "center" ? "center" : spec.align === "right" ? "right" : "left";
950
- const tx = spec.align === "center" ? x + w / 2 : spec.align === "right" ? x + w : x;
951
- ctx.fillText(line, tx, topY + i * lineH + spec.fontSizePx * 0.8, w);
952
- });
953
- ctx.textAlign = "left";
954
- }
955
- function drawGrid(ctx, grid, comp, x, y, w, h, pxPerMm, dpi, fontFamily, measurer) {
956
- const layout = resolveGridLayout(grid, w / pxPerMm, h / pxPerMm);
957
- const borders = resolveBoxBorders(comp.style);
958
- const stroke = resolveStroke(comp.style);
959
- for (const box of layout.cells) {
960
- const bg = box.cell.style?.backgroundColor;
961
- if (bg) {
962
- ctx.fillStyle = bg;
963
- ctx.fillRect(
964
- x + box.xMm * pxPerMm,
965
- y + box.yMm * pxPerMm,
966
- box.widthMm * pxPerMm,
967
- box.heightMm * pxPerMm
968
- );
969
- }
970
- }
971
- if (borders.inner) {
972
- ctx.strokeStyle = stroke.color;
973
- ctx.lineWidth = ptToPx(stroke.widthPt, dpi);
974
- for (const e of layout.edges) {
975
- ctx.beginPath();
976
- if (e.kind === "v") {
977
- ctx.moveTo(x + e.pos * pxPerMm, y + e.from * pxPerMm);
978
- ctx.lineTo(x + e.pos * pxPerMm, y + e.to * pxPerMm);
979
- } else {
980
- ctx.moveTo(x + e.from * pxPerMm, y + e.pos * pxPerMm);
981
- ctx.lineTo(x + e.to * pxPerMm, y + e.pos * pxPerMm);
982
- }
983
- ctx.stroke();
984
- }
985
- ctx.beginPath();
986
- if (borders.top) {
987
- ctx.moveTo(x, y);
988
- ctx.lineTo(x + w, y);
989
- }
990
- if (borders.right) {
991
- ctx.moveTo(x + w, y);
992
- ctx.lineTo(x + w, y + h);
993
- }
994
- if (borders.bottom) {
995
- ctx.moveTo(x + w, y + h);
996
- ctx.lineTo(x, y + h);
997
- }
998
- if (borders.left) {
999
- ctx.moveTo(x, y + h);
1000
- ctx.lineTo(x, y);
1001
- }
1002
- ctx.stroke();
1003
- }
1004
- for (const box of layout.cells) {
1005
- const text = typeof box.cell.text === "string" ? box.cell.text : "";
1006
- if (!text) continue;
1007
- const st = box.cell.style;
1008
- const fontSizePt = st?.fontSize ?? DEFAULT_FONT_PT;
1009
- const lines = wrapText(
1010
- text,
1011
- box.widthMm - 1,
1012
- { fontSizePt },
1013
- measurer
1014
- ).join("\n");
1015
- drawTextBlock(
1016
- ctx,
427
+ function Ae(e, n, i) {
428
+ const t = document.createElement("canvas"), { widthPx: r, heightPx: s } = ie(e, i);
429
+ t.width = Math.round(r * n), t.height = Math.round(s * n), t.style.width = `${r}px`, t.style.height = `${s}px`;
430
+ const a = t.getContext("2d");
431
+ if (!a)
432
+ throw new Error("当前环境不支持 Canvas 2D(测试需真浏览器,见 e2e/canvas.spec.ts)");
433
+ return a.scale(n, n), a.fillStyle = "#ffffff", a.fillRect(0, 0, r, s), { canvas: t, ctx: a };
434
+ }
435
+ function De(e, n = 96) {
436
+ return W(e, n).fontSizePx;
437
+ }
438
+ function re(e, n, i, t, r, s, a, o = "top") {
439
+ e.font = `${n.bold ? "bold " : ""}${n.fontSizePx}px ${a}`, e.fillStyle = n.color, e.textBaseline = "alphabetic";
440
+ const l = n.fontSizePx * n.lineHeight, d = n.text === "" ? [""] : n.text.split(`
441
+ `), h = d.length * l;
442
+ let c = t;
443
+ o === "middle" ? c = t + (s - h) / 2 : o === "bottom" && (c = t + s - h), d.forEach((m, u) => {
444
+ e.textAlign = n.align === "center" ? "center" : n.align === "right" ? "right" : "left";
445
+ const g = n.align === "center" ? i + r / 2 : n.align === "right" ? i + r : i;
446
+ e.fillText(m, g, c + u * l + n.fontSizePx * 0.8, r);
447
+ }), e.textAlign = "left";
448
+ }
449
+ function Ee(e, n, i, t, r, s, a, o, l, d, h) {
450
+ const c = ce(n, s / o, a / o), m = V(i.style), u = F(i.style);
451
+ for (const g of c.cells) {
452
+ const M = g.cell.style?.backgroundColor;
453
+ M && (e.fillStyle = M, e.fillRect(
454
+ t + g.xMm * o,
455
+ r + g.yMm * o,
456
+ g.widthMm * o,
457
+ g.heightMm * o
458
+ ));
459
+ }
460
+ if (m.inner) {
461
+ e.strokeStyle = u.color, e.lineWidth = O(u.widthPt, l);
462
+ for (const g of c.edges)
463
+ e.beginPath(), g.kind === "v" ? (e.moveTo(t + g.pos * o, r + g.from * o), e.lineTo(t + g.pos * o, r + g.to * o)) : (e.moveTo(t + g.from * o, r + g.pos * o), e.lineTo(t + g.to * o, r + g.pos * o)), e.stroke();
464
+ e.beginPath(), m.top && (e.moveTo(t, r), e.lineTo(t + s, r)), m.right && (e.moveTo(t + s, r), e.lineTo(t + s, r + a)), m.bottom && (e.moveTo(t + s, r + a), e.lineTo(t, r + a)), m.left && (e.moveTo(t, r + a), e.lineTo(t, r)), e.stroke();
465
+ }
466
+ for (const g of c.cells) {
467
+ const M = typeof g.cell.text == "string" ? g.cell.text : "";
468
+ if (!M) continue;
469
+ const p = g.cell.style, k = p?.fontSize ?? j, T = G(
470
+ M,
471
+ g.widthMm - 1,
472
+ { fontSizePt: k },
473
+ h
474
+ ).join(`
475
+ `);
476
+ re(
477
+ e,
1017
478
  {
1018
- text: lines,
1019
- fontSizePx: resolveFontSize(st, dpi).fontSizePx,
1020
- bold: st?.bold ?? false,
1021
- color: st?.color ?? resolveTextColor(comp.style, DEFAULT_TEXT_COLOR),
1022
- align: st?.align ?? "left",
1023
- lineHeight: LINE_HEIGHT
479
+ text: T,
480
+ fontSizePx: W(p, l).fontSizePx,
481
+ bold: p?.bold ?? !1,
482
+ color: p?.color ?? Q(i.style, me),
483
+ align: p?.align ?? "left",
484
+ lineHeight: q
1024
485
  },
1025
- x + (box.xMm + 0.5) * pxPerMm,
1026
- y + box.yMm * pxPerMm,
1027
- Math.max(0, (box.widthMm - 1) * pxPerMm),
1028
- box.heightMm * pxPerMm,
1029
- fontFamily,
1030
- st?.verticalAlign ?? "middle"
486
+ t + (g.xMm + 0.5) * o,
487
+ r + g.yMm * o,
488
+ Math.max(0, (g.widthMm - 1) * o),
489
+ g.heightMm * o,
490
+ d,
491
+ p?.verticalAlign ?? "middle"
1031
492
  );
1032
493
  }
1033
494
  }
1034
- function drawComponent(ctx, comp, pxPerMm, dpi, fontFamily, measurer) {
1035
- const x = comp.leftMm * pxPerMm;
1036
- const y = comp.topMm * pxPerMm;
1037
- const w = comp.widthMm * pxPerMm;
1038
- const h = comp.heightMm * pxPerMm;
1039
- const s = comp.style ?? {};
1040
- if (comp.grid) {
1041
- drawGrid(ctx, comp.grid, comp, x, y, w, h, pxPerMm, dpi, fontFamily, measurer);
495
+ function oe(e, n, i, t, r, s) {
496
+ const a = n.leftMm * i, o = n.topMm * i, l = n.widthMm * i, d = n.heightMm * i, h = n.style ?? {};
497
+ if (n.grid) {
498
+ Ee(e, n.grid, n, a, o, l, d, i, t, r, s);
1042
499
  return;
1043
500
  }
1044
- switch (comp.kind) {
501
+ switch (n.kind) {
1045
502
  case "text": {
1046
- const fontSizePt = s.fontSize ?? DEFAULT_FONT_PT;
1047
- const text = isRichText(comp) ? comp.richParagraphs.map((p) => (p.segments ?? []).map((seg) => seg.text ?? seg.field ?? "").join("")).join("\n") : Array.isArray(comp.lines) && comp.lines.length > 0 ? comp.lines.join("\n") : wrapText(comp.text ?? "", comp.widthMm, { fontSizePt }, measurer).join("\n");
1048
- drawTextBlock(
1049
- ctx,
503
+ const c = h.fontSize ?? j, m = Z(n) ? n.richParagraphs.map((u) => (u.segments ?? []).map((g) => g.text ?? g.field ?? "").join("")).join(`
504
+ `) : Array.isArray(n.lines) && n.lines.length > 0 ? n.lines.join(`
505
+ `) : G(n.text ?? "", n.widthMm, { fontSizePt: c }, s).join(`
506
+ `);
507
+ re(
508
+ e,
1050
509
  {
1051
- text,
1052
- fontSizePx: resolveFontSize(s, dpi).fontSizePx,
1053
- bold: s.bold ?? false,
1054
- color: resolveTextColor(s),
1055
- align: s.align ?? "left",
1056
- lineHeight: resolveLineHeight(s)
510
+ text: m,
511
+ fontSizePx: W(h, t).fontSizePx,
512
+ bold: h.bold ?? !1,
513
+ color: Q(h),
514
+ align: h.align ?? "left",
515
+ lineHeight: he(h)
1057
516
  },
1058
- x,
1059
- y,
1060
- w,
1061
- h,
1062
- fontFamily,
1063
- s.verticalAlign
517
+ a,
518
+ o,
519
+ l,
520
+ d,
521
+ r,
522
+ h.verticalAlign
1064
523
  );
1065
524
  break;
1066
525
  }
1067
526
  case "rect": {
1068
- const stroke = resolveStroke(s);
1069
- const borders = resolveBoxBorders(s);
1070
- if (s.backgroundColor) {
1071
- ctx.fillStyle = s.backgroundColor;
1072
- ctx.fillRect(x, y, w, h);
1073
- }
1074
- if (borders.inner) {
1075
- ctx.strokeStyle = stroke.color;
1076
- ctx.lineWidth = ptToPx(stroke.widthPt, dpi);
1077
- ctx.beginPath();
1078
- if (borders.top) {
1079
- ctx.moveTo(x, y);
1080
- ctx.lineTo(x + w, y);
1081
- }
1082
- if (borders.right) {
1083
- ctx.moveTo(x + w, y);
1084
- ctx.lineTo(x + w, y + h);
1085
- }
1086
- if (borders.bottom) {
1087
- ctx.moveTo(x + w, y + h);
1088
- ctx.lineTo(x, y + h);
1089
- }
1090
- if (borders.left) {
1091
- ctx.moveTo(x, y + h);
1092
- ctx.lineTo(x, y);
1093
- }
1094
- ctx.stroke();
1095
- }
527
+ const c = F(h), m = V(h);
528
+ h.backgroundColor && (e.fillStyle = h.backgroundColor, e.fillRect(a, o, l, d)), m.inner && (e.strokeStyle = c.color, e.lineWidth = O(c.widthPt, t), e.beginPath(), m.top && (e.moveTo(a, o), e.lineTo(a + l, o)), m.right && (e.moveTo(a + l, o), e.lineTo(a + l, o + d)), m.bottom && (e.moveTo(a + l, o + d), e.lineTo(a, o + d)), m.left && (e.moveTo(a, o + d), e.lineTo(a, o)), e.stroke());
1096
529
  break;
1097
530
  }
1098
531
  case "line": {
1099
- const stroke = resolveStroke({ ...s, borderColor: s.lineColor ?? s.borderColor });
1100
- ctx.strokeStyle = stroke.color;
1101
- ctx.lineWidth = ptToPx(stroke.widthPt, dpi);
1102
- ctx.beginPath();
1103
- ctx.moveTo(x, y + h / 2);
1104
- ctx.lineTo(x + w, y + h / 2);
1105
- ctx.stroke();
532
+ const c = F({ ...h, borderColor: h.lineColor ?? h.borderColor });
533
+ e.strokeStyle = c.color, e.lineWidth = O(c.widthPt, t), e.beginPath(), e.moveTo(a, o + d / 2), e.lineTo(a + l, o + d / 2), e.stroke();
1106
534
  break;
1107
535
  }
1108
536
  case "ellipse": {
1109
- const stroke = resolveStroke(s);
1110
- ctx.strokeStyle = stroke.color;
1111
- ctx.lineWidth = ptToPx(stroke.widthPt, dpi);
1112
- if (s.backgroundColor) {
1113
- ctx.fillStyle = s.backgroundColor;
1114
- ctx.beginPath();
1115
- ctx.ellipse(x + w / 2, y + h / 2, w / 2, h / 2, 0, 0, Math.PI * 2);
1116
- ctx.fill();
1117
- }
1118
- ctx.beginPath();
1119
- ctx.ellipse(x + w / 2, y + h / 2, w / 2, h / 2, 0, 0, Math.PI * 2);
1120
- ctx.stroke();
537
+ const c = F(h);
538
+ e.strokeStyle = c.color, e.lineWidth = O(c.widthPt, t), h.backgroundColor && (e.fillStyle = h.backgroundColor, e.beginPath(), e.ellipse(a + l / 2, o + d / 2, l / 2, d / 2, 0, 0, Math.PI * 2), e.fill()), e.beginPath(), e.ellipse(a + l / 2, o + d / 2, l / 2, d / 2, 0, 0, Math.PI * 2), e.stroke();
1121
539
  break;
1122
540
  }
1123
541
  }
1124
542
  }
1125
- function renderPlanToCanvas(plan, options = {}) {
1126
- const dpr = options.dpr ?? (typeof devicePixelRatio === "number" ? devicePixelRatio : 1);
1127
- const dpi = options.dpi ?? 96;
1128
- const pxPerMm = dpi / 96 * PX_PER_MM_BASE;
1129
- const fontFamily = options.fontFamily ?? '"Microsoft YaHei", sans-serif';
1130
- const measurer = options.measurer ?? heuristicMeasurer;
1131
- const start = Math.max(0, options.start ?? 0);
1132
- const end = Math.min(plan.pages.length - 1, options.end ?? plan.pages.length - 1);
1133
- const canvases = [];
1134
- for (let i = start; i <= end; i++) {
1135
- const page = plan.pages[i];
1136
- const { canvas, ctx } = createPageCanvas(page, dpr, dpi);
1137
- for (const comp of page.components) {
1138
- drawComponent(ctx, comp, pxPerMm, dpi, fontFamily, measurer);
1139
- }
1140
- canvases.push(canvas);
1141
- }
1142
- return { canvases };
1143
- }
1144
- function createCanvasPager(plan, options = {}) {
1145
- const dpr = options.dpr ?? (typeof devicePixelRatio === "number" ? devicePixelRatio : 1);
1146
- const dpi = options.dpi ?? 96;
1147
- const pxPerMm = dpi / 96 * PX_PER_MM_BASE;
1148
- const fontFamily = options.fontFamily ?? '"Microsoft YaHei", sans-serif';
1149
- const measurer = options.measurer ?? heuristicMeasurer;
1150
- const overscan = options.overscan ?? 1;
1151
- const gapPx = options.gapPx ?? 18;
1152
- const pagesPerFrame = options.pagesPerFrame ?? 1;
1153
- const pageHeightsPx = plan.pages.map((p) => p.pageHeightMm * pxPerMm);
1154
- const maxPageWidthPx = Math.max(1, ...plan.pages.map((p) => p.pageWidthMm * pxPerMm));
1155
- const windowState = { start: 0, end: -1 };
1156
- let viewport = null;
1157
- let contentEl = null;
1158
- let topSpacer = null;
1159
- let bottomSpacer = null;
1160
- let slots = [];
1161
- let raf = 0;
1162
- let queued = [];
1163
- function ensureLayout() {
1164
- const vp = viewport;
1165
- vp.innerHTML = "";
1166
- contentEl = document.createElement("div");
1167
- contentEl.style.cssText = `width:${maxPageWidthPx}px;margin:0 auto;`;
1168
- topSpacer = document.createElement("div");
1169
- bottomSpacer = document.createElement("div");
1170
- contentEl.appendChild(topSpacer);
1171
- slots = [];
1172
- const slotCount = Math.min(plan.pages.length, 3 + overscan * 2);
1173
- for (let i = 0; i < slotCount; i++) {
1174
- const slot = document.createElement("div");
1175
- slot.style.cssText = `margin:0 auto ${gapPx}px;box-shadow:0 2px 8px rgba(0,0,0,.35);background:#fff;`;
1176
- contentEl.appendChild(slot);
1177
- slots.push(slot);
1178
- }
1179
- contentEl.appendChild(bottomSpacer);
1180
- vp.appendChild(contentEl);
1181
- }
1182
- function drawPageInto(slot, pageIndex) {
1183
- const page = plan.pages[pageIndex];
1184
- const { widthPx: w, heightPx: h } = measurePageSizePx(page, dpi);
1185
- let canvas = slot.firstElementChild;
1186
- if (!canvas || canvas.tagName !== "CANVAS") {
1187
- canvas = document.createElement("canvas");
1188
- slot.innerHTML = "";
1189
- slot.appendChild(canvas);
1190
- }
1191
- canvas.width = Math.round(w * dpr);
1192
- canvas.height = Math.round(h * dpr);
1193
- canvas.style.width = `${w}px`;
1194
- canvas.style.height = `${h}px`;
1195
- const ctx = canvas.getContext("2d");
1196
- if (!ctx) return;
1197
- ctx.setTransform(1, 0, 0, 1, 0, 0);
1198
- ctx.scale(dpr, dpr);
1199
- ctx.fillStyle = "#ffffff";
1200
- ctx.fillRect(0, 0, w, h);
1201
- for (const comp of page.components) {
1202
- drawComponent(ctx, comp, pxPerMm, dpi, fontFamily, measurer);
1203
- }
1204
- canvas.dataset.canvasPage = String(pageIndex);
1205
- slot.style.height = `${h}px`;
1206
- slot.style.width = `${w}px`;
1207
- }
1208
- function applyWindow(win) {
1209
- windowState.start = win.start;
1210
- windowState.end = win.end;
1211
- topSpacer.style.height = `${win.start * gapPx + pageHeightsPx.slice(0, win.start).reduce((s, h) => s + h, 0)}px`;
1212
- const below = plan.pages.length - 1 - win.end;
1213
- bottomSpacer.style.height = `${below * gapPx + pageHeightsPx.slice(win.end + 1).reduce((s, h) => s + h, 0)}px`;
1214
- const used = win.end - win.start + 1;
1215
- slots.forEach((slot, i) => {
1216
- if (i < used) {
1217
- slot.style.display = "";
1218
- const pageIndex = win.start + i;
1219
- slot.style.height = `${pageHeightsPx[pageIndex] ?? 0}px`;
1220
- } else {
1221
- slot.style.display = "none";
543
+ function Oe(e, n = {}) {
544
+ if (typeof document > "u")
545
+ throw new Error("renderPlanToCanvas 需要浏览器环境(SSR 请在客户端钩子中调用)");
546
+ const i = n.dpr ?? (typeof devicePixelRatio == "number" ? devicePixelRatio : 1), t = n.dpi ?? 96, r = t / 96 * U, s = n.fontFamily ?? '"Microsoft YaHei", sans-serif', a = n.measurer ?? J, o = Math.max(0, n.start ?? 0), l = Math.min(e.pages.length - 1, n.end ?? e.pages.length - 1), d = [];
547
+ for (let h = o; h <= l; h++) {
548
+ const c = e.pages[h], { canvas: m, ctx: u } = Ae(c, i, t);
549
+ for (const g of c.components)
550
+ oe(u, g, r, t, s, a);
551
+ d.push(m);
552
+ }
553
+ return { canvases: d };
554
+ }
555
+ function je(e, n = {}) {
556
+ const i = n.dpr ?? (typeof devicePixelRatio == "number" ? devicePixelRatio : 1), t = n.dpi ?? 96, r = t / 96 * U, s = n.fontFamily ?? '"Microsoft YaHei", sans-serif', a = n.measurer ?? J, o = n.overscan ?? 1, l = n.gapPx ?? 18, d = n.pagesPerFrame ?? 1, h = e.pages.map((f) => f.pageHeightMm * r), c = Math.max(1, ...e.pages.map((f) => f.pageWidthMm * r)), m = { start: 0, end: -1 };
557
+ let u = null, g = null, M = null, p = null, k = [], T = 0, E = [];
558
+ function w() {
559
+ const f = u;
560
+ f.innerHTML = "", g = document.createElement("div"), g.style.cssText = `width:${c}px;margin:0 auto;`, M = document.createElement("div"), p = document.createElement("div"), g.appendChild(M), k = [];
561
+ const b = Math.min(e.pages.length, 3 + o * 2);
562
+ for (let P = 0; P < b; P++) {
563
+ const y = document.createElement("div");
564
+ y.style.cssText = `margin:0 auto ${l}px;box-shadow:0 2px 8px rgba(0,0,0,.35);background:#fff;`, g.appendChild(y), k.push(y);
565
+ }
566
+ g.appendChild(p), f.appendChild(g);
567
+ }
568
+ function I(f, b) {
569
+ const P = e.pages[b], { widthPx: y, heightPx: x } = ie(P, t);
570
+ let A = f.firstElementChild;
571
+ (!A || A.tagName !== "CANVAS") && (A = document.createElement("canvas"), f.innerHTML = "", f.appendChild(A)), A.width = Math.round(y * i), A.height = Math.round(x * i), A.style.width = `${y}px`, A.style.height = `${x}px`;
572
+ const z = A.getContext("2d");
573
+ if (z) {
574
+ z.setTransform(1, 0, 0, 1, 0, 0), z.scale(i, i), z.fillStyle = "#ffffff", z.fillRect(0, 0, y, x);
575
+ for (const ae of P.components)
576
+ oe(z, ae, r, t, s, a);
577
+ A.dataset.canvasPage = String(b), f.style.height = `${x}px`, f.style.width = `${y}px`;
578
+ }
579
+ }
580
+ function R(f) {
581
+ m.start = f.start, m.end = f.end, M.style.height = `${f.start * l + h.slice(0, f.start).reduce((y, x) => y + x, 0)}px`;
582
+ const b = e.pages.length - 1 - f.end;
583
+ p.style.height = `${b * l + h.slice(f.end + 1).reduce((y, x) => y + x, 0)}px`;
584
+ const P = f.end - f.start + 1;
585
+ k.forEach((y, x) => {
586
+ if (x < P) {
587
+ y.style.display = "";
588
+ const A = f.start + x;
589
+ y.style.height = `${h[A] ?? 0}px`;
590
+ } else
591
+ y.style.display = "none";
592
+ }), E = [];
593
+ for (let y = f.start; y <= f.end; y++) {
594
+ const x = k[y - f.start];
595
+ if (!x) continue;
596
+ x.firstElementChild?.dataset?.canvasPage !== String(y) && E.push(y);
597
+ }
598
+ D();
599
+ }
600
+ function D() {
601
+ T || E.length === 0 || (T = requestAnimationFrame(() => {
602
+ T = 0;
603
+ let f = Math.max(1, d);
604
+ for (; E.length > 0 && f-- > 0; ) {
605
+ const b = E.shift(), P = k[b - m.start];
606
+ P && I(P, b);
1222
607
  }
1223
- });
1224
- queued = [];
1225
- for (let i = win.start; i <= win.end; i++) {
1226
- const slot = slots[i - win.start];
1227
- if (!slot) continue;
1228
- const already = slot.firstElementChild;
1229
- if (already?.dataset?.canvasPage !== String(i)) queued.push(i);
1230
- }
1231
- scheduleFrame();
1232
- }
1233
- function scheduleFrame() {
1234
- if (raf || queued.length === 0) return;
1235
- raf = requestAnimationFrame(() => {
1236
- raf = 0;
1237
- let budget = Math.max(1, pagesPerFrame);
1238
- while (queued.length > 0 && budget-- > 0) {
1239
- const pageIndex = queued.shift();
1240
- const slot = slots[pageIndex - windowState.start];
1241
- if (slot) drawPageInto(slot, pageIndex);
1242
- }
1243
- if (queued.length > 0) scheduleFrame();
1244
- });
1245
- }
1246
- function onScroll() {
1247
- if (raf) return;
1248
- raf = requestAnimationFrame(() => {
1249
- raf = 0;
1250
- const vp = viewport;
1251
- const win = computePageWindow({
1252
- pageHeightsPx,
1253
- viewportHeightPx: vp.clientHeight,
1254
- scrollTopPx: vp.scrollTop,
1255
- overscan,
1256
- gapPx
608
+ E.length > 0 && D();
609
+ }));
610
+ }
611
+ function $() {
612
+ T || (T = requestAnimationFrame(() => {
613
+ T = 0;
614
+ const f = u, b = Pe({
615
+ pageHeightsPx: h,
616
+ viewportHeightPx: f.clientHeight,
617
+ scrollTopPx: f.scrollTop,
618
+ overscan: o,
619
+ gapPx: l
1257
620
  });
1258
- if (win.start !== windowState.start || win.end !== windowState.end) {
1259
- applyWindow(win);
1260
- } else {
1261
- scheduleFrame();
1262
- }
1263
- });
621
+ b.start !== m.start || b.end !== m.end ? R(b) : D();
622
+ }));
1264
623
  }
624
+ let B = null;
1265
625
  return {
1266
- attach(vp) {
1267
- viewport = vp;
1268
- ensureLayout();
1269
- vp.addEventListener("scroll", onScroll, { passive: true });
1270
- onScroll();
626
+ attach(f) {
627
+ if (typeof document > "u")
628
+ throw new Error("createCanvasPager 需要浏览器环境(SSR 请在客户端钩子中调用 attach)");
629
+ u = f, w(), f.addEventListener("scroll", $, { passive: !0 }), typeof ResizeObserver < "u" && (B = new ResizeObserver(() => $()), B.observe(f)), $();
1271
630
  },
1272
631
  destroy() {
1273
- if (raf) cancelAnimationFrame(raf);
1274
- raf = 0;
1275
- viewport?.removeEventListener("scroll", onScroll);
1276
- queued = [];
1277
- contentEl?.remove();
1278
- viewport = null;
632
+ T && cancelAnimationFrame(T), T = 0, B?.disconnect(), B = null, u?.removeEventListener("scroll", $), E = [], g?.remove(), u = null;
1279
633
  },
1280
634
  window() {
1281
- return { ...windowState };
635
+ return { ...m };
1282
636
  }
1283
637
  };
1284
638
  }
1285
-
1286
- // src/compat/jh4j-template.ts
1287
- function num(v, fallback) {
1288
- return typeof v === "number" && Number.isFinite(v) ? v : fallback;
639
+ function S(e, n) {
640
+ return typeof e == "number" && Number.isFinite(e) ? e : n;
1289
641
  }
1290
- function str(v, fallback = "") {
1291
- return typeof v === "string" ? v : fallback;
642
+ function v(e, n = "") {
643
+ return typeof e == "string" ? e : n;
1292
644
  }
1293
- function isRaw(v) {
1294
- return typeof v === "object" && v !== null && !Array.isArray(v);
645
+ function N(e) {
646
+ return typeof e == "object" && e !== null && !Array.isArray(e);
1295
647
  }
1296
- function mapAlign(h) {
1297
- if (h === "Center") return "center";
1298
- if (h === "Right") return "right";
1299
- return "left";
648
+ function $e(e) {
649
+ return e === "Center" ? "center" : e === "Right" ? "right" : "left";
1300
650
  }
1301
- function mapVAlign(v) {
1302
- if (v === "Center") return "middle";
1303
- if (v === "Bottom") return "bottom";
1304
- return "top";
651
+ function He(e) {
652
+ return e === "Center" ? "middle" : e === "Bottom" ? "bottom" : "top";
1305
653
  }
1306
- function baseStyle(node) {
1307
- const fontSize = parseFloat(str(node["FontSize"], "10.5"));
654
+ function Re(e) {
655
+ const n = parseFloat(v(e.FontSize, "10.5"));
1308
656
  return {
1309
- fontSize: Number.isFinite(fontSize) ? fontSize : 10.5,
1310
- fontFamily: str(node["FontFamily"], "\u9ED1\u4F53") || void 0,
1311
- bold: str(node["FontWeight"]) === "bold" || void 0,
1312
- italic: str(node["FontStyle"]) === "italic" || void 0,
1313
- underline: node["Underline"] === true || void 0,
1314
- color: str(node["FontColor"]) || void 0,
1315
- backgroundColor: str(node["BackgroundColor"]) || void 0,
1316
- align: mapAlign(str(node["HorAlignment"], "Left")),
1317
- verticalAlign: mapVAlign(str(node["VertAlignment"], "Top")),
657
+ fontSize: Number.isFinite(n) ? n : 10.5,
658
+ fontFamily: v(e.FontFamily, "黑体") || void 0,
659
+ bold: v(e.FontWeight) === "bold" || void 0,
660
+ italic: v(e.FontStyle) === "italic" || void 0,
661
+ underline: e.Underline === !0 || void 0,
662
+ color: v(e.FontColor) || void 0,
663
+ backgroundColor: v(e.BackgroundColor) || void 0,
664
+ align: $e(v(e.HorAlignment, "Left")),
665
+ verticalAlign: He(v(e.VertAlignment, "Top")),
1318
666
  lineHeight: (() => {
1319
- const lh = parseFloat(str(node["RowSpace"], "1"));
1320
- return Number.isFinite(lh) && lh !== 1 ? lh : void 0;
667
+ const i = parseFloat(v(e.RowSpace, "1"));
668
+ return Number.isFinite(i) && i !== 1 ? i : void 0;
1321
669
  })(),
1322
- borderColor: str(node["BorderColor"]) || void 0,
1323
- borderTop: node["BorderTop"] !== false,
1324
- borderRight: node["BorderRight"] !== false,
1325
- borderBottom: node["BorderBottom"] !== false,
1326
- borderLeft: node["BorderLeft"] !== false
670
+ borderColor: v(e.BorderColor) || void 0,
671
+ borderTop: e.BorderTop !== !1,
672
+ borderRight: e.BorderRight !== !1,
673
+ borderBottom: e.BorderBottom !== !1,
674
+ borderLeft: e.BorderLeft !== !1
1327
675
  };
1328
676
  }
1329
- function convertElement(node, warnings) {
1330
- const uitype = str(node["uitype"]);
1331
- const comp = {
677
+ function Be(e, n) {
678
+ const i = v(e.uitype), t = {
1332
679
  kind: "text",
1333
- leftMm: num(node["left"], 0),
1334
- topMm: num(node["top"], 0),
1335
- widthMm: num(node["width"], 40),
1336
- heightMm: num(node["height"], 8),
1337
- nid: str(node["nid"]) || void 0,
1338
- style: baseStyle(node)
680
+ leftMm: S(e.left, 0),
681
+ topMm: S(e.top, 0),
682
+ widthMm: S(e.width, 40),
683
+ heightMm: S(e.height, 8),
684
+ nid: v(e.nid) || void 0,
685
+ style: Re(e)
1339
686
  };
1340
- switch (uitype) {
687
+ switch (i) {
1341
688
  case "text": {
1342
- comp.kind = "text";
1343
- const text = node["Text"] ?? node["text"] ?? node["Value"];
1344
- comp.text = text == null ? "" : String(text);
1345
- const lines = node["Lines"] ?? node["lines"];
1346
- if (Array.isArray(lines)) {
1347
- comp.lines = lines.map((l) => String(l));
1348
- }
1349
- return comp;
689
+ t.kind = "text";
690
+ const r = e.Text ?? e.text ?? e.Value;
691
+ t.text = r == null ? "" : String(r);
692
+ const s = e.Lines ?? e.lines;
693
+ return Array.isArray(s) && (t.lines = s.map((a) => String(a))), t;
1350
694
  }
1351
695
  case "richtext":
1352
- comp.kind = "text";
1353
- comp.text = str(node["Text"]);
1354
- warnings.push(`\u5BCC\u6587\u672C ${comp.nid ?? ""} \u5BFC\u5165\u4E3A\u7EAF\u6587\u672C\uFF08\u7248\u5F0F\u7EC6\u8282\u53EF\u80FD\u635F\u5931\uFF09`);
1355
- return comp;
696
+ return t.kind = "text", t.text = v(e.Text), n.push(`富文本 ${t.nid ?? ""} 导入为纯文本(版式细节可能损失)`), t;
1356
697
  case "image":
1357
698
  case "barcode":
1358
699
  case "qrcode":
1359
700
  case "chart":
1360
- comp.kind = uitype === "image" ? "image" : uitype;
1361
- comp.fallbackText = `[${uitype}]`;
1362
- warnings.push(`\u56FE\u7247\u7C7B\u7EC4\u4EF6 ${comp.nid ?? ""} \u9700\u8FD0\u884C\u65F6\u6570\u636E\uFF08imageData\uFF09\uFF0C\u5DF2\u5BFC\u5165\u4E3A\u5360\u4F4D`);
1363
- return comp;
701
+ return t.kind = i === "image" ? "image" : i, t.fallbackText = `[${i}]`, n.push(`图片类组件 ${t.nid ?? ""} 需运行时数据(imageData),已导入为占位`), t;
1364
702
  case "table": {
1365
- comp.kind = "rect";
1366
- const cellsRaw = node["Cells"] ?? node["cells"];
1367
- if (Array.isArray(cellsRaw)) {
1368
- const grid = {
1369
- cells: cellsRaw.map(
1370
- (row) => Array.isArray(row) ? row.map((cell) => ({
1371
- text: isRaw(cell) ? str(cell["Text"] ?? cell["text"]) : "",
1372
- colSpan: isRaw(cell) ? num(cell["ColSpan"], 1) : 1
703
+ t.kind = "rect";
704
+ const r = e.Cells ?? e.cells;
705
+ if (Array.isArray(r)) {
706
+ const s = {
707
+ cells: r.map(
708
+ (a) => Array.isArray(a) ? a.map((o) => ({
709
+ text: N(o) ? v(o.Text ?? o.text) : "",
710
+ colSpan: N(o) ? S(o.ColSpan, 1) : 1
1373
711
  })) : []
1374
712
  )
1375
713
  };
1376
- comp.grid = grid;
1377
- } else {
1378
- comp.fallbackText = "[table]";
1379
- warnings.push(`\u8868\u683C ${comp.nid ?? ""} \u7F3A\u5C11 Cells\uFF0C\u5BFC\u5165\u4E3A\u7A7A\u6846`);
1380
- }
1381
- return comp;
714
+ t.grid = s;
715
+ } else
716
+ t.fallbackText = "[table]", n.push(`表格 ${t.nid ?? ""} 缺少 Cells,导入为空框`);
717
+ return t;
1382
718
  }
1383
719
  case "subreport":
1384
- warnings.push(`\u5B50\u62A5\u8868 ${comp.nid ?? ""} \u6682\u4E0D\u652F\u6301\u5BFC\u5165\uFF0C\u5DF2\u8DF3\u8FC7`);
1385
- return null;
1386
- default: {
1387
- if (str(node["ShapeType"]) === "hline" || uitype === "hline") {
1388
- comp.kind = "line";
1389
- return comp;
1390
- }
1391
- if (uitype === "vline") {
1392
- comp.kind = "line";
1393
- return comp;
1394
- }
1395
- if (uitype === "rect" || uitype === "oval" || uitype === "shape") {
1396
- comp.kind = uitype === "oval" ? "ellipse" : "rect";
1397
- return comp;
1398
- }
1399
- warnings.push(`\u672A\u77E5\u7EC4\u4EF6\u7C7B\u578B ${uitype}\uFF0C\u5DF2\u8DF3\u8FC7`);
1400
- return null;
1401
- }
720
+ return n.push(`子报表 ${t.nid ?? ""} 暂不支持导入,已跳过`), null;
721
+ default:
722
+ return v(e.ShapeType) === "hline" || i === "hline" || i === "vline" ? (t.kind = "line", t) : i === "rect" || i === "oval" || i === "shape" ? (t.kind = i === "oval" ? "ellipse" : "rect", t) : (n.push(`未知组件类型 ${i},已跳过`), null);
1402
723
  }
1403
724
  }
1404
- function importJh4jTemplateContent(content) {
1405
- const warnings = [];
1406
- let root = null;
1407
- if (typeof content === "string") {
725
+ function Ge(e) {
726
+ const n = [];
727
+ let i = null;
728
+ if (typeof e == "string")
1408
729
  try {
1409
- const parsed = JSON.parse(content);
1410
- if (isRaw(parsed)) root = parsed;
730
+ const d = JSON.parse(e);
731
+ N(d) && (i = d);
1411
732
  } catch {
1412
733
  return {
1413
734
  template: { pages: [] },
1414
- warnings: ["content \u4E0D\u662F\u5408\u6CD5 JSON"]
735
+ warnings: ["content 不是合法 JSON"]
1415
736
  };
1416
737
  }
1417
- } else if (isRaw(content)) {
1418
- root = content;
1419
- }
1420
- if (!root) {
1421
- return { template: { pages: [] }, warnings: ["content \u4E3A\u7A7A"] };
1422
- }
1423
- const globalConfig = isRaw(root["GlobalConfig"]) ? root["GlobalConfig"] : {};
1424
- const defaultWidth = num(globalConfig["paperWidthMm"], 210);
1425
- const defaultHeight = num(globalConfig["paperHeightMm"], 297);
1426
- const defaultMargins = {
1427
- top: num(globalConfig["marginTop"], 10),
1428
- bottom: num(globalConfig["marginBottom"], 10),
1429
- left: num(globalConfig["marginLeft"], 10),
1430
- right: num(globalConfig["marginRight"], 10)
1431
- };
1432
- const pageNodes = Array.isArray(root["children"]) ? root["children"].filter((c) => isRaw(c) && str(c["uitype"]) === "page") : [];
1433
- if (pageNodes.length === 0) {
1434
- warnings.push("content \u4E2D\u6CA1\u6709 uitype=page \u7684\u9875\u8282\u70B9");
1435
- }
1436
- const pages = pageNodes.map((raw) => {
1437
- const node = raw;
1438
- const elements = Array.isArray(node["children"]) ? node["children"] : [];
1439
- const components = [];
1440
- for (const el of elements) {
1441
- if (!isRaw(el)) continue;
1442
- const converted = convertElement(el, warnings);
1443
- if (converted) components.push(converted);
738
+ else N(e) && (i = e);
739
+ if (!i)
740
+ return { template: { pages: [] }, warnings: ["content 为空"] };
741
+ const t = N(i.GlobalConfig) ? i.GlobalConfig : {}, r = S(t.paperWidthMm, 210), s = S(t.paperHeightMm, 297), a = {
742
+ top: S(t.marginTop, 10),
743
+ bottom: S(t.marginBottom, 10),
744
+ left: S(t.marginLeft, 10),
745
+ right: S(t.marginRight, 10)
746
+ }, o = Array.isArray(i.children) ? i.children.filter((d) => N(d) && v(d.uitype) === "page") : [];
747
+ o.length === 0 && n.push("content 中没有 uitype=page 的页节点");
748
+ const l = o.map((d) => {
749
+ const h = d, c = Array.isArray(h.children) ? h.children : [], m = [];
750
+ for (const u of c) {
751
+ if (!N(u)) continue;
752
+ const g = Be(u, n);
753
+ g && m.push(g);
1444
754
  }
1445
755
  return {
1446
- widthMm: num(node["width"], defaultWidth),
1447
- heightMm: num(node["DesignHeight"], defaultHeight),
1448
- marginTopMm: num(node["MarginTop"], defaultMargins.top),
1449
- marginBottomMm: num(node["MarginBottom"], defaultMargins.bottom),
1450
- marginLeftMm: num(node["MarginLeft"], defaultMargins.left),
1451
- marginRightMm: num(node["MarginRight"], defaultMargins.right),
1452
- components
756
+ widthMm: S(h.width, r),
757
+ heightMm: S(h.DesignHeight, s),
758
+ marginTopMm: S(h.MarginTop, a.top),
759
+ marginBottomMm: S(h.MarginBottom, a.bottom),
760
+ marginLeftMm: S(h.MarginLeft, a.left),
761
+ marginRightMm: S(h.MarginRight, a.right),
762
+ components: m
1453
763
  };
1454
764
  });
1455
- if (pages.length === 0) {
1456
- warnings.push("\u8F6C\u6362\u7ED3\u679C\u4E3A\u7A7A\u9875\uFF0C\u5DF2\u56DE\u9000\u4E00\u5F20\u7A7A\u767D\u9875");
1457
- pages.push({
1458
- widthMm: defaultWidth,
1459
- heightMm: defaultHeight,
1460
- ...defaultMargins,
1461
- components: []
1462
- });
1463
- }
1464
- return { template: { pages }, warnings };
1465
- }
1466
-
1467
- // src/builder/template-builder.ts
1468
- function resolvePaper(paper, heightArg, landscape) {
1469
- let widthMm;
1470
- let heightMm;
1471
- if (typeof paper === "string") {
1472
- const preset = PAPER_SIZES[paper];
1473
- if (!preset) throw new Error(`\u672A\u77E5\u7EB8\u5F20\u9884\u8BBE "${paper}"\uFF08\u53EF\u7528\uFF1A${Object.keys(PAPER_SIZES).join("/")}\uFF09`);
1474
- widthMm = preset.widthMm;
1475
- heightMm = preset.heightMm;
1476
- } else if (typeof paper === "number") {
1477
- widthMm = paper;
1478
- heightMm = heightArg ?? 297;
1479
- } else {
1480
- widthMm = paper.widthMm;
1481
- heightMm = paper.heightMm;
1482
- }
1483
- return landscape ? { widthMm: heightMm, heightMm: widthMm } : { widthMm, heightMm };
1484
- }
1485
- var TemplateBuilder = class {
765
+ return l.length === 0 && (n.push("转换结果为空页,已回退一张空白页"), l.push({
766
+ widthMm: r,
767
+ heightMm: s,
768
+ ...a,
769
+ components: []
770
+ })), { template: { pages: l }, warnings: n };
771
+ }
772
+ function Ne(e, n, i) {
773
+ let t, r;
774
+ if (typeof e == "string") {
775
+ const s = K[e];
776
+ if (!s) throw new Error(`未知纸张预设 "${e}"(可用:${Object.keys(K).join("/")})`);
777
+ t = s.widthMm, r = s.heightMm;
778
+ } else typeof e == "number" ? (t = e, r = n ?? 297) : (t = e.widthMm, r = e.heightMm);
779
+ return i ? { widthMm: r, heightMm: t } : { widthMm: t, heightMm: r };
780
+ }
781
+ class Le {
1486
782
  constructor() {
1487
- this.pages = [];
1488
- this.pending = null;
783
+ this.pages = [], this.pending = null;
1489
784
  }
1490
785
  /**
1491
786
  * 新建页。纸张支持三种写法:
@@ -1493,106 +788,89 @@ var TemplateBuilder = class {
1493
788
  * - 数字:.page(210, 297)(第三参数兼容旧 margins 对象或新 options)
1494
789
  * - 对象:.page({ widthMm: 210, heightMm: 297 })
1495
790
  */
1496
- page(paper = "a4", optionsOrHeight = {}, maybeOptions) {
791
+ page(n = "a4", i = {}, t) {
1497
792
  this.collect();
1498
- const legacyMargins = maybeOptions != null && !("margins" in maybeOptions) && !("landscape" in maybeOptions) && ("marginTopMm" in maybeOptions || "marginBottomMm" in maybeOptions || "marginLeftMm" in maybeOptions || "marginRightMm" in maybeOptions);
1499
- const options = legacyMargins ? { margins: maybeOptions } : maybeOptions ?? {};
1500
- const { widthMm, heightMm } = resolvePaper(
1501
- paper,
1502
- typeof optionsOrHeight === "number" ? optionsOrHeight : void 0,
1503
- options.landscape
1504
- );
1505
- const margins = options.margins ?? {};
1506
- this.pending = new PageBuilder(this, {
1507
- widthMm,
1508
- heightMm,
1509
- marginTopMm: margins.marginTopMm ?? 10,
1510
- marginBottomMm: margins.marginBottomMm ?? 10,
1511
- marginLeftMm: margins.marginLeftMm ?? 10,
1512
- marginRightMm: margins.marginRightMm ?? 10
1513
- });
1514
- return this.pending;
793
+ const s = t != null && !("margins" in t) && !("landscape" in t) && ("marginTopMm" in t || "marginBottomMm" in t || "marginLeftMm" in t || "marginRightMm" in t) ? { margins: t } : t ?? {}, { widthMm: a, heightMm: o } = Ne(
794
+ n,
795
+ typeof i == "number" ? i : void 0,
796
+ s.landscape
797
+ ), l = s.margins ?? {};
798
+ return this.pending = new ze(this, {
799
+ widthMm: a,
800
+ heightMm: o,
801
+ marginTopMm: l.marginTopMm ?? 10,
802
+ marginBottomMm: l.marginBottomMm ?? 10,
803
+ marginLeftMm: l.marginLeftMm ?? 10,
804
+ marginRightMm: l.marginRightMm ?? 10
805
+ }), this.pending;
1515
806
  }
1516
807
  collect() {
1517
- if (this.pending) {
1518
- this.pages.push(this.pending.buildPage());
1519
- this.pending = null;
1520
- }
808
+ this.pending && (this.pages.push(this.pending.buildPage()), this.pending = null);
1521
809
  }
1522
810
  build() {
1523
- this.collect();
1524
- if (this.pages.length === 0) {
1525
- throw new Error("\u6A21\u677F\u81F3\u5C11\u9700\u8981\u4E00\u9875\uFF1A\u5148\u8C03\u7528 .page() \u6DFB\u52A0\u5185\u5BB9");
1526
- }
811
+ if (this.collect(), this.pages.length === 0)
812
+ throw new Error("模板至少需要一页:先调用 .page() 添加内容");
1527
813
  return { pages: this.pages };
1528
814
  }
1529
- };
1530
- var PageBuilder = class {
1531
- constructor(parent, page) {
1532
- this.parent = parent;
1533
- this.page = page;
1534
- this.components = [];
815
+ }
816
+ class ze {
817
+ constructor(n, i) {
818
+ this.parent = n, this.page = i, this.components = [];
1535
819
  }
1536
- text(content, geometry = {}, style = {}) {
1537
- this.components.push({
820
+ text(n, i = {}, t = {}) {
821
+ return this.components.push({
1538
822
  kind: "text",
1539
- leftMm: geometry.leftMm ?? 0,
1540
- topMm: geometry.topMm ?? 0,
1541
- widthMm: geometry.widthMm ?? 60,
1542
- heightMm: geometry.heightMm ?? 8,
1543
- text: content,
1544
- style
1545
- });
1546
- return this;
1547
- }
1548
- list(dataset, geometry, columns, options = {}) {
1549
- this.components.push({
823
+ leftMm: i.leftMm ?? 0,
824
+ topMm: i.topMm ?? 0,
825
+ widthMm: i.widthMm ?? 60,
826
+ heightMm: i.heightMm ?? 8,
827
+ text: n,
828
+ style: t
829
+ }), this;
830
+ }
831
+ list(n, i, t, r = {}) {
832
+ return this.components.push({
1550
833
  kind: "list",
1551
- leftMm: geometry.leftMm ?? 10,
1552
- topMm: geometry.topMm ?? 30,
1553
- widthMm: geometry.widthMm ?? 180,
1554
- dataset,
1555
- columns,
1556
- ...options
1557
- });
1558
- return this;
1559
- }
1560
- rect(geometry, style = {}) {
1561
- this.components.push({ kind: "rect", ...geometry, style });
1562
- return this;
1563
- }
1564
- line(leftMm, topMm, widthMm, style = {}) {
1565
- this.components.push({
834
+ leftMm: i.leftMm ?? 10,
835
+ topMm: i.topMm ?? 30,
836
+ widthMm: i.widthMm ?? 180,
837
+ dataset: n,
838
+ columns: t,
839
+ ...r
840
+ }), this;
841
+ }
842
+ rect(n, i = {}) {
843
+ return this.components.push({ kind: "rect", ...n, style: i }), this;
844
+ }
845
+ line(n, i, t, r = {}) {
846
+ return this.components.push({
1566
847
  kind: "line",
1567
- leftMm,
1568
- topMm,
1569
- widthMm,
848
+ leftMm: n,
849
+ topMm: i,
850
+ widthMm: t,
1570
851
  heightMm: 0.5,
1571
- style
1572
- });
1573
- return this;
852
+ style: r
853
+ }), this;
1574
854
  }
1575
- barcode(content, geometry) {
1576
- this.components.push({
855
+ barcode(n, i) {
856
+ return this.components.push({
1577
857
  kind: "barcode",
1578
- leftMm: geometry.leftMm ?? 0,
1579
- topMm: geometry.topMm ?? 0,
1580
- widthMm: geometry.widthMm ?? 40,
1581
- heightMm: geometry.heightMm ?? 12,
1582
- fallbackText: content
1583
- });
1584
- return this;
1585
- }
1586
- qrcode(content, sizeMm, leftMm, topMm) {
1587
- this.components.push({
858
+ leftMm: i.leftMm ?? 0,
859
+ topMm: i.topMm ?? 0,
860
+ widthMm: i.widthMm ?? 40,
861
+ heightMm: i.heightMm ?? 12,
862
+ fallbackText: n
863
+ }), this;
864
+ }
865
+ qrcode(n, i, t, r) {
866
+ return this.components.push({
1588
867
  kind: "qrcode",
1589
- leftMm,
1590
- topMm,
1591
- widthMm: sizeMm,
1592
- heightMm: sizeMm,
1593
- fallbackText: content
1594
- });
1595
- return this;
868
+ leftMm: t,
869
+ topMm: r,
870
+ widthMm: i,
871
+ heightMm: i,
872
+ fallbackText: n
873
+ }), this;
1596
874
  }
1597
875
  buildPage() {
1598
876
  return { ...this.page, components: this.components };
@@ -1603,9 +881,60 @@ var PageBuilder = class {
1603
881
  build() {
1604
882
  return this.done().build();
1605
883
  }
1606
- };
1607
- function createTemplate() {
1608
- return new TemplateBuilder();
1609
884
  }
1610
-
1611
- export { CSS_DPI, DEFAULT_BORDER_PT, DEFAULT_FONT_PT, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, LINE_HEIGHT, MM_PER_INCH, PAPER_SIZES, PageBuilder, RENDER_PLAN_SCHEMA_VERSION, SCHEMA_VERSION_JH4J, SCHEMA_VERSION_LOCAL, SCHEMA_VERSION_MACH, TemplateBuilder, assertRenderPlan, charWidthEm, classOf, computePageWindow, createCanvasMeasurer, createCanvasPager, createHeuristicMeasurer, createTemplate, heuristicMeasurer, importJh4jTemplateContent, isImageBackedComponent, isRichText, measurePageSizePx, measureTextMm, mmToPx, mmToPxFactor, paginateTemplate, planFontSizePx, ptToPx, pxToMm, renderComponent, renderPage, renderPlan, renderPlanToCanvas, resolveBoxBorders, resolveFontSize, resolveGridLayout, resolveLineHeight, resolvePaper, resolveStroke, resolveTextColor, round, toRenderPlan, validateComponent, validatePage, validateRenderPlan, wrapText };
885
+ function Ve() {
886
+ return new Le();
887
+ }
888
+ export {
889
+ Ue as CSS_DPI,
890
+ Ke as DEFAULT_BORDER_PT,
891
+ j as DEFAULT_FONT_PT,
892
+ Ye as DEFAULT_STROKE_COLOR,
893
+ me as DEFAULT_TEXT_COLOR,
894
+ q as LINE_HEIGHT,
895
+ Xe as MM_PER_INCH,
896
+ K as PAPER_SIZES,
897
+ ze as PageBuilder,
898
+ se as RENDER_PLAN_SCHEMA_VERSION,
899
+ Ze as SCHEMA_VERSION_JH4J,
900
+ Qe as SCHEMA_VERSION_LOCAL,
901
+ et as SCHEMA_VERSION_MACH,
902
+ Le as TemplateBuilder,
903
+ _e as assertRenderPlan,
904
+ tt as charWidthEm,
905
+ C as classOf,
906
+ Pe as computePageWindow,
907
+ nt as createCanvasMeasurer,
908
+ je as createCanvasPager,
909
+ it as createHeuristicMeasurer,
910
+ Ve as createTemplate,
911
+ J as heuristicMeasurer,
912
+ Ge as importJh4jTemplateContent,
913
+ le as isImageBackedComponent,
914
+ Z as isRichText,
915
+ ie as measurePageSizePx,
916
+ rt as measureTextMm,
917
+ de as mmToPx,
918
+ ot as mmToPxFactor,
919
+ We as paginateTemplate,
920
+ De as planFontSizePx,
921
+ O as ptToPx,
922
+ at as pxToMm,
923
+ ne as renderComponent,
924
+ xe as renderPage,
925
+ Ie as renderPlan,
926
+ Oe as renderPlanToCanvas,
927
+ V as resolveBoxBorders,
928
+ W as resolveFontSize,
929
+ ce as resolveGridLayout,
930
+ he as resolveLineHeight,
931
+ Ne as resolvePaper,
932
+ F as resolveStroke,
933
+ Q as resolveTextColor,
934
+ _ as round,
935
+ st as toRenderPlan,
936
+ ee as validateComponent,
937
+ ue as validatePage,
938
+ pe as validateRenderPlan,
939
+ G as wrapText
940
+ };