@agile-team/mach-report 2.10.0 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +6 -2
  2. package/dist/ExcelBindingWizard-LWX6G1A2.js +1465 -0
  3. package/dist/ExcelBindingWizard-a4kslPHF.cjs +1 -0
  4. package/dist/ParamEditor-BLaE5q5W.js +522 -0
  5. package/dist/ParamEditor-MBBC7lUE.cjs +1 -0
  6. package/dist/ReportBatchPanel-B5ClP9tm.js +350 -0
  7. package/dist/ReportBatchPanel-Dc-SDkYA.cjs +1 -0
  8. package/dist/ReportPreview-DWXROHBP.cjs +6 -0
  9. package/dist/ReportPreview-DiNXhQI0.js +4138 -0
  10. package/dist/ReportTemplateLibrary-5fk5CQBO.cjs +1 -0
  11. package/dist/ReportTemplateLibrary-BZB-XWjj.js +311 -0
  12. package/dist/RuleEditor-C2QsOHOs.cjs +1 -0
  13. package/dist/RuleEditor-D9wQHrkf.js +2024 -0
  14. package/dist/TemplateReviewPanel-BKofGrV9.js +222 -0
  15. package/dist/TemplateReviewPanel-DwtOcLue.cjs +1 -0
  16. package/dist/analytics.cjs +1 -1
  17. package/dist/analytics.d.cts +2 -0
  18. package/dist/analytics.d.ts +2 -0
  19. package/dist/analytics.js +29 -29
  20. package/dist/batch-Bt3Fd27Z.cjs +1 -0
  21. package/dist/batch-mRqhhhjt.js +364 -0
  22. package/dist/computed-Bvk0W15F.js +521 -0
  23. package/dist/computed-CGV2a809.cjs +1 -0
  24. package/dist/config-B612mw0x.js +525 -0
  25. package/dist/config-BRoLo2oj.cjs +1 -0
  26. package/dist/designer.cjs +2 -2
  27. package/dist/designer.d.cts +730 -9
  28. package/dist/designer.d.ts +730 -9
  29. package/dist/designer.js +2093 -1785
  30. package/dist/index.cjs +8 -8
  31. package/dist/index.d.cts +161 -3
  32. package/dist/index.d.ts +161 -3
  33. package/dist/index.js +486 -431
  34. package/dist/injection-keys-Db_DyLkm.cjs +1 -0
  35. package/dist/injection-keys-e85udZCp.js +7 -0
  36. package/dist/list-cell-BuYn4tGF.cjs +1 -0
  37. package/dist/{list-cell-Dxyi7DOw.js → list-cell-ClFra1zS.js} +54 -40
  38. package/dist/matrix-DVyWiYsd.cjs +1 -0
  39. package/dist/matrix-yZsGnldA.js +227 -0
  40. package/dist/param-validation-BlHHXs6u.js +153 -0
  41. package/dist/param-validation-DCK039V1.cjs +1 -0
  42. package/dist/pdf.cjs +25 -25
  43. package/dist/pdf.d.cts +3 -0
  44. package/dist/pdf.d.ts +3 -0
  45. package/dist/pdf.js +677 -677
  46. package/dist/plugin-BDTU4D94.cjs +1 -0
  47. package/dist/plugin-Cd5G2QQn.js +22 -0
  48. package/dist/region-binding-workflow-CXDmt9Bs.js +977 -0
  49. package/dist/region-binding-workflow-DhQvu1co.cjs +3 -0
  50. package/dist/{report-params-B_VCihAh.js → report-params-B44imUd4.js} +1 -1
  51. package/dist/{report-params-CjWrjPl6.cjs → report-params-SJfhKgaX.cjs} +1 -1
  52. package/dist/server/node.d.cts +5 -2
  53. package/dist/server/node.d.ts +5 -2
  54. package/dist/server-node.cjs +1 -1
  55. package/dist/server-node.js +87 -87
  56. package/dist/server.cjs +1 -1
  57. package/dist/server.d.cts +201 -2
  58. package/dist/server.d.ts +201 -2
  59. package/dist/server.js +557 -658
  60. package/dist/style.css +1 -1
  61. package/dist/template-registry-WNXdkiET.js +506 -0
  62. package/dist/template-registry-ukBGlm8N.cjs +1 -0
  63. package/dist/template-review-BXp2oyqg.cjs +1 -0
  64. package/dist/template-review-BdcXSYbx.js +1616 -0
  65. package/dist/tree-BX380Rr7.cjs +1 -0
  66. package/dist/tree-CqcQ99NM.js +172 -0
  67. package/dist/{validate-UUy9yP4K.js → validate-7s0yn6ii.js} +44 -44
  68. package/dist/validate-DsRiNw8h.cjs +1 -0
  69. package/dist/vue/async.d.cts +93 -4
  70. package/dist/vue/async.d.ts +93 -4
  71. package/dist/vue/index.d.cts +145 -7
  72. package/dist/vue/index.d.ts +145 -7
  73. package/dist/vue-async.cjs +1 -1
  74. package/dist/vue-async.js +5 -5
  75. package/dist/vue.cjs +1 -1
  76. package/dist/vue.js +116 -113
  77. package/dist/{workbook-session-B-bW5_yR.js → workbook-session-BKOTwcoq.js} +1 -1
  78. package/dist/{workbook-session-D7RtdNo0.cjs → workbook-session-CLYLhZWu.cjs} +1 -1
  79. package/dist/worker.cjs +1 -1
  80. package/dist/worker.d.cts +5 -2
  81. package/dist/worker.d.ts +5 -2
  82. package/dist/worker.js +1 -1
  83. package/dist/xlsx.cjs +3 -3
  84. package/dist/xlsx.d.cts +129 -2
  85. package/dist/xlsx.d.ts +129 -2
  86. package/dist/xlsx.js +336 -242
  87. package/package.json +1 -1
  88. package/dist/ExcelBindingWizard-CF7RplWm.cjs +0 -1
  89. package/dist/ExcelBindingWizard-qhwEderR.js +0 -842
  90. package/dist/ReportPreview-BE1tCHqE.js +0 -4604
  91. package/dist/ReportPreview-QKRKQOe3.cjs +0 -6
  92. package/dist/RuleEditor-BA36yIV6.js +0 -1723
  93. package/dist/RuleEditor-CczJ6mJm.cjs +0 -1
  94. package/dist/TemplateReviewPanel-CHi4Alqa.cjs +0 -1
  95. package/dist/TemplateReviewPanel-Dz0G5o83.js +0 -217
  96. package/dist/binding-preview-BWsdf_z2.cjs +0 -2
  97. package/dist/binding-preview-DILq0-0f.js +0 -649
  98. package/dist/decimal-CI1OAczk.js +0 -87
  99. package/dist/decimal-CQA0xJex.cjs +0 -1
  100. package/dist/list-cell-CyM1ZlRN.cjs +0 -1
  101. package/dist/matrix-BbXarwyk.js +0 -661
  102. package/dist/matrix-Cm65WLLP.cjs +0 -1
  103. package/dist/param-validation-BWNjLcN0.js +0 -116
  104. package/dist/param-validation-CiTxFeZ8.cjs +0 -1
  105. package/dist/plugin-CThk42vJ.cjs +0 -1
  106. package/dist/plugin-tGn7-5oF.js +0 -25
  107. package/dist/template-registry-CGWTLtIA.cjs +0 -1
  108. package/dist/template-registry-DzlQs3OF.js +0 -434
  109. package/dist/template-review-D1RoNCPw.cjs +0 -1
  110. package/dist/template-review-fnteXRng.js +0 -1473
  111. package/dist/validate-Bf6ccFr2.cjs +0 -1
@@ -0,0 +1,977 @@
1
+ import { v as F } from "./dataset-H5pFuQGU.js";
2
+ import { v as D, d as z, p as Z } from "./template-registry-WNXdkiET.js";
3
+ import { r as N } from "./grid-geometry-BNptEcMm.js";
4
+ function v(t) {
5
+ let e = "";
6
+ for (let o = t; o > 0; o = Math.floor((o - 1) / 26)) e = String.fromCharCode(65 + (o - 1) % 26) + e;
7
+ return e;
8
+ }
9
+ function $(t) {
10
+ return `${v(t.left)}${t.top}:${v(t.right)}${t.bottom}`;
11
+ }
12
+ function L(t) {
13
+ let e = 0;
14
+ for (const o of t.toUpperCase()) e = e * 26 + o.charCodeAt(0) - 64;
15
+ return e;
16
+ }
17
+ function p(t) {
18
+ if (typeof t != "string") throw new Error("Excel 范围应为 A1:B20 格式的字符串");
19
+ const e = /^\$?([A-Z]{1,3})\$?([1-9]\d{0,6})(?::\$?([A-Z]{1,3})\$?([1-9]\d{0,6}))?$/i.exec(t.trim());
20
+ if (!e) throw new Error(`Excel 范围无效:${t}`);
21
+ const o = { left: L(e[1]), top: Number(e[2]), right: L(e[3] ?? e[1]), bottom: Number(e[4] ?? e[2]) };
22
+ if (o.right < o.left || o.bottom < o.top || o.right > 16384 || o.bottom > 1048576)
23
+ throw new Error(`Excel 范围超出边界或顺序无效:${t}`);
24
+ return o;
25
+ }
26
+ function zt(t, e) {
27
+ if (e !== void 0) return p(e);
28
+ const o = t.model.rows ?? [];
29
+ if (!o.length) return { top: 1, left: 1, bottom: 1, right: 1 };
30
+ const r = { top: 1 / 0, left: 1 / 0, bottom: 1, right: 1 };
31
+ for (const n of o)
32
+ r.top = Math.min(r.top, n.number), r.bottom = Math.max(r.bottom, n.number), r.left = Math.min(r.left, n.min || 1), r.right = Math.max(r.right, n.max || 1);
33
+ return r;
34
+ }
35
+ function Zt(t, e, o) {
36
+ const r = t.bottom - t.top + 1, n = t.right - t.left + 1;
37
+ if (r > e.limits.maxRows || n > e.limits.maxColumns || r * n > o)
38
+ throw new Error(`Excel 范围 ${$(t)} 超过导入行、列或单元格上限;请用 sheets/range 缩小范围`);
39
+ return r * n;
40
+ }
41
+ function at(t, e) {
42
+ return t.top <= e.bottom && t.bottom >= e.top && t.left <= e.right && t.right >= e.left;
43
+ }
44
+ function qt(t, e) {
45
+ const o = [];
46
+ for (const r of t.model.merges) {
47
+ const n = p(r);
48
+ if (at(e, n)) {
49
+ if (n.left < e.left || n.right > e.right || n.top < e.top || n.bottom > e.bottom)
50
+ throw new Error(`${t.name}: 范围 ${$(e)} 截断合并单元格 ${r},请包含完整合并区域`);
51
+ o.push(n);
52
+ }
53
+ }
54
+ return o;
55
+ }
56
+ function Ut(t, e) {
57
+ const o = /* @__PURE__ */ new Map();
58
+ for (const n of e) o.set(n.top, Math.max(o.get(n.top) ?? n.top, n.bottom));
59
+ const r = [];
60
+ for (let n = t.top; n <= t.bottom; ) {
61
+ let s = o.get(n) ?? n;
62
+ for (let i = n; i <= s; i++) s = Math.max(s, o.get(i) ?? i);
63
+ r.push({ top: n, bottom: s }), n = s + 1;
64
+ }
65
+ return r;
66
+ }
67
+ function Qt(t, e, o, r) {
68
+ const n = [];
69
+ let s, i = 0;
70
+ for (const a of t) {
71
+ const c = a.bottom - a.top + 1;
72
+ if (c > 200) throw new Error("合并单元格跨越超过 200 行,无法安全分段;请先缩小或拆分该合并区域");
73
+ let l = 0;
74
+ for (let h = a.top; h <= a.bottom; h++) l += r(h);
75
+ if (l > o && Number.isFinite(o)) throw new Error("合并区域或单行高度超过标准纸张可用高度;请使用 wide 或调整原模板行高");
76
+ const f = s ? a.bottom - s.top + 1 : c;
77
+ s && (f > e || i + l > o) && (n.push(s), s = void 0, i = 0), s ? s.bottom = a.bottom : s = { ...a }, i += l;
78
+ }
79
+ return s && n.push(s), n;
80
+ }
81
+ function Xt(t) {
82
+ const e = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set();
83
+ for (const r of t) {
84
+ e.set(`${r.top}:${r.left}`, r);
85
+ for (let n = r.top; n <= r.bottom; n++)
86
+ for (let s = r.left; s <= r.right; s++)
87
+ (n !== r.top || s !== r.left) && o.add(`${n}:${s}`);
88
+ }
89
+ return { masters: e, covered: o };
90
+ }
91
+ function B(t) {
92
+ return JSON.parse(JSON.stringify(t));
93
+ }
94
+ function it(t, e) {
95
+ const o = t.template.pages.slice(e.pageStart, e.pageStart + e.pageCount), r = o[0];
96
+ if (!r) throw new Error(`工作表 ${e.name} 没有可绑定页面`);
97
+ const n = /* @__PURE__ */ new Map();
98
+ let s = [];
99
+ for (const i of o)
100
+ for (const a of i.components) {
101
+ if (a.kind === "list" || !a.grid || a.meta?.xlsxSheet !== e.name) continue;
102
+ const c = p(String(a.meta.xlsxRange)), l = a.grid;
103
+ s = l.colWidthsMm ?? [], l.cells.forEach((f, h) => n.set(c.top + h, { cells: B(f), height: l.rowHeightsMm?.[h] ?? 6 }));
104
+ }
105
+ if (!s.length || !n.size) throw new Error(`工作表 ${e.name} 缺少导入几何元数据`);
106
+ return { rows: n, widths: [...s], page: r, range: p(e.range) };
107
+ }
108
+ function K(t, e, o) {
109
+ const r = [], n = [];
110
+ for (let s = e; s <= o; s++) {
111
+ const i = t.rows.get(s);
112
+ if (!i) throw new Error(`导入模板缺少第 ${s} 行`);
113
+ for (const a of i.cells)
114
+ if (a && s + (a.rowSpan ?? 1) - 1 > o) throw new Error(`第 ${s} 行合并区域跨越绑定边界,请调整 header/detail 范围`);
115
+ r.push(B(i.cells)), n.push(i.height);
116
+ }
117
+ return { cells: r, rowHeightsMm: n, colWidthsMm: t.widths, paddingMm: 0.25 };
118
+ }
119
+ function lt(t, e) {
120
+ const o = p(t.header), r = t.detail ? p(t.detail) : { ...e.range, top: o.bottom + 1 };
121
+ for (const n of [o, r])
122
+ if (n.left !== e.range.left || n.right !== e.range.right || n.top < e.range.top || n.bottom > e.range.bottom || n.top > n.bottom) throw new Error("绑定区域必须位于导入选区内并覆盖其完整列宽");
123
+ if (r.top !== o.bottom + 1) throw new Error("detail 应紧接 header,避免静态内容被隐式删除");
124
+ if (t.columns.length !== e.widths.length) throw new Error("columns 应逐列映射整个选区;不能自动猜测业务字段");
125
+ return ct(e, [o.top, o.bottom + 1, r.bottom + 1]), { header: o, detail: r };
126
+ }
127
+ function ct(t, e) {
128
+ for (const [o, r] of t.rows) for (const n of r.cells) {
129
+ const s = o + (n?.rowSpan ?? 1);
130
+ if (e.some((i) => o < i && s > i)) throw new Error(`第 ${o} 行合并区域跨越绑定边界,请调整 header/detail 范围`);
131
+ }
132
+ }
133
+ function ft(t, e) {
134
+ const o = [];
135
+ for (const r of N(t, e.reduce((n, s) => n + s, 0), 100).cells)
136
+ for (let n = r.ci; n < Math.min(e.length, r.ci + (r.cell.colSpan ?? 1)); n++) o[n] = r.cell;
137
+ return o;
138
+ }
139
+ function gt(t, e, o, r) {
140
+ if (e) return e;
141
+ const n = t?.numberFormat;
142
+ if (!n || n === "General") return;
143
+ const s = /^(#,##)?0(?:\.(0+))?(%)?$/.exec(n);
144
+ if (s) {
145
+ const i = s[2]?.length ?? 0;
146
+ if (i <= 100) return s[3] ? { kind: "percent", digits: i } : { kind: "number", digits: i, ...s[1] ? { thousands: !0 } : {} };
147
+ }
148
+ r.push(`${o}: Excel 数字格式 ${n} 未自动套用到动态数据,请在 columns 中显式声明 format`);
149
+ }
150
+ function ht(t, e, o, r, n) {
151
+ const s = ft(e, r), i = N(o, r.reduce((f, h) => f + h, 0), 20).cells;
152
+ if (i.some(({ cell: f }) => (f.colSpan ?? 1) !== 1 || (f.rowSpan ?? 1) !== 1)) throw new Error("动态明细样例行不能包含合并格;合并表头可以保留");
153
+ const a = new Map(i.map((f) => [f.ci, f.cell])), c = /* @__PURE__ */ new Set(), l = t.columns.map((f, h) => {
154
+ const g = typeof f == "string" ? { field: f } : f;
155
+ if (!g || typeof g.field != "string" || !g.field.trim() || c.has(g.field)) throw new Error(`columns[${h}] 需要唯一的非空 field`);
156
+ c.add(g.field);
157
+ const m = s[h]?.text ?? g.field, d = a.get(h), w = t.inferSampleFormats === !1 ? g.format : gt(d, g.format, g.field, n);
158
+ return { ...g, ...w ? { format: w } : {}, header: g.header ?? m, widthMm: r[h], style: { ...d?.style, ...g.style }, ...g.semanticRole && !g.align ? { align: "auto" } : {}, ...g.editable === void 0 && d?.editable === !1 ? { editable: !1 } : {} };
159
+ });
160
+ return mt(t, s, l), l;
161
+ }
162
+ function mt(t, e, o) {
163
+ const r = /* @__PURE__ */ new Map();
164
+ t.columns.forEach((n, s) => {
165
+ const i = e[s];
166
+ if (!i || typeof n == "string") return;
167
+ const a = r.get(i) ?? { style: {} };
168
+ if (n.header !== void 0) {
169
+ if (a.text !== void 0 && a.text !== n.header) throw new Error("同一合并表头不能配置不同 header");
170
+ a.text = n.header;
171
+ }
172
+ pt(a.style, { ...n.headerAlign ? { align: n.headerAlign } : {}, ...n.headerStyle }), r.set(i, a);
173
+ });
174
+ for (const [n, s] of r)
175
+ s.text !== void 0 && Object.assign(n, { text: s.text, rawText: s.text, value: s.text }), n.style = { ...n.style, ...s.style }, e.forEach((i, a) => {
176
+ i === n && (s.text !== void 0 && (o[a].header = s.text), s.style.align !== void 0 && (o[a].headerAlign = s.style.align));
177
+ });
178
+ }
179
+ function pt(t, e) {
180
+ for (const o of Object.keys(e))
181
+ if (e[o] !== void 0) {
182
+ if (t[o] !== void 0 && t[o] !== e[o]) throw new Error(`同一合并表头不能配置不同 ${o}`);
183
+ Object.assign(t, { [o]: e[o] });
184
+ }
185
+ }
186
+ function dt(t, e) {
187
+ const o = t.page, r = e.rowHeightsMm.reduce((n, s) => n + s, 0);
188
+ return { ...o, heightMm: Math.max(o.heightMm, r + (o.marginTopMm ?? 0) + (o.marginBottomMm ?? 0)), components: [{ kind: "rect", leftMm: o.marginLeftMm ?? 0, topMm: o.marginTopMm ?? 0, widthMm: t.widths.reduce((n, s) => n + s, 0), heightMm: r, grid: e }] };
189
+ }
190
+ function ut(t, e, o, r) {
191
+ const n = it(t, e), { header: s, detail: i } = lt(o, n), a = K(n, n.range.top, s.bottom), c = K(n, i.top, i.top), l = { ...n.page, components: [] }, f = {
192
+ kind: "list",
193
+ id: `bound:${e.name}`,
194
+ dataset: o.dataset ?? "detail",
195
+ title: e.name,
196
+ leftMm: l.marginLeftMm ?? 0,
197
+ topMm: l.marginTopMm ?? 0,
198
+ widthMm: n.widths.reduce((h, g) => h + g, 0),
199
+ layout: l.layout ?? "page",
200
+ headerGrid: a,
201
+ columns: ht(o, a, c, n.widths, r),
202
+ rowHeightMm: c.rowHeightsMm[0],
203
+ headerEveryPage: !0,
204
+ align: "auto",
205
+ paddingMm: 0.25,
206
+ ...o.rowKey ? { rowKey: o.rowKey } : {},
207
+ ...o.revisionField ? { revisionField: o.revisionField } : {},
208
+ ...o.sourceTokenField ? { sourceTokenField: o.sourceTokenField } : {},
209
+ ...o.groupBy ? { groupBy: o.groupBy } : {},
210
+ ...o.grandTotal === void 0 ? {} : { grandTotal: o.grandTotal }
211
+ };
212
+ return l.components.push(f), i.bottom === n.range.bottom ? [l] : (r.push(`${e.name}: 明细区域后的静态内容保留为后续独立页面,不推断动态页脚定位`), [l, dt(n, K(n, i.bottom + 1, n.range.bottom))]);
213
+ }
214
+ function wt(t, e) {
215
+ const o = D(t.template);
216
+ if (!o.ok) throw new Error(`导入模板无效:${o.errors[0]?.message}`);
217
+ if (!e.length) throw new Error("至少需要一个 Excel 业务绑定");
218
+ const r = /* @__PURE__ */ new Map();
219
+ for (const c of e) {
220
+ if (!t.sheets.some((l) => l.name === c.sheet) || r.has(c.sheet)) throw new Error(`绑定工作表不存在或重复:${c.sheet}`);
221
+ r.set(c.sheet, c);
222
+ }
223
+ const n = [...t.warnings], s = t.sheets.flatMap((c) => {
224
+ const l = r.get(c.name);
225
+ return l ? ut(t, c, l, n) : B(t.template.pages.slice(c.pageStart, c.pageStart + c.pageCount));
226
+ }), i = { ...B(t.template), pages: s }, a = D(i);
227
+ if (!a.ok) throw new Error(`业务模板无效:${a.errors[0]?.path} ${a.errors[0]?.message}`);
228
+ return { template: i, warnings: n };
229
+ }
230
+ function q(t) {
231
+ const e = t.semanticRole ?? (t.type === "number" || t.type === "decimal" ? "measure" : t.type === "date" ? "date" : "text");
232
+ return {
233
+ field: t.field,
234
+ semanticRole: e,
235
+ editable: !1,
236
+ ...t.type === "number" && t.digits !== void 0 ? { format: { kind: "number", digits: t.digits } } : {},
237
+ ...t.type === "date" ? { format: { kind: "date", pattern: "YYYY-MM-DD" } } : {}
238
+ };
239
+ }
240
+ function yt(t) {
241
+ return t === null || typeof t == "string" || typeof t == "boolean" || typeof t == "number" && Number.isFinite(t);
242
+ }
243
+ function H(t, e = 0) {
244
+ if (yt(t)) return;
245
+ if (!t || typeof t != "object" || e > 16)
246
+ throw new Error("绑定会话元数据只允许有限深度的普通 JSON 值");
247
+ const o = Object.getPrototypeOf(t);
248
+ if (Array.isArray(t) ? o !== Array.prototype : o !== Object.prototype && o !== null)
249
+ throw new Error("绑定会话不能包含特殊对象原型");
250
+ if (Object.getOwnPropertySymbols(t).length)
251
+ throw new Error("绑定会话不能包含 Symbol");
252
+ if (Array.isArray(t) && Object.keys(t).length !== t.length)
253
+ throw new Error("绑定会话数组不能包含空位或额外属性");
254
+ for (const [r, n] of Object.entries(
255
+ Object.getOwnPropertyDescriptors(t)
256
+ ))
257
+ if (!(Array.isArray(t) && r === "length")) {
258
+ if (["__proto__", "prototype", "constructor"].includes(r) || n.get || n.set || !n.enumerable)
259
+ throw new Error("绑定会话包含不安全元数据");
260
+ H(n.value, e + 1);
261
+ }
262
+ }
263
+ function Et(t, e) {
264
+ return Mt(t, e);
265
+ }
266
+ function Mt(t, e) {
267
+ const o = t.sheets.find((c) => c.name === e.sheet);
268
+ if (!o) return [];
269
+ const r = p(e.regions.header), n = p(e.regions.detail), s = [r.top, r.bottom + 1, n.bottom + 1], i = [], a = /* @__PURE__ */ new Set();
270
+ for (const c of t.template.pages.slice(
271
+ o.pageStart,
272
+ o.pageStart + o.pageCount
273
+ ))
274
+ for (const l of c.components) {
275
+ if (l.kind === "list" || !l.grid || l.meta?.xlsxSheet !== e.sheet)
276
+ continue;
277
+ const f = p(String(l.meta.xlsxRange));
278
+ l.grid.cells.forEach((h, g) => {
279
+ const m = f.top + g;
280
+ for (const d of h) {
281
+ const w = s.some(
282
+ (b) => m < b && m + (d?.rowSpan ?? 1) > b
283
+ ), M = m === n.top && ((d?.rowSpan ?? 1) > 1 || (d?.colSpan ?? 1) > 1);
284
+ if (!w && !M) continue;
285
+ const E = w ? "$.recipe.regions" : "$.recipe.regions.detail";
286
+ a.has(E) || (a.add(E), i.push({
287
+ path: E,
288
+ code: "region",
289
+ message: w ? `第 ${m} 行合并区域跨越绑定边界,请选择完整合并区域` : "动态明细原型行不能包含合并格"
290
+ }));
291
+ }
292
+ });
293
+ }
294
+ return i;
295
+ }
296
+ function U(t) {
297
+ return JSON.parse(JSON.stringify(t));
298
+ }
299
+ function O(t) {
300
+ return t instanceof Error ? t.message : String(t);
301
+ }
302
+ function u(t, e, o, r) {
303
+ t.push({ path: e, code: o, message: r });
304
+ }
305
+ function Q(t, e) {
306
+ return { fields: t.fields, ...e ? { rowKey: e } : {} };
307
+ }
308
+ function bt(t, e) {
309
+ const o = /* @__PURE__ */ new Set();
310
+ for (const [r, n] of t.entries()) {
311
+ const s = `$.datasets[${r}]`;
312
+ if (!n || typeof n.id != "string" || !n.id.trim() || o.has(n.id)) {
313
+ u(e, s, "schema", "数据集标识应非空且唯一");
314
+ continue;
315
+ }
316
+ o.add(n.id);
317
+ try {
318
+ F([], Q(n, n.rowKey));
319
+ for (const [i, a] of n.fields.entries())
320
+ a.digits !== void 0 && (!Number.isInteger(a.digits) || a.digits < 0 || a.digits > 100) && u(
321
+ e,
322
+ `${s}.fields[${i}].digits`,
323
+ "schema",
324
+ "显示精度应为 0–100 的整数"
325
+ );
326
+ } catch (i) {
327
+ u(e, s, "schema", O(i));
328
+ }
329
+ }
330
+ }
331
+ function $t(t, e, o) {
332
+ const r = t.sheets.find((a) => a.name === e.sheet);
333
+ if (!r) {
334
+ u(o, "$.recipe.sheet", "source", "指定的工作表不存在");
335
+ return;
336
+ }
337
+ let n;
338
+ try {
339
+ n = p(r.range);
340
+ } catch (a) {
341
+ u(o, "$.source.sheets", "source", O(a));
342
+ return;
343
+ }
344
+ const s = /* @__PURE__ */ new Map();
345
+ for (const a of ["title", "header", "detail", "footer"]) {
346
+ const c = e.regions?.[a];
347
+ if (!(!c && (a === "title" || a === "footer")))
348
+ try {
349
+ const l = p(c ?? "");
350
+ if (l.left !== n.left || l.right !== n.right || l.top < n.top || l.bottom > n.bottom)
351
+ throw new Error("区域必须覆盖选区完整列宽,并位于原始工作表内");
352
+ s.set(a, l);
353
+ } catch (l) {
354
+ u(o, `$.recipe.regions.${a}`, "region", O(l));
355
+ }
356
+ }
357
+ const i = [...s.values()];
358
+ i.length && (i[0].top !== n.top || i[i.length - 1].bottom !== n.bottom) && u(
359
+ o,
360
+ "$.recipe.regions",
361
+ "region",
362
+ "标题、表头、明细、页脚应完整覆盖来源,不能隐式删除静态内容"
363
+ );
364
+ for (let a = 1; a < i.length; a++)
365
+ i[a].top !== i[a - 1].bottom + 1 && u(o, "$.recipe.regions", "region", "各区域应顺序相邻且不重叠");
366
+ }
367
+ function xt(t, e, o, r) {
368
+ if (!Array.isArray(t.fields) || t.fields.length !== o)
369
+ return u(
370
+ r,
371
+ "$.recipe.fields",
372
+ "mapping",
373
+ "每个物理 Excel 列必须显式绑定一个业务字段"
374
+ ), 0;
375
+ const n = new Set(e.fields.map((a) => a.field)), s = /* @__PURE__ */ new Set();
376
+ let i = 0;
377
+ t.fields.forEach((a, c) => {
378
+ typeof a != "string" || !n.has(a) ? u(
379
+ r,
380
+ `$.recipe.fields[${c}]`,
381
+ "mapping",
382
+ "请选择契约中已声明的字段"
383
+ ) : s.has(a) ? u(
384
+ r,
385
+ `$.recipe.fields[${c}]`,
386
+ "mapping",
387
+ "同一业务字段不能重复绑定物理列"
388
+ ) : (i++, s.add(a));
389
+ });
390
+ try {
391
+ if (!t.rowKey)
392
+ throw new Error("请明确选择稳定业务主键,不能使用展示行号");
393
+ const a = Q(e, t.rowKey), c = F(e.samples ?? [], a, {
394
+ path: `$.datasets.${e.id}.samples`,
395
+ maxRows: 100,
396
+ maxCells: 2e5,
397
+ maxIssues: 30
398
+ });
399
+ for (const l of c.issues)
400
+ u(
401
+ r,
402
+ l.path,
403
+ l.code === "row-key" ? "row-key" : "schema",
404
+ l.message
405
+ );
406
+ } catch (a) {
407
+ u(r, "$.recipe.rowKey", "row-key", O(a));
408
+ }
409
+ return i;
410
+ }
411
+ function St(t, e) {
412
+ const o = [];
413
+ return !e || e.version !== "1.0" ? [
414
+ {
415
+ path: "$.recipe.version",
416
+ code: "schema",
417
+ message: "不支持的 Excel 绑定配置版本"
418
+ }
419
+ ] : ($t(t, e, o), o.length || o.push(...Et(t, e)), o);
420
+ }
421
+ function Rt(t, e, o) {
422
+ const r = [];
423
+ if (!e || e.version !== "1.0")
424
+ return {
425
+ ok: !1,
426
+ issues: [
427
+ {
428
+ path: "$.recipe.version",
429
+ code: "schema",
430
+ message: "不支持的 Excel 绑定配置版本"
431
+ }
432
+ ],
433
+ mapped: 0,
434
+ total: 0
435
+ };
436
+ bt(o, r);
437
+ const n = t.sheets.find((a) => a.name === e.sheet)?.columnCount ?? 0, s = o.find((a) => a.id === e.dataset);
438
+ let i = 0;
439
+ return s ? r.some((a) => a.code === "schema") || (i = xt(e, s, n, r)) : u(
440
+ r,
441
+ "$.recipe.dataset",
442
+ "schema",
443
+ "请明确选择宿主提供的数据集契约"
444
+ ), { ok: r.length === 0, issues: r, mapped: i, total: n };
445
+ }
446
+ function vt(t, e, o) {
447
+ const r = Rt(t, e, o);
448
+ if (!e || e.version !== "1.0") return r;
449
+ const n = [
450
+ ...St(t, e),
451
+ ...r.issues
452
+ ];
453
+ return { ...r, ok: n.length === 0, issues: n };
454
+ }
455
+ function te(t, e, o, r) {
456
+ const n = vt(t, e, o);
457
+ if (!n.ok)
458
+ throw new Error(
459
+ n.issues.map((f) => `${f.path}: ${f.message}`).join(`
460
+ `)
461
+ );
462
+ const s = t.sheets.find((f) => f.name === e.sheet), i = {
463
+ ...t,
464
+ sheets: [{ ...s, pageStart: 0 }],
465
+ template: {
466
+ ...t.template,
467
+ pages: t.template.pages.slice(
468
+ s.pageStart,
469
+ s.pageStart + s.pageCount
470
+ )
471
+ }
472
+ }, a = new Map(
473
+ o.find((f) => f.id === e.dataset).fields.map((f) => [f.field, f])
474
+ ), c = {
475
+ sheet: e.sheet,
476
+ dataset: e.dataset,
477
+ header: e.regions.header,
478
+ detail: e.regions.detail,
479
+ rowKey: e.rowKey,
480
+ inferSampleFormats: !1,
481
+ columns: e.fields.map((f) => q(a.get(f)))
482
+ }, l = wt(i, [c]);
483
+ return {
484
+ document: z({ ...r, template: l.template }),
485
+ recipe: U(e),
486
+ warnings: l.warnings
487
+ };
488
+ }
489
+ function kt(t, e) {
490
+ if (t?.version !== "1.0" || !Array.isArray(t.fields) || t.fields.length > 16384 || t.fields.some((o) => typeof o != "string"))
491
+ throw new Error("Excel 绑定配置无效");
492
+ if (typeof t.dataset != "string" || typeof t.rowKey != "string" || !t.regions || typeof e?.id != "string" || typeof e.name != "string")
493
+ throw new Error("Excel 绑定参数或标识无效");
494
+ for (const o of Object.values(t.regions))
495
+ o !== "" && p(o);
496
+ }
497
+ function At(t) {
498
+ for (const e of t.sheets)
499
+ if (p(e.range), typeof e.name != "string" || ![e.index, e.rowCount, e.columnCount, e.pageCount].every(
500
+ (o) => Number.isInteger(o) && o > 0
501
+ ) || !Number.isInteger(e.pageStart) || e.pageStart < 0 || e.pageStart + e.pageCount > t.template.pages.length)
502
+ throw new Error("Excel 绑定工作表几何元数据无效");
503
+ }
504
+ function Ct(t, e, o) {
505
+ if (H({
506
+ sheets: t.sheets,
507
+ warnings: t.warnings,
508
+ recipe: e,
509
+ identity: o
510
+ }), !Array.isArray(t.sheets) || !t.sheets.length || t.sheets.length > 32 || !Array.isArray(t.warnings) || t.warnings.some((r) => typeof r != "string"))
511
+ throw new Error("Excel 绑定来源元数据无效");
512
+ if (kt(e, o), !t.sheets.some((r) => r.name === e.sheet))
513
+ throw new Error("Excel 绑定工作表不存在");
514
+ At(t);
515
+ }
516
+ function Bt(t, e, o) {
517
+ return Ct(t, e, o), Z({
518
+ schemaVersion: "1.0",
519
+ id: o.id,
520
+ name: o.name,
521
+ template: t.template
522
+ }), U({ version: "1.0", source: t, recipe: e, identity: o });
523
+ }
524
+ function ee(t) {
525
+ if (typeof t == "string" && t.length > 1e7)
526
+ throw new Error("Excel 绑定会话超过 1000 万字符上限");
527
+ const e = typeof t == "string" ? JSON.parse(t) : t;
528
+ if (!e || e.version !== "1.0" || e.recipe?.version !== "1.0" || !Array.isArray(e.source?.sheets))
529
+ throw new Error("Excel 绑定会话结构或版本无效");
530
+ return Bt(
531
+ e.source,
532
+ e.recipe,
533
+ e.identity
534
+ );
535
+ }
536
+ function oe(t, e, o, r) {
537
+ const n = t.sheets.find((c) => c.name === e);
538
+ if (!n) throw new Error("工作表不存在");
539
+ const s = p(n.range), i = Math.min(o, r), a = Math.max(o, r);
540
+ if (!Number.isInteger(i) || !Number.isInteger(a) || i < s.top || a > s.bottom)
541
+ throw new Error("选中行超出来源区域");
542
+ return $({ ...s, top: i, bottom: a });
543
+ }
544
+ function P(t, e, o) {
545
+ const r = t ?? e;
546
+ if (!Number.isInteger(r) || r < 1 || r > o)
547
+ throw new Error(`预览窗口大小应为 1–${o} 的整数`);
548
+ return r;
549
+ }
550
+ function Y(t, e, o) {
551
+ const r = t ?? e;
552
+ if (!Number.isInteger(r)) throw new Error("预览起点应为整数");
553
+ return Math.max(e, Math.min(o, r));
554
+ }
555
+ function re(t, e, o = {}) {
556
+ const r = t.sheets.find((g) => g.name === e);
557
+ if (!r) throw new Error("指定的工作表不存在");
558
+ const n = p(r.range), s = Y(o.row, n.top, n.bottom), i = Y(o.column, n.left, n.right), a = Math.min(
559
+ n.bottom,
560
+ s + P(o.rows, 24, 100) - 1
561
+ ), c = Math.min(
562
+ n.right,
563
+ i + P(o.columns, 12, 32) - 1
564
+ ), l = Array.from({ length: a - s + 1 }, (g, m) => ({
565
+ row: s + m,
566
+ cells: []
567
+ })), f = /* @__PURE__ */ new Set();
568
+ for (const g of t.template.pages.slice(
569
+ r.pageStart,
570
+ r.pageStart + r.pageCount
571
+ ))
572
+ for (const m of g.components) {
573
+ if (m.kind === "list" || !m.grid || m.meta?.xlsxSheet !== e)
574
+ continue;
575
+ const d = p(String(m.meta.xlsxRange));
576
+ if (d.bottom < s || d.top > a) continue;
577
+ const w = N(
578
+ m.grid,
579
+ m.widthMm,
580
+ m.heightMm
581
+ );
582
+ for (const M of w.cells)
583
+ h(M.cell, d.top + M.ri, d.left + M.ci);
584
+ }
585
+ for (const g of l) {
586
+ for (let m = i; m <= c; m++)
587
+ f.has(`${g.row}:${m}`) || g.cells.push({
588
+ address: `${v(m)}${g.row}`,
589
+ row: g.row,
590
+ column: m,
591
+ text: "",
592
+ rowSpan: 1,
593
+ colSpan: 1,
594
+ continued: !1
595
+ });
596
+ g.cells.sort((m, d) => m.column - d.column);
597
+ }
598
+ return {
599
+ top: s,
600
+ bottom: a,
601
+ left: i,
602
+ right: c,
603
+ source: n,
604
+ rows: l,
605
+ columns: Array.from({ length: c - i + 1 }, (g, m) => ({
606
+ column: i + m,
607
+ name: v(i + m)
608
+ }))
609
+ };
610
+ function h(g, m, d) {
611
+ const w = m + (g.rowSpan ?? 1) - 1, M = d + (g.colSpan ?? 1) - 1;
612
+ if (w < s || m > a || M < i || d > c)
613
+ return;
614
+ const E = Math.max(s, m), b = Math.max(i, d), W = Math.min(a, w) - E + 1, _ = Math.min(c, M) - b + 1;
615
+ l[E - s].cells.push({
616
+ address: `${v(d)}${m}`,
617
+ row: E,
618
+ column: b,
619
+ text: g.text ?? g.rawText ?? String(g.value ?? ""),
620
+ rowSpan: W,
621
+ colSpan: _,
622
+ continued: E !== m || b !== d,
623
+ style: g.style
624
+ });
625
+ for (let T = E; T < E + W; T++)
626
+ for (let I = b; I < b + _; I++)
627
+ f.add(`${T}:${I}`);
628
+ }
629
+ }
630
+ function S(t) {
631
+ return JSON.parse(JSON.stringify(t));
632
+ }
633
+ function X(t, e) {
634
+ const o = t.sheets.find((a) => a.name === e);
635
+ if (!o) throw new Error("指定的工作表不存在");
636
+ const r = t.template.pages.slice(o.pageStart, o.pageStart + o.pageCount), n = r[0];
637
+ if (!n) throw new Error("工作表没有可绑定的页面");
638
+ const s = { page: n, range: p(o.range), widths: [], heights: /* @__PURE__ */ new Map(), cells: [], cellsByRow: /* @__PURE__ */ new Map(), topOffsets: /* @__PURE__ */ new Map() };
639
+ for (const a of r) for (const c of a.components) {
640
+ if (c.kind === "list" || !c.grid || c.meta?.xlsxSheet !== e) continue;
641
+ const l = p(String(c.meta.xlsxRange));
642
+ s.widths.length || (s.widths = [...c.grid.colWidthsMm ?? []]), c.grid.cells.forEach((f, h) => s.heights.set(l.top + h, c.grid.rowHeightsMm?.[h] ?? 6));
643
+ for (const f of N(c.grid, c.widthMm, c.heightMm).cells) {
644
+ const h = l.top + f.ri, g = l.left + f.ci;
645
+ s.cells.push({ top: h, left: g, bottom: h + (f.cell.rowSpan ?? 1) - 1, right: g + (f.cell.colSpan ?? 1) - 1, cell: f.cell });
646
+ }
647
+ }
648
+ if (s.widths.length !== s.range.right - s.range.left + 1 || s.heights.size !== s.range.bottom - s.range.top + 1)
649
+ throw new Error("来源工作表几何元数据不完整");
650
+ let i = 0;
651
+ for (let a = s.range.top; a <= s.range.bottom; a++)
652
+ s.topOffsets.set(a, i), i += s.heights.get(a);
653
+ s.topOffsets.set(s.range.bottom + 1, i);
654
+ for (const a of s.cells) for (let c = a.top; c <= a.bottom; c++) {
655
+ const l = s.cellsByRow.get(c) ?? [];
656
+ l.push(a), s.cellsByRow.set(c, l);
657
+ }
658
+ return s;
659
+ }
660
+ function tt(t, e) {
661
+ return t.left <= e.right && e.left <= t.right && t.top <= e.bottom && e.top <= t.bottom;
662
+ }
663
+ function R(t, e) {
664
+ return t.top <= e.top && t.bottom >= e.bottom && t.left <= e.left && t.right >= e.right;
665
+ }
666
+ function et(t, e) {
667
+ return t.widths.slice(e.left - t.range.left, e.right - t.range.left + 1).reduce((o, r) => o + r, 0);
668
+ }
669
+ function C(t, e) {
670
+ return (t.topOffsets.get(e.bottom + 1) ?? 0) - (t.topOffsets.get(e.top) ?? 0);
671
+ }
672
+ function A(t, e) {
673
+ const o = /* @__PURE__ */ new Set();
674
+ for (let r = e.top; r <= e.bottom; r++) for (const n of t.cellsByRow.get(r) ?? []) tt(n, e) && o.add(n);
675
+ return [...o];
676
+ }
677
+ function ot(t, e) {
678
+ for (const o of A(t, e)) if (!R(e, o)) throw new Error(`合并区域 ${$(o)} 跨越选区 ${$(e)}`);
679
+ }
680
+ function j(t, e, o = []) {
681
+ const r = A(t, e);
682
+ for (const a of r) if (!R(e, a)) throw new Error(`合并区域 ${$(a)} 跨越选区 ${$(e)}`);
683
+ const n = [], s = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
684
+ for (const a of r)
685
+ if (!o.some((c) => R(c, a))) {
686
+ s.set(`${a.top}:${a.left}`, a);
687
+ for (let c = a.top; c <= a.bottom; c++) for (let l = a.left; l <= a.right; l++) i.add(`${c}:${l}`);
688
+ }
689
+ for (let a = e.top; a <= e.bottom; a++) {
690
+ const c = [];
691
+ for (let l = e.left; l <= e.right; l++) {
692
+ const f = s.get(`${a}:${l}`);
693
+ f ? (c.push(S(f.cell)), l = f.right) : i.has(`${a}:${l}`) || c.push(null);
694
+ }
695
+ n.push(c);
696
+ }
697
+ return { cells: n, colWidthsMm: t.widths.slice(e.left - t.range.left, e.right - t.range.left + 1), rowHeightsMm: Array.from({ length: e.bottom - e.top + 1 }, (a, c) => t.heights.get(e.top + c)), paddingMm: 0.25 };
698
+ }
699
+ function k(t) {
700
+ const e = p(t.range);
701
+ return t.headerRange ? { ...e, top: p(t.headerRange).top } : e;
702
+ }
703
+ function J(t, e) {
704
+ return (t.page.marginTopMm ?? 0) + (t.topOffsets.get(e) ?? 0);
705
+ }
706
+ function rt(t, e) {
707
+ return { xlsxFlow: { version: "1.0", columnStart: e.left - t.range.left } };
708
+ }
709
+ function nt(t, e, o, r, n = []) {
710
+ const s = j(t, o, n);
711
+ for (const i of s.cells) for (const a of i) a && (a.editable = !1, delete a.source);
712
+ return { kind: "rect", nid: r, leftMm: t.page.marginLeftMm ?? 0, topMm: J(t, o.top), widthMm: et(t, o), heightMm: C(t, o), grid: s, meta: rt(t, o) };
713
+ }
714
+ function Ot(t, e, o, r) {
715
+ const n = p(o.range), s = k(o), i = j(t, n), a = new Map(r.fields.map((f) => [f.field, f])), c = i.colWidthsMm, l = o.fields.map((f, h) => ({ ...q(a.get(f)), header: a.get(f).label ?? f, widthMm: c[h], style: S(i.cells[0]?.[h]?.style ?? {}), align: "auto" }));
716
+ return {
717
+ kind: "list",
718
+ id: `xlsx-region:${o.id}`,
719
+ dataset: o.dataset,
720
+ rowKey: o.rowKey,
721
+ ...o.revisionField ? { revisionField: o.revisionField } : {},
722
+ ...o.sourceTokenField ? { sourceTokenField: o.sourceTokenField } : {},
723
+ title: `${e.sheet} · ${o.id}`,
724
+ layout: t.page.layout ?? "wide",
725
+ leftMm: (t.page.marginLeftMm ?? 0) + t.widths.slice(0, n.left - t.range.left).reduce((f, h) => f + h, 0),
726
+ topMm: J(t, s.top),
727
+ widthMm: et(t, n),
728
+ rowHeightMm: i.rowHeightsMm[0],
729
+ header: !!o.headerRange,
730
+ headerEveryPage: o.mode === "repeat",
731
+ ...o.mode === "record" ? { cardinality: "record" } : {},
732
+ ...o.headerRange ? { headerGrid: j(t, p(o.headerRange)) } : {},
733
+ columns: l,
734
+ paddingMm: i.paddingMm,
735
+ meta: rt(t, n)
736
+ };
737
+ }
738
+ function V(t, e, o, r = 0) {
739
+ const n = [], s = t.page.heightMm - (t.page.marginTopMm ?? 0) - (t.page.marginBottomMm ?? 0) - r, i = Math.max(1, Math.min(100, Math.floor(1e4 / t.widths.length)));
740
+ for (let a = e; a <= o; ) {
741
+ const c = a;
742
+ let l = a, f = 0;
743
+ for (; a <= o; ) {
744
+ let h = a;
745
+ for (let m = a; m <= h; m++) for (const d of t.cellsByRow.get(m) ?? []) h = Math.max(h, d.bottom);
746
+ if (h > o) throw new Error("静态合并区域跨越动态绑定边界,请调整区域");
747
+ const g = C(t, { ...t.range, top: a, bottom: h });
748
+ if (a > c && (h - c + 1 > i || f + g > s)) break;
749
+ if (g > s) throw new Error("静态合并区域高度超过单页可用高度,请调整原始模板");
750
+ f += g, l = h, a = h + 1;
751
+ }
752
+ n.push({ range: { ...t.range, top: c, bottom: l }, bindings: [] });
753
+ }
754
+ return n;
755
+ }
756
+ function Ft(t, e) {
757
+ const o = [...e.regions].sort((a, c) => k(a).top - k(c).top), r = [];
758
+ let n = t.range.top;
759
+ const s = e.footerRange ? C(t, p(e.footerRange)) : 0;
760
+ for (const a of o) {
761
+ const c = k(a), l = r[r.length - 1];
762
+ if (l?.bindings.length && l.range.top === c.top && l.range.bottom === c.bottom) {
763
+ l.bindings.push(a);
764
+ continue;
765
+ }
766
+ n < c.top && r.push(...V(t, n, c.top - 1, s)), r.push({ range: { ...t.range, top: c.top, bottom: c.bottom }, bindings: [a] }), n = c.bottom + 1;
767
+ }
768
+ const i = e.footerRange ? p(e.footerRange).top - 1 : t.range.bottom;
769
+ return n <= i && r.push(...V(t, n, i, s)), r;
770
+ }
771
+ function Nt(t, e, o, r, n) {
772
+ const s = [], i = o.bindings.map(k), a = o.bindings.some((l) => l.mode === "repeat"), c = A(t, o.range).some((l) => !i.some((f) => R(f, l)));
773
+ !a && (!o.bindings.length || c) && s.push(nt(t, e, o.range, `xlsx-static:${r}`, i));
774
+ for (const l of o.bindings) s.push(Ot(t, e, l, n.find((f) => f.id === l.dataset)));
775
+ return { components: s, flow: { componentIds: s.map((l) => l.kind === "list" ? l.id : l.nid), topMm: J(t, o.range.top), heightMm: C(t, o.range) } };
776
+ }
777
+ function Tt(t, e, o, r) {
778
+ const n = X(t, e.sheet), s = { ...S(n.page), components: [] }, i = Ft(n, e).map((a, c) => Nt(n, e, a, c, o));
779
+ if (s.components = i.flatMap((a) => a.components), s.flow = { bands: i.map((a) => a.flow) }, s.meta = { xlsxFlow: { version: "1.0", templateId: r, sheet: e.sheet, fullWidthsMm: n.widths } }, e.footerRange) {
780
+ const a = p(e.footerRange), c = nt(n, e, a, "xlsx-footer");
781
+ c.pageAnchor = "footer", c.topMm = s.heightMm - (s.marginBottomMm ?? 0) - c.heightMm, s.components.push(c);
782
+ }
783
+ return { ...S(t.template), pages: [s] };
784
+ }
785
+ function x(t) {
786
+ return t instanceof Error ? t.message : String(t);
787
+ }
788
+ function y(t, e, o, r) {
789
+ t.push({ path: e, code: o, message: r });
790
+ }
791
+ function G(t, e, o = !1) {
792
+ const r = p(t);
793
+ if (!R(e.range, r)) throw new Error("绑定范围应完整位于来源工作表内");
794
+ if (o && r.top !== r.bottom) throw new Error("每个动态区域应选择一行原型;多个数据行由 repeat 自动扩展");
795
+ return ot(e, r), r;
796
+ }
797
+ function It(t) {
798
+ const e = t.cell;
799
+ return !!e.formula || !!e.children?.length || e.value !== null && e.value !== void 0 && e.value !== "" || !!e.text || !!e.rawText;
800
+ }
801
+ function Kt(t, e, o) {
802
+ if (!t.headerRange) return;
803
+ const r = G(t.headerRange, e);
804
+ if (r.left !== o.left || r.right !== o.right || r.bottom + 1 !== o.top) throw new Error("区域表头应与原型等列宽,并紧接原型上方");
805
+ return r;
806
+ }
807
+ function jt(t, e) {
808
+ const o = G(t.range, e, !0), r = Kt(t, e, o);
809
+ if (ot(e, { ...e.range, top: r?.top ?? o.top, bottom: o.bottom }), A(e, o).some((s) => s.bottom !== s.top || s.left !== s.right)) throw new Error("动态原型行不能包含合并格;请保留合并表头并选择其下方数据行");
810
+ if (t.mode === "repeat") {
811
+ const s = { ...e.range, top: r?.top ?? o.top, bottom: o.bottom };
812
+ if (A(e, s).some((i) => !R({ ...o, top: s.top }, i) && It(i))) throw new Error("纵向重复区域的旁列存在静态内容,无法安全拉伸;请扩大区域或将静态内容移至独立行");
813
+ }
814
+ return { ...o, top: r?.top ?? o.top };
815
+ }
816
+ function st(t) {
817
+ if (!t || t.version !== "2.0" || typeof t.sheet != "string" || !Array.isArray(t.regions) || !t.regions.length || t.regions.length > 128) throw new Error("多区域绑定应为 version 2.0,并包含 1–128 个区域");
818
+ }
819
+ function Ht(t, e) {
820
+ const o = [];
821
+ try {
822
+ st(e);
823
+ } catch (i) {
824
+ return [{ path: "$.recipe", code: "schema", message: x(i) }];
825
+ }
826
+ let r;
827
+ try {
828
+ r = X(t, e.sheet);
829
+ } catch (i) {
830
+ return [{ path: "$.recipe.sheet", code: "source", message: x(i) }];
831
+ }
832
+ const n = /* @__PURE__ */ new Set(), s = [];
833
+ if (e.regions.forEach((i, a) => {
834
+ const c = `$.recipe.regions[${a}]`;
835
+ try {
836
+ if (!i || typeof i.id != "string" || !i.id.trim() || n.has(i.id)) throw new Error("区域标识应非空且唯一");
837
+ if (n.add(i.id), !["record", "repeat"].includes(i.mode)) throw new Error("区域模式应为 record 或 repeat");
838
+ const l = jt(i, r);
839
+ for (const f of s) {
840
+ if (tt(l, f.range)) throw new Error(`区域与 ${f.path} 重叠(含表头)`);
841
+ if (l.top <= f.range.bottom && f.range.top <= l.bottom && (i.mode === "repeat" || f.mode === "repeat")) throw new Error("同一行不能并排放置重复区域;请按纵向顺序排列");
842
+ if (l.top <= f.range.bottom && f.range.top <= l.bottom && (l.top !== f.range.top || l.bottom !== f.range.bottom)) throw new Error("并排单记录区域应使用相同的起止行(包括表头),避免不明确的位移");
843
+ }
844
+ s.push({ range: l, mode: i.mode, path: c });
845
+ } catch (l) {
846
+ y(o, c, "region", x(l));
847
+ }
848
+ }), e.footerRange) try {
849
+ const i = G(e.footerRange, r);
850
+ if (i.left !== r.range.left || i.right !== r.range.right || i.bottom !== r.range.bottom) throw new Error("重复页尾应覆盖完整列宽并位于来源最后几行");
851
+ if (s.some((a) => a.range.bottom >= i.top)) throw new Error("页尾与动态区域或区域表头相交");
852
+ if (C(r, i) >= r.page.heightMm - (r.page.marginTopMm ?? 0) - (r.page.marginBottomMm ?? 0)) throw new Error("页尾高度占满单页,不能为报表明细预留空间");
853
+ } catch (i) {
854
+ y(o, "$.recipe.footerRange", "region", x(i));
855
+ }
856
+ return o;
857
+ }
858
+ function Jt(t, e) {
859
+ const o = /* @__PURE__ */ new Map();
860
+ for (const [r, n] of t.entries()) try {
861
+ if (!n || typeof n.id != "string" || !n.id.trim() || o.has(n.id)) throw new Error("数据集标识应非空且唯一");
862
+ F([], { fields: n.fields, ...n.rowKey ? { rowKey: n.rowKey } : {} });
863
+ for (const s of n.fields) if (s.digits !== void 0 && (!Number.isInteger(s.digits) || s.digits < 0 || s.digits > 100)) throw new Error("显示精度应为 0–100 的整数");
864
+ o.set(n.id, n);
865
+ } catch (s) {
866
+ y(e, `$.datasets[${r}]`, "schema", x(s));
867
+ }
868
+ return o;
869
+ }
870
+ function Gt(t, e, o, r) {
871
+ const n = p(t.range), s = n.right - n.left + 1;
872
+ if (!Array.isArray(t.fields) || t.fields.length !== s)
873
+ return y(r, `${o}.fields`, "mapping", "区域每个物理列应显式绑定一个字段"), 0;
874
+ const i = new Set(e.fields.map((l) => l.field)), a = /* @__PURE__ */ new Set();
875
+ let c = 0;
876
+ if (t.fields.forEach((l, f) => {
877
+ !i.has(l) || a.has(l) ? y(r, `${o}.fields[${f}]`, "mapping", "请选择契约内已声明且不重复的字段") : (a.add(l), c++);
878
+ }), !t.rowKey) y(r, `${o}.rowKey`, "row-key", "每个区域应声明稳定业务主键");
879
+ else {
880
+ const l = F(e.samples ?? [], { fields: e.fields, rowKey: t.rowKey }, { path: `$.datasets.${e.id}.samples`, maxRows: 100, maxIssues: 30 });
881
+ for (const f of l.issues) y(r, f.path, f.code === "row-key" ? "row-key" : "schema", f.message);
882
+ }
883
+ for (const l of ["revisionField", "sourceTokenField"]) t[l] !== void 0 && !i.has(t[l]) && y(r, `${o}.${l}`, "source", "并发字段应引用同一区域数据集契约内的字段");
884
+ return t.mode === "record" && (e.samples?.length ?? 0) > 1 && y(r, o, "schema", "record 区域数据集最多一行;多行请使用 repeat"), c;
885
+ }
886
+ function Wt(t, e) {
887
+ const o = [];
888
+ try {
889
+ st(t);
890
+ } catch (i) {
891
+ return { ok: !1, issues: [{ path: "$.recipe", code: "schema", message: x(i) }], mapped: 0, total: 0 };
892
+ }
893
+ const r = Jt(e, o);
894
+ let n = 0, s = 0;
895
+ for (const [i, a] of t.regions.entries()) {
896
+ const c = `$.recipe.regions[${i}]`;
897
+ try {
898
+ const l = p(a.range);
899
+ s += l.right - l.left + 1;
900
+ const f = r.get(a.dataset);
901
+ f ? n += Gt(a, f, c, o) : y(o, `${c}.dataset`, "source", "请选择宿主提供的数据集契约");
902
+ } catch (l) {
903
+ y(o, c, "schema", x(l));
904
+ }
905
+ }
906
+ return { ok: o.length === 0, issues: o, mapped: n, total: s };
907
+ }
908
+ function _t(t, e, o) {
909
+ const r = Wt(e, o), n = [...Ht(t, e), ...r.issues];
910
+ return { ...r, ok: !n.length, issues: n };
911
+ }
912
+ function ne(t, e, o, r) {
913
+ const n = _t(t, e, o);
914
+ if (!n.ok) throw new Error(n.issues.map((s) => `${s.path}: ${s.message}`).join(`
915
+ `));
916
+ return {
917
+ document: z({ ...r, template: Tt(t, e, o, r.id) }),
918
+ recipe: S(e),
919
+ warnings: [...t.warnings]
920
+ };
921
+ }
922
+ function Dt(t) {
923
+ if (!t || t.version !== "2.0" || typeof t.sheet != "string" || !Array.isArray(t.regions) || !t.regions.length || t.regions.length > 128) throw new Error("多区域绑定会话配置或版本无效");
924
+ for (const e of t.regions) {
925
+ if (!e || typeof e.id != "string" || typeof e.dataset != "string" || typeof e.rowKey != "string" || !["record", "repeat"].includes(e.mode) || !Array.isArray(e.fields) || e.fields.length > 2048 || e.fields.some((o) => typeof o != "string")) throw new Error("多区域绑定会话的区域结构无效");
926
+ e.range && p(e.range), e.headerRange && p(e.headerRange);
927
+ }
928
+ t.footerRange && p(t.footerRange);
929
+ }
930
+ function Lt(t, e, o) {
931
+ if (H({ sheets: t.sheets, warnings: t.warnings, recipe: e, identity: o }), Dt(e), !Array.isArray(t.sheets) || !t.sheets.length || !Array.isArray(t.warnings) || t.warnings.some((r) => typeof r != "string") || !t.sheets.some((r) => r.name === e.sheet)) throw new Error("多区域绑定会话的来源无效");
932
+ for (const r of t.sheets)
933
+ if (p(r.range), ![r.index, r.rowCount, r.columnCount, r.pageCount].every((n) => Number.isInteger(n) && n > 0) || !Number.isInteger(r.pageStart) || r.pageStart < 0 || r.pageStart + r.pageCount > t.template.pages.length) throw new Error("多区域绑定会话的工作表几何无效");
934
+ return Z({ schemaVersion: "1.0", ...o, template: t.template }), S({ version: "2.0", source: t, recipe: e, identity: o });
935
+ }
936
+ function se(t) {
937
+ if (typeof t == "string" && t.length > 1e7) throw new Error("绑定会话超过 1000 万字符上限");
938
+ const e = typeof t == "string" ? JSON.parse(t) : t;
939
+ if (!e || e.version !== "2.0" || !e.source || !e.recipe || !e.identity) throw new Error("多区域绑定会话结构或版本无效");
940
+ return Lt(e.source, e.recipe, e.identity);
941
+ }
942
+ function ae(t, e, o, r = o) {
943
+ const n = t.sheets.find((a) => a.name === e);
944
+ if (!n) throw new Error("工作表不存在");
945
+ const s = p(n.range);
946
+ if (![o.row, o.column, r.row, r.column].every(Number.isInteger)) throw new Error("单元格坐标应为整数");
947
+ const i = { top: Math.min(o.row, r.row), bottom: Math.max(o.row, r.row), left: Math.min(o.column, r.column), right: Math.max(o.column, r.column) };
948
+ if (i.top < s.top || i.bottom > s.bottom || i.left < s.left || i.right > s.right) throw new Error("选区超出来源工作表");
949
+ return $(i);
950
+ }
951
+ export {
952
+ Bt as a,
953
+ wt as b,
954
+ te as c,
955
+ ne as d,
956
+ Lt as e,
957
+ ae as f,
958
+ oe as g,
959
+ re as h,
960
+ se as i,
961
+ vt as j,
962
+ St as k,
963
+ _t as l,
964
+ Wt as m,
965
+ Ht as n,
966
+ p as o,
967
+ ee as p,
968
+ v as q,
969
+ Zt as r,
970
+ zt as s,
971
+ $ as t,
972
+ qt as u,
973
+ Rt as v,
974
+ Ut as w,
975
+ Qt as x,
976
+ Xt as y
977
+ };