@veltra/sheet 2.0.1 → 2.2.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 (339) hide show
  1. package/dist/components/report/binding-badge.js +76 -0
  2. package/dist/components/report/designer/cell-coords.js +46 -0
  3. package/dist/components/report/designer/col-widths.js +15 -0
  4. package/dist/components/report/designer/conditional-rules/helpers.js +139 -0
  5. package/dist/components/report/designer/drop-highlight-overlay.js +76 -0
  6. package/dist/components/report/designer/float-panel.js +385 -0
  7. package/dist/components/report/designer/role.js +17 -0
  8. package/dist/components/report/designer/rule-preview.js +33 -0
  9. package/dist/components/report/designer/rule-row.js +269 -0
  10. package/dist/components/report/designer/rules-dialog.js +135 -0
  11. package/dist/components/report/designer/topology-overlay.js +122 -0
  12. package/dist/components/report/designer/topology.js +64 -0
  13. package/dist/components/report/designer/use-grid-overlay.js +75 -0
  14. package/dist/components/report/designer-hub.js +177 -0
  15. package/dist/components/report/field-panel-helpers.js +33 -0
  16. package/dist/components/report/field-panel.js +132 -0
  17. package/dist/components/report/filter-bar.js +74 -0
  18. package/dist/components/report/hub-connection-form.js +145 -0
  19. package/dist/components/report/hub-dataset-editor.js +394 -0
  20. package/dist/components/report/report-designer.js +343 -0
  21. package/dist/components/report/report-viewer.js +111 -0
  22. package/dist/components/report/style.d.ts +17 -0
  23. package/dist/components/report/style.js +18 -0
  24. package/dist/components/report/style2.css +869 -0
  25. package/dist/components/report/use-report-designer.js +360 -0
  26. package/dist/components/report/use-report-viewer.js +50 -0
  27. package/dist/components/sheet/formula-bar.js +393 -0
  28. package/dist/components/sheet/formula-suggest-list.js +66 -0
  29. package/dist/components/sheet/import-file.js +140 -0
  30. package/dist/components/sheet/insert-count-menu-item.js +68 -0
  31. package/dist/components/sheet/insert-image.js +79 -0
  32. package/dist/components/sheet/popup-helpers.js +73 -0
  33. package/dist/components/sheet/popups/border-popup.js +75 -0
  34. package/dist/components/sheet/popups/border-preset-glyph.js +106 -0
  35. package/dist/components/sheet/popups/export-popup.js +51 -0
  36. package/dist/components/sheet/popups/fill-color-popup.js +37 -0
  37. package/dist/components/sheet/popups/find-popup.js +113 -0
  38. package/dist/components/sheet/popups/font-color-popup.js +37 -0
  39. package/dist/components/sheet/popups/font-size-popup.js +63 -0
  40. package/dist/components/sheet/popups/import.worker.d.ts +21 -0
  41. package/dist/components/sheet/popups/import.worker.js +41 -0
  42. package/dist/components/sheet/popups/insert-image-popup.js +38 -0
  43. package/dist/components/sheet/sheet-context-menu.js +200 -0
  44. package/dist/components/sheet/sheet-tabs.js +162 -0
  45. package/dist/components/sheet/sheet-toolbar.js +106 -0
  46. package/dist/components/sheet/sheet.js +198 -0
  47. package/dist/components/sheet/style.d.ts +11 -0
  48. package/dist/components/sheet/style.js +12 -0
  49. package/dist/components/sheet/style2.css +654 -0
  50. package/dist/components/sheet/use-find-replace.js +161 -0
  51. package/dist/components/sheet/use-formula-ref-select.js +37 -0
  52. package/dist/components/sheet/use-formula-suggest.js +126 -0
  53. package/dist/components/sheet/use-sheet-grid.js +188 -0
  54. package/dist/components/sheet/use-sheet-state.js +122 -0
  55. package/dist/components/sheet/use-sheet-tabs-bar.js +90 -0
  56. package/dist/components/sheet/use-tool-groups.js +42 -0
  57. package/dist/components/sheet/use-tool-popup.js +123 -0
  58. package/dist/components/sheet/use-toolbar-scroll.js +72 -0
  59. package/dist/index.d.ts +18 -26
  60. package/dist/index.js +14 -24
  61. package/dist/report/binding.d.ts +45 -0
  62. package/dist/report/binding.js +175 -0
  63. package/dist/report/connector.d.ts +66 -0
  64. package/dist/report/connector.js +159 -0
  65. package/dist/report/export-xlsx.d.ts +19 -0
  66. package/dist/report/export-xlsx.js +95 -0
  67. package/dist/report/filter-bar.d.ts +10 -0
  68. package/dist/report/filter-bar.js +31 -0
  69. package/dist/report/index.d.ts +12 -0
  70. package/dist/report/params.d.ts +13 -0
  71. package/dist/report/params.js +61 -0
  72. package/dist/report/render/aggregate.js +157 -0
  73. package/dist/report/render/builder.d.ts +12 -0
  74. package/dist/report/render/builder.js +139 -0
  75. package/dist/report/render/coordinate.d.ts +25 -0
  76. package/dist/report/render/coordinate.js +733 -0
  77. package/dist/report/render/index.d.ts +14 -0
  78. package/dist/report/render/index.js +21 -0
  79. package/dist/report/render/style-resolver.js +50 -0
  80. package/dist/report/render/template-index.d.ts +24 -0
  81. package/dist/report/render/template-index.js +137 -0
  82. package/dist/report/rules/evaluate.d.ts +25 -0
  83. package/dist/report/rules/evaluate.js +82 -0
  84. package/dist/report/rules/index.d.ts +2 -0
  85. package/dist/report/template.d.ts +59 -0
  86. package/dist/report/template.js +80 -0
  87. package/dist/report/types.d.ts +85 -0
  88. package/dist/tools/builtin.js +279 -8
  89. package/dist/tools/context.d.ts +54 -11
  90. package/dist/tools/context.js +28 -5
  91. package/dist/tools/download.js +68 -0
  92. package/dist/tools/export.worker.d.ts +16 -0
  93. package/dist/tools/export.worker.js +29 -0
  94. package/dist/tools/registry.d.ts +7 -4
  95. package/dist/tools/registry.js +1 -3
  96. package/dist/types/index.d.ts +3 -1
  97. package/dist/types/report-designer.d.ts +36 -0
  98. package/dist/types/report-viewer.d.ts +38 -0
  99. package/dist/types/sheet.d.ts +22 -5
  100. package/package.json +10 -7
  101. package/src/components/report/__test__/conditional-rules-helpers.test.ts +87 -0
  102. package/src/components/report/__test__/field-panel-helpers.test.ts +65 -0
  103. package/src/components/report/__test__/float-panel-position.test.ts +45 -0
  104. package/src/components/report/__test__/report-designer.test.ts +388 -0
  105. package/src/components/report/__test__/report-viewer.test.ts +334 -0
  106. package/src/components/report/__test__/topology.test.ts +143 -0
  107. package/src/components/report/__test__/use-report-designer.test.ts +565 -0
  108. package/src/components/report/binding-badge.ts +73 -0
  109. package/src/components/report/designer/cell-coords.ts +94 -0
  110. package/src/components/report/designer/col-widths.ts +33 -0
  111. package/src/components/report/designer/conditional-rules/helpers.ts +186 -0
  112. package/src/components/report/designer/drop-highlight-overlay.vue +74 -0
  113. package/src/components/report/designer/float-panel.vue +387 -0
  114. package/src/components/report/designer/role.ts +32 -0
  115. package/src/components/report/designer/rule-preview.vue +40 -0
  116. package/src/components/report/designer/rule-row.vue +252 -0
  117. package/src/components/report/designer/rules-dialog.vue +126 -0
  118. package/src/components/report/designer/topology-overlay.vue +127 -0
  119. package/src/components/report/designer/topology.ts +124 -0
  120. package/src/components/report/designer/use-grid-overlay.ts +113 -0
  121. package/src/components/report/designer-hub.vue +198 -0
  122. package/src/components/report/field-panel-helpers.ts +44 -0
  123. package/src/components/report/field-panel.vue +136 -0
  124. package/src/components/report/filter-bar.vue +77 -0
  125. package/src/components/report/hub-connection-form.vue +124 -0
  126. package/src/components/report/hub-dataset-editor.vue +369 -0
  127. package/src/components/report/index.ts +2 -0
  128. package/src/components/report/report-designer.vue +356 -0
  129. package/src/components/report/report-viewer.vue +128 -0
  130. package/src/components/report/style-designer.scss +583 -0
  131. package/src/components/report/style-hub.scss +292 -0
  132. package/src/components/report/style-viewer.scss +104 -0
  133. package/src/components/report/style.scss +3 -0
  134. package/src/components/report/style.ts +20 -0
  135. package/src/components/report/use-report-designer.ts +547 -0
  136. package/src/components/report/use-report-viewer.ts +79 -0
  137. package/src/components/sheet/__test__/formula-bar.test.ts +474 -0
  138. package/src/components/sheet/__test__/import-file.test.ts +183 -0
  139. package/src/components/sheet/__test__/insert-count-menu-item.test.ts +123 -0
  140. package/src/components/sheet/__test__/insert-image-popup.test.ts +89 -0
  141. package/src/components/sheet/__test__/insert-image.test.ts +100 -0
  142. package/src/components/sheet/__test__/sheet-component.test.ts +993 -0
  143. package/src/components/sheet/__test__/sheet-context-menu.test.ts +206 -0
  144. package/src/components/sheet/__test__/use-formula-ref-select.test.ts +35 -0
  145. package/src/components/sheet/__test__/use-formula-suggest.test.ts +83 -0
  146. package/src/components/sheet/formula-bar.vue +473 -0
  147. package/src/components/sheet/formula-suggest-list.vue +64 -0
  148. package/src/components/sheet/import-file.ts +173 -0
  149. package/src/components/sheet/insert-count-menu-item.vue +69 -0
  150. package/src/components/sheet/insert-image.ts +90 -0
  151. package/src/components/sheet/parsing.ts +11 -0
  152. package/src/components/sheet/popup-helpers.ts +50 -0
  153. package/src/components/sheet/popups/border-popup.vue +93 -0
  154. package/src/components/sheet/popups/border-preset-glyph.vue +111 -0
  155. package/src/components/sheet/popups/export-popup.vue +52 -0
  156. package/src/components/sheet/popups/fill-color-popup.vue +39 -0
  157. package/src/components/sheet/popups/find-popup.vue +111 -0
  158. package/src/components/sheet/popups/font-color-popup.vue +39 -0
  159. package/src/components/sheet/popups/font-size-popup.vue +52 -0
  160. package/src/components/sheet/popups/import.worker.ts +66 -0
  161. package/src/components/sheet/popups/insert-image-popup.vue +39 -0
  162. package/src/components/sheet/sheet-context-menu.ts +229 -0
  163. package/src/components/sheet/sheet-tabs.vue +162 -0
  164. package/src/components/sheet/sheet-toolbar.vue +91 -0
  165. package/src/components/sheet/sheet.vue +211 -0
  166. package/src/components/sheet/style.scss +737 -0
  167. package/src/components/sheet/style.ts +13 -0
  168. package/src/components/sheet/use-find-replace.ts +200 -0
  169. package/src/components/sheet/use-formula-ref-select.ts +34 -0
  170. package/src/components/sheet/use-formula-suggest.ts +150 -0
  171. package/src/components/sheet/use-sheet-grid.ts +247 -0
  172. package/src/components/sheet/use-sheet-state.ts +161 -0
  173. package/src/components/sheet/use-sheet-tabs-bar.ts +115 -0
  174. package/src/components/sheet/use-tool-groups.ts +61 -0
  175. package/src/components/sheet/use-tool-popup.ts +150 -0
  176. package/src/components/sheet/use-toolbar-scroll.ts +95 -0
  177. package/src/env.d.ts +11 -0
  178. package/src/index.ts +39 -14
  179. package/src/report/__test__/binding.test.ts +218 -0
  180. package/src/report/__test__/connector.test.ts +218 -0
  181. package/src/report/__test__/export-xlsx.test.ts +118 -0
  182. package/src/report/__test__/filter-bar.test.ts +58 -0
  183. package/src/report/__test__/params.test.ts +156 -0
  184. package/src/report/__test__/render.test.ts +728 -0
  185. package/src/report/__test__/rules.test.ts +131 -0
  186. package/src/report/__test__/template.test.ts +355 -0
  187. package/src/report/binding.ts +243 -0
  188. package/src/report/connector.ts +205 -0
  189. package/src/report/export-xlsx.ts +118 -0
  190. package/src/report/filter-bar.ts +36 -0
  191. package/src/report/index.ts +13 -0
  192. package/src/report/params.ts +96 -0
  193. package/src/report/render/__test__/aggregate.test.ts +16 -0
  194. package/src/report/render/__test__/coordinate.test.ts +405 -0
  195. package/src/report/render/aggregate.ts +240 -0
  196. package/src/report/render/builder.ts +211 -0
  197. package/src/report/render/coordinate.ts +1239 -0
  198. package/src/report/render/index.ts +30 -0
  199. package/src/report/render/style-resolver.ts +68 -0
  200. package/src/report/render/template-index.ts +200 -0
  201. package/src/report/rules/evaluate.ts +113 -0
  202. package/src/report/rules/index.ts +7 -0
  203. package/src/report/template.ts +141 -0
  204. package/src/report/types.ts +96 -0
  205. package/src/tools/__test__/builtin.test.ts +208 -66
  206. package/src/tools/__test__/context.test.ts +62 -2
  207. package/src/tools/builtin.ts +350 -6
  208. package/src/tools/context.ts +89 -11
  209. package/src/tools/download.ts +82 -0
  210. package/src/tools/export.worker.ts +61 -0
  211. package/src/tools/registry.ts +16 -1
  212. package/src/types/index.ts +2 -0
  213. package/src/types/report-designer.ts +36 -0
  214. package/src/types/report-viewer.ts +37 -0
  215. package/src/types/sheet.ts +26 -3
  216. package/dist/core/address.d.ts +0 -60
  217. package/dist/core/address.js +0 -142
  218. package/dist/core/address.js.map +0 -1
  219. package/dist/core/cell-store.d.ts +0 -61
  220. package/dist/core/cell-store.js +0 -135
  221. package/dist/core/cell-store.js.map +0 -1
  222. package/dist/core/command/default-registry.d.ts +0 -10
  223. package/dist/core/command/default-registry.js +0 -18
  224. package/dist/core/command/default-registry.js.map +0 -1
  225. package/dist/core/command/history.d.ts +0 -64
  226. package/dist/core/command/history.js +0 -127
  227. package/dist/core/command/history.js.map +0 -1
  228. package/dist/core/command/merge-cells.d.ts +0 -21
  229. package/dist/core/command/merge-cells.js +0 -74
  230. package/dist/core/command/merge-cells.js.map +0 -1
  231. package/dist/core/command/registry.d.ts +0 -17
  232. package/dist/core/command/registry.js +0 -26
  233. package/dist/core/command/registry.js.map +0 -1
  234. package/dist/core/command/set-cell-formula.d.ts +0 -17
  235. package/dist/core/command/set-cell-formula.js +0 -29
  236. package/dist/core/command/set-cell-formula.js.map +0 -1
  237. package/dist/core/command/set-cell-value.d.ts +0 -22
  238. package/dist/core/command/set-cell-value.js +0 -35
  239. package/dist/core/command/set-cell-value.js.map +0 -1
  240. package/dist/core/command/types.d.ts +0 -68
  241. package/dist/core/events.js +0 -29
  242. package/dist/core/events.js.map +0 -1
  243. package/dist/core/fill.d.ts +0 -34
  244. package/dist/core/fill.js +0 -320
  245. package/dist/core/fill.js.map +0 -1
  246. package/dist/core/formula/ast.d.ts +0 -58
  247. package/dist/core/formula/ast.js +0 -38
  248. package/dist/core/formula/ast.js.map +0 -1
  249. package/dist/core/formula/dependency-graph.d.ts +0 -70
  250. package/dist/core/formula/dependency-graph.js +0 -269
  251. package/dist/core/formula/dependency-graph.js.map +0 -1
  252. package/dist/core/formula/errors.d.ts +0 -25
  253. package/dist/core/formula/errors.js +0 -36
  254. package/dist/core/formula/errors.js.map +0 -1
  255. package/dist/core/formula/evaluator.d.ts +0 -41
  256. package/dist/core/formula/evaluator.js +0 -154
  257. package/dist/core/formula/evaluator.js.map +0 -1
  258. package/dist/core/formula/functions.d.ts +0 -30
  259. package/dist/core/formula/functions.js +0 -209
  260. package/dist/core/formula/functions.js.map +0 -1
  261. package/dist/core/formula/parser.d.ts +0 -7
  262. package/dist/core/formula/parser.js +0 -208
  263. package/dist/core/formula/parser.js.map +0 -1
  264. package/dist/core/formula/tokenizer.d.ts +0 -37
  265. package/dist/core/formula/tokenizer.js +0 -146
  266. package/dist/core/formula/tokenizer.js.map +0 -1
  267. package/dist/core/merge-manager.d.ts +0 -64
  268. package/dist/core/merge-manager.js +0 -111
  269. package/dist/core/merge-manager.js.map +0 -1
  270. package/dist/core/selection.d.ts +0 -31
  271. package/dist/core/selection.js +0 -62
  272. package/dist/core/selection.js.map +0 -1
  273. package/dist/core/sheet.d.ts +0 -116
  274. package/dist/core/sheet.js +0 -224
  275. package/dist/core/sheet.js.map +0 -1
  276. package/dist/core/workbook.d.ts +0 -43
  277. package/dist/core/workbook.js +0 -77
  278. package/dist/core/workbook.js.map +0 -1
  279. package/dist/grid/sheet-grid.d.ts +0 -81
  280. package/dist/grid/sheet-grid.js +0 -331
  281. package/dist/grid/sheet-grid.js.map +0 -1
  282. package/dist/grid/vtable-theme.js +0 -80
  283. package/dist/grid/vtable-theme.js.map +0 -1
  284. package/dist/tools/builtin.js.map +0 -1
  285. package/dist/tools/context.js.map +0 -1
  286. package/dist/tools/registry.js.map +0 -1
  287. package/dist/vue/index.d.ts +0 -2
  288. package/dist/vue/sheet.js +0 -211
  289. package/dist/vue/sheet.js.map +0 -1
  290. package/dist/vue/sheet.vue.d.ts +0 -24
  291. package/dist/vue/style.d.ts +0 -1
  292. package/dist/vue/style.js +0 -2
  293. package/dist/vue/style2.css +0 -93
  294. package/src/core/__test__/address.test.ts +0 -113
  295. package/src/core/__test__/cell-store.test.ts +0 -97
  296. package/src/core/__test__/command.test.ts +0 -377
  297. package/src/core/__test__/fill.test.ts +0 -140
  298. package/src/core/__test__/formula-adversarial.test.ts +0 -265
  299. package/src/core/__test__/formula-engine.test.ts +0 -470
  300. package/src/core/__test__/formula-functions.test.ts +0 -178
  301. package/src/core/__test__/formula-parser.test.ts +0 -160
  302. package/src/core/__test__/history.test.ts +0 -225
  303. package/src/core/__test__/merge-manager.test.ts +0 -106
  304. package/src/core/__test__/sheet.test.ts +0 -142
  305. package/src/core/address.ts +0 -166
  306. package/src/core/cell-store.ts +0 -173
  307. package/src/core/command/default-registry.ts +0 -15
  308. package/src/core/command/history.ts +0 -167
  309. package/src/core/command/index.ts +0 -7
  310. package/src/core/command/merge-cells.ts +0 -74
  311. package/src/core/command/registry.ts +0 -30
  312. package/src/core/command/set-cell-formula.ts +0 -29
  313. package/src/core/command/set-cell-value.ts +0 -38
  314. package/src/core/command/types.ts +0 -73
  315. package/src/core/events.ts +0 -37
  316. package/src/core/fill.ts +0 -314
  317. package/src/core/formula/ast.ts +0 -66
  318. package/src/core/formula/dependency-graph.ts +0 -329
  319. package/src/core/formula/errors.ts +0 -41
  320. package/src/core/formula/evaluator.ts +0 -219
  321. package/src/core/formula/functions.ts +0 -266
  322. package/src/core/formula/index.ts +0 -7
  323. package/src/core/formula/parser.ts +0 -198
  324. package/src/core/formula/tokenizer.ts +0 -160
  325. package/src/core/merge-manager.ts +0 -158
  326. package/src/core/selection.ts +0 -66
  327. package/src/core/sheet.ts +0 -282
  328. package/src/core/workbook.ts +0 -99
  329. package/src/grid/__test__/canvas-mock.ts +0 -49
  330. package/src/grid/__test__/setup.ts +0 -3
  331. package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
  332. package/src/grid/__test__/sheet-grid.test.ts +0 -275
  333. package/src/grid/sheet-grid.ts +0 -407
  334. package/src/grid/vtable-theme.ts +0 -61
  335. package/src/vue/__test__/sheet-component.test.ts +0 -267
  336. package/src/vue/sheet.vue +0 -235
  337. package/src/vue/style.scss +0 -94
  338. package/src/vue/style.ts +0 -2
  339. /package/src/{vue → components/sheet}/index.ts +0 -0
@@ -0,0 +1,66 @@
1
+ import { DatasetField, ParamValues } from "./types.js";
2
+ //#region src/report/connector.d.ts
3
+ /** 数据连接类型(ADR-0003 决策 3:收敛为 MySQL / PostgreSQL) */
4
+ type ConnectionType = 'mysql' | 'postgresql';
5
+ /** 各连接类型的默认端口 */
6
+ declare const DEFAULT_CONNECTION_PORTS: Record<ConnectionType, number>;
7
+ /**
8
+ * 切换连接类型时解析端口:若当前端口仍是上一类型的默认值(或 0),则切到新类型默认端口;
9
+ * 用户已自定义的端口保持不变。
10
+ */
11
+ declare function resolvePortOnTypeChange(prevType: ConnectionType, nextType: ConnectionType, currentPort: number): number;
12
+ /**
13
+ * 数据连接(纯序列化对象,仅驻留内存)。
14
+ * 凭据持久化与安全存储由下游负责(ADR-0003 决策 4)。
15
+ */
16
+ interface DataConnection {
17
+ id: string;
18
+ label: string;
19
+ type: ConnectionType;
20
+ host: string;
21
+ port: number;
22
+ database: string;
23
+ username: string;
24
+ password: string;
25
+ }
26
+ /** 业务错误(`200 + { ok: false, error }`)或客户端传输层错误 */
27
+ interface ConnectorError {
28
+ code: string;
29
+ message: string;
30
+ }
31
+ /** 统一结果:成功携带 data;失败携带 error(连接器不抛异常,调用方只处理一条错误路径) */
32
+ type Result<T> = {
33
+ ok: true;
34
+ data: T;
35
+ } | {
36
+ ok: false;
37
+ error: ConnectorError;
38
+ };
39
+ /** query 成功结果:字段 schema + 行记录(契约 `{ fields, rows }` 归一化后) */
40
+ interface QueryResult {
41
+ fields: DatasetField[];
42
+ rows: Record<string, unknown>[];
43
+ }
44
+ /**
45
+ * 数据连接器(词汇表:Data Connector):test / describe / query 三方法镜像 HTTP 契约三端点。
46
+ * 真实数据库访问由下游后端以任意语言实现(BYO)。
47
+ */
48
+ interface DataConnector {
49
+ test(connection: DataConnection): Promise<Result<void>>;
50
+ describe(connection: DataConnection, sql: string): Promise<Result<DatasetField[]>>;
51
+ query(connection: DataConnection, sql: string, values: ParamValues): Promise<Result<QueryResult>>;
52
+ }
53
+ interface CreateHttpConnectorOptions {
54
+ /** 契约端点前缀,如 `https://api.example.com/report`;三端点 = `{endpoint}/test|describe|query`(无版本段) */
55
+ endpoint: string;
56
+ }
57
+ /**
58
+ * 创建 HTTP 数据连接器:三方法对应 `POST {endpoint}/test|describe|query`。
59
+ * - 请求体 JSON 序列化,`Content-Type: application/json`;
60
+ * - 网络异常与非 2xx(传输层错误)折叠为 `{ ok: false, error }`,不抛异常;
61
+ * - 业务错误(连接失败 / SQL 报错)由服务端以 `200 + { ok: false, error: { code, message } }` 返回并原样透传;
62
+ * - `describe` / `query` 的 fields 归一化为内核 `DatasetField`(label 回退 name,type 缺省 string)。
63
+ */
64
+ declare function createHttpConnector({ endpoint }: CreateHttpConnectorOptions): DataConnector;
65
+ //#endregion
66
+ export { ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, QueryResult, Result, createHttpConnector, resolvePortOnTypeChange };
@@ -0,0 +1,159 @@
1
+ //#region src/report/connector.ts
2
+ /** 各连接类型的默认端口 */
3
+ const DEFAULT_CONNECTION_PORTS = {
4
+ mysql: 3306,
5
+ postgresql: 5432
6
+ };
7
+ /**
8
+ * 切换连接类型时解析端口:若当前端口仍是上一类型的默认值(或 0),则切到新类型默认端口;
9
+ * 用户已自定义的端口保持不变。
10
+ */
11
+ function resolvePortOnTypeChange(prevType, nextType, currentPort) {
12
+ if (prevType === nextType) return currentPort;
13
+ if (currentPort === DEFAULT_CONNECTION_PORTS[prevType] || currentPort === 0) return DEFAULT_CONNECTION_PORTS[nextType];
14
+ return currentPort;
15
+ }
16
+ /** 客户端错误:网络不可达 / 非 2xx / 响应不可解析(业务错误由服务端 200 透传) */
17
+ function badResponse(message) {
18
+ return {
19
+ ok: false,
20
+ error: {
21
+ code: "BAD_RESPONSE",
22
+ message
23
+ }
24
+ };
25
+ }
26
+ function isRecord(value) {
27
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28
+ }
29
+ function toConnectorError(value) {
30
+ if (isRecord(value)) {
31
+ const { code, message } = value;
32
+ if (typeof code === "string" && typeof message === "string") return {
33
+ code,
34
+ message
35
+ };
36
+ }
37
+ return {
38
+ code: "SERVER_ERROR",
39
+ message: "服务端返回未知错误"
40
+ };
41
+ }
42
+ /** 契约字段 → 内核 DatasetField(label 缺省回退 name,type 缺省 string) */
43
+ function normalizeField(field) {
44
+ return {
45
+ name: field.name,
46
+ label: field.name,
47
+ type: field.type ?? "string"
48
+ };
49
+ }
50
+ /** 校验并归一化契约 fields;形状不合法返回 null */
51
+ function normalizeFields(fields) {
52
+ if (!Array.isArray(fields)) return null;
53
+ const normalized = [];
54
+ for (const field of fields) {
55
+ if (!isRecord(field) || typeof field.name !== "string") return null;
56
+ normalized.push(normalizeField(field));
57
+ }
58
+ return normalized;
59
+ }
60
+ /**
61
+ * 创建 HTTP 数据连接器:三方法对应 `POST {endpoint}/test|describe|query`。
62
+ * - 请求体 JSON 序列化,`Content-Type: application/json`;
63
+ * - 网络异常与非 2xx(传输层错误)折叠为 `{ ok: false, error }`,不抛异常;
64
+ * - 业务错误(连接失败 / SQL 报错)由服务端以 `200 + { ok: false, error: { code, message } }` 返回并原样透传;
65
+ * - `describe` / `query` 的 fields 归一化为内核 `DatasetField`(label 回退 name,type 缺省 string)。
66
+ */
67
+ function createHttpConnector({ endpoint }) {
68
+ async function postJson(path, body) {
69
+ let response;
70
+ try {
71
+ response = await fetch(`${endpoint}${path}`, {
72
+ method: "POST",
73
+ headers: { "Content-Type": "application/json" },
74
+ body: JSON.stringify(body)
75
+ });
76
+ } catch (error) {
77
+ return {
78
+ ok: false,
79
+ error: {
80
+ code: "NETWORK_ERROR",
81
+ message: error instanceof Error ? error.message : String(error)
82
+ }
83
+ };
84
+ }
85
+ if (!response.ok) return {
86
+ ok: false,
87
+ error: {
88
+ code: `HTTP_${response.status}`,
89
+ message: `请求失败(HTTP ${response.status})`
90
+ }
91
+ };
92
+ let payload;
93
+ try {
94
+ payload = await response.json();
95
+ } catch {
96
+ return badResponse("响应不是合法 JSON");
97
+ }
98
+ if (!isRecord(payload)) return badResponse("响应不是 JSON 对象");
99
+ return {
100
+ ok: true,
101
+ data: payload
102
+ };
103
+ }
104
+ return {
105
+ async test(connection) {
106
+ const result = await postJson("/test", { connection });
107
+ if (!result.ok) return result;
108
+ if (result.data.ok === true) return {
109
+ ok: true,
110
+ data: void 0
111
+ };
112
+ return {
113
+ ok: false,
114
+ error: toConnectorError(result.data.error)
115
+ };
116
+ },
117
+ async describe(connection, sql) {
118
+ const result = await postJson("/describe", {
119
+ connection,
120
+ sql
121
+ });
122
+ if (!result.ok) return result;
123
+ if (result.data.ok !== true) return {
124
+ ok: false,
125
+ error: toConnectorError(result.data.error)
126
+ };
127
+ const fields = normalizeFields(result.data.fields);
128
+ if (!fields) return badResponse("describe 响应缺少合法的 fields 数组");
129
+ return {
130
+ ok: true,
131
+ data: fields
132
+ };
133
+ },
134
+ async query(connection, sql, values) {
135
+ const result = await postJson("/query", {
136
+ connection,
137
+ sql,
138
+ values
139
+ });
140
+ if (!result.ok) return result;
141
+ if (result.data.ok !== true) return {
142
+ ok: false,
143
+ error: toConnectorError(result.data.error)
144
+ };
145
+ const fields = normalizeFields(result.data.fields);
146
+ if (!fields) return badResponse("query 响应缺少合法的 fields 数组");
147
+ if (!Array.isArray(result.data.rows)) return badResponse("query 响应缺少 rows 数组");
148
+ return {
149
+ ok: true,
150
+ data: {
151
+ fields,
152
+ rows: result.data.rows
153
+ }
154
+ };
155
+ }
156
+ };
157
+ }
158
+ //#endregion
159
+ export { DEFAULT_CONNECTION_PORTS, createHttpConnector, resolvePortOnTypeChange };
@@ -0,0 +1,19 @@
1
+ import { Sheet } from "@veltra/sheet-core";
2
+ import { ColumnDef } from "hucre";
3
+ //#region src/report/export-xlsx.d.ts
4
+ /** 列宽条目:模型列索引 → 像素宽(sheet-core 列宽未进 SheetSnapshot,导出时由调用方显式传入) */
5
+ type ReportColWidthEntry = readonly [number, number];
6
+ /** VTable 像素列宽 → Excel 字符宽度(近似换算) */
7
+ declare function pxToExcelColWidth(px: number): number;
8
+ /** 从列宽条目构建 hucre ColumnDef */
9
+ declare function buildColumnDefs(colWidths: ReadonlyArray<ReportColWidthEntry>): ColumnDef[];
10
+ /**
11
+ * 将已填充的 Sheet(Filled Report)导出为保真 XLSX(合并 / 样式 / 行高 / 列宽)。
12
+ * 条件样式颜色已在 renderReport 展开阶段打平进 StylePool(ADR-0001 决策 2)。
13
+ *
14
+ * 与 `exportWorkbookXlsx`(sheet-core)的差异:列宽未进 SheetSnapshot,
15
+ * 只能经 VTable 运行时读取,故这里接收显式列宽并写入 columns 定义。
16
+ */
17
+ declare function exportFilledReportXlsx(sheet: Sheet, colWidths: ReadonlyArray<ReportColWidthEntry>): Promise<Uint8Array>;
18
+ //#endregion
19
+ export { ReportColWidthEntry, buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth };
@@ -0,0 +1,95 @@
1
+ import { rangeToHucre, styleToHucre } from "@veltra/sheet-core/core/io/export";
2
+ import { writeXlsx } from "hucre/xlsx";
3
+ //#region src/report/export-xlsx.ts
4
+ /** 像素 → Excel points */
5
+ function pxToPt(px) {
6
+ return px * .75;
7
+ }
8
+ /** VTable 像素列宽 → Excel 字符宽度(近似换算) */
9
+ function pxToExcelColWidth(px) {
10
+ return Math.max(1, Math.round((px - 5) / 7));
11
+ }
12
+ /** 从列宽条目构建 hucre ColumnDef */
13
+ function buildColumnDefs(colWidths) {
14
+ if (colWidths.length === 0) return [];
15
+ const maxCol = Math.max(...colWidths.map(([col]) => col));
16
+ const columns = Array.from({ length: maxCol + 1 }, () => ({}));
17
+ for (const [col, width] of colWidths) columns[col] = { width: pxToExcelColWidth(width) };
18
+ return columns;
19
+ }
20
+ /**
21
+ * 将已填充的 Sheet(Filled Report)导出为保真 XLSX(合并 / 样式 / 行高 / 列宽)。
22
+ * 条件样式颜色已在 renderReport 展开阶段打平进 StylePool(ADR-0001 决策 2)。
23
+ *
24
+ * 与 `exportWorkbookXlsx`(sheet-core)的差异:列宽未进 SheetSnapshot,
25
+ * 只能经 VTable 运行时读取,故这里接收显式列宽并写入 columns 定义。
26
+ */
27
+ async function exportFilledReportXlsx(sheet, colWidths) {
28
+ let maxRow = -1;
29
+ let maxCol = -1;
30
+ for (const [addr] of sheet.store.entries()) {
31
+ if (addr.row > maxRow) maxRow = addr.row;
32
+ if (addr.col > maxCol) maxCol = addr.col;
33
+ }
34
+ for (const [row] of sheet.getRowHeights()) if (row > maxRow) maxRow = row;
35
+ for (const [col] of colWidths) if (col > maxCol) maxCol = col;
36
+ const rows = maxRow < 0 ? [] : Array.from({ length: maxRow + 1 }, () => Array.from({ length: maxCol + 1 }, () => null));
37
+ const cells = /* @__PURE__ */ new Map();
38
+ for (const [addr, data] of sheet.store.entries()) {
39
+ const row = rows[addr.row];
40
+ const key = `${addr.row},${addr.col}`;
41
+ const cell = {};
42
+ if (data.s != null) {
43
+ const style = sheet.stylePool.get(data.s);
44
+ if (style) cell.style = styleToHucre(style);
45
+ }
46
+ if (data.f != null && data.f !== "") {
47
+ cell.formula = data.f;
48
+ if (data.v != null) cell.formulaResult = data.v;
49
+ row[addr.col] = data.v ?? null;
50
+ cells.set(key, cell);
51
+ continue;
52
+ }
53
+ if (data.t === "e") {
54
+ cell.value = data.v;
55
+ cell.type = "error";
56
+ row[addr.col] = null;
57
+ cells.set(key, cell);
58
+ continue;
59
+ }
60
+ if (data.t === "d") {
61
+ cell.value = data.v;
62
+ cell.type = "number";
63
+ cell.style = {
64
+ ...cell.style,
65
+ numFmt: "yyyy-mm-dd"
66
+ };
67
+ row[addr.col] = null;
68
+ cells.set(key, cell);
69
+ continue;
70
+ }
71
+ row[addr.col] = data.v ?? null;
72
+ if (Object.keys(cell).length > 0) cells.set(key, cell);
73
+ }
74
+ const writeSheet = {
75
+ name: sheet.name || "报表",
76
+ rows,
77
+ ...cells.size > 0 ? { cells } : {},
78
+ ...sheet.merges.size > 0 ? { merges: sheet.merges.getMerges().map((range) => rangeToHucre(range)) } : {},
79
+ ...colWidths.length > 0 ? { columns: buildColumnDefs(colWidths) } : {}
80
+ };
81
+ const frozen = sheet.frozen;
82
+ if (frozen.rows > 0 || frozen.cols > 0) writeSheet.freezePane = {
83
+ rows: frozen.rows,
84
+ columns: frozen.cols
85
+ };
86
+ const rowDefs = /* @__PURE__ */ new Map();
87
+ for (const [row, height] of sheet.getRowHeights()) rowDefs.set(row, { height: pxToPt(height) });
88
+ if (rowDefs.size > 0) writeSheet.rowDefs = rowDefs;
89
+ return writeXlsx({
90
+ sheets: [writeSheet],
91
+ activeSheet: 0
92
+ });
93
+ }
94
+ //#endregion
95
+ export { buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth };
@@ -0,0 +1,10 @@
1
+ import { ParamValues } from "./types.js";
2
+ //#region src/report/filter-bar.d.ts
3
+ /** 将运行时 date-range 参数值规范为 [from, to] 字符串元组 */
4
+ declare function parseDateRangeValue(raw: unknown): [string, string];
5
+ /** 将运行时 number 参数值规范为 UNumberInput 可接受的 number | undefined */
6
+ declare function resolveNumberParamValue(raw: unknown): number | undefined;
7
+ /** 合并单参数变更,保持其余参数值不变 */
8
+ declare function patchParamValues(values: ParamValues, id: string, value: unknown): ParamValues;
9
+ //#endregion
10
+ export { parseDateRangeValue, patchParamValues, resolveNumberParamValue };
@@ -0,0 +1,31 @@
1
+ //#region src/report/filter-bar.ts
2
+ function toParamString(value) {
3
+ if (value == null || value === "") return "";
4
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
5
+ return "";
6
+ }
7
+ /** 将运行时 date-range 参数值规范为 [from, to] 字符串元组 */
8
+ function parseDateRangeValue(raw) {
9
+ if (Array.isArray(raw)) return [toParamString(raw[0]), toParamString(raw[1])];
10
+ if (raw && typeof raw === "object") {
11
+ const obj = raw;
12
+ return [toParamString(obj.from ?? obj.start), toParamString(obj.to ?? obj.end)];
13
+ }
14
+ return ["", ""];
15
+ }
16
+ /** 将运行时 number 参数值规范为 UNumberInput 可接受的 number | undefined */
17
+ function resolveNumberParamValue(raw) {
18
+ if (raw === "" || raw == null) return void 0;
19
+ if (typeof raw === "number" && Number.isFinite(raw)) return raw;
20
+ const parsed = Number(raw);
21
+ return Number.isFinite(parsed) ? parsed : void 0;
22
+ }
23
+ /** 合并单参数变更,保持其余参数值不变 */
24
+ function patchParamValues(values, id, value) {
25
+ return {
26
+ ...values,
27
+ [id]: value
28
+ };
29
+ }
30
+ //#endregion
31
+ export { parseDateRangeValue, patchParamValues, resolveNumberParamValue };
@@ -0,0 +1,12 @@
1
+ import { ConditionalOperator, ConditionalRule, DatasetCatalogItem, DatasetField, DatasetRecords, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, ReportAggregate, ReportBinding, ReportExpand, ReportPreset, ReportSort } from "./types.js";
2
+ import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog } from "./binding.js";
3
+ import { ConditionalEvalContext, evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./rules/evaluate.js";
4
+ import "./rules/index.js";
5
+ import { buildParamDefs, extractParamIds, resolveBoundDatasetParams } from "./params.js";
6
+ import { ReportColWidthEntry, buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth } from "./export-xlsx.js";
7
+ import { mapFilledColWidths } from "./render/builder.js";
8
+ import { renderReport, resolveFilledColWidths } from "./render/index.js";
9
+ import { ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, QueryResult, Result, createHttpConnector, resolvePortOnTypeChange } from "./connector.js";
10
+ import { IncompatibleTemplateVersionError, REPORT_TEMPLATE_VERSION, ReportDatasetDef, ReportTemplate, assertCompatibleTemplateVersion, createReportTemplate, fetchTemplateRecords, getBoundDatasetIds, getTemplateDatasets, resolveParamDefaults, resolveTemplateParams } from "./template.js";
11
+ import { parseDateRangeValue, patchParamValues, resolveNumberParamValue } from "./filter-bar.js";
12
+ export { type ConditionalEvalContext, ConditionalOperator, ConditionalRule, ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, DatasetCatalogItem, DatasetField, DatasetRecords, IncompatibleTemplateVersionError, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, QueryResult, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, ReportAggregate, ReportBinding, ReportColWidthEntry, ReportDatasetDef, ReportExpand, ReportPreset, ReportSort, ReportTemplate, Result, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatCellAddress, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, presetBindingPatch, pxToExcelColWidth, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber };
@@ -0,0 +1,13 @@
1
+ import { QueryParamDef } from "./types.js";
2
+ //#region src/report/params.d.ts
3
+ /** 从 SQL 提取 `${param}` 占位符 id(ADR-0002 决策 2:前端纯函数) */
4
+ declare function extractParamIds(sql: string): string[];
5
+ /**
6
+ * 从 SQL 构建查询参数定义:提取 `${param}` 占位符 + 上下文类型推断,
7
+ * 再叠加数据集编辑器的元数据覆盖(label / 类型 / 默认值 / 选项)。
8
+ */
9
+ declare function buildParamDefs(sql: string, overrides?: Record<string, Partial<Omit<QueryParamDef, 'id'>>>): QueryParamDef[];
10
+ /** 按绑定的数据集 id 合并查询参数(同名参数先见为准) */
11
+ declare function resolveBoundDatasetParams(queryParams: QueryParamDef[], boundDatasetIds: readonly string[], getDatasetParams: (datasetId: string) => QueryParamDef[]): QueryParamDef[];
12
+ //#endregion
13
+ export { buildParamDefs, extractParamIds, resolveBoundDatasetParams };
@@ -0,0 +1,61 @@
1
+ //#region src/report/params.ts
2
+ /** 从 SQL 提取 `${param}` 占位符 id(ADR-0002 决策 2:前端纯函数) */
3
+ function extractParamIds(sql) {
4
+ const ids = [];
5
+ const re = /\$\{([^}]+)\}/g;
6
+ let match;
7
+ while ((match = re.exec(sql)) !== null) {
8
+ const id = match[1].trim();
9
+ if (id && !ids.includes(id)) ids.push(id);
10
+ }
11
+ return ids;
12
+ }
13
+ function escapeRegExp(value) {
14
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15
+ }
16
+ /** 从 SQL 上下文推断参数控件类型(BETWEEN/LIKE/数值比较) */
17
+ function inferParamTypeFromSql(sql, paramId) {
18
+ if (new RegExp(`\\bBETWEEN\\s+\\$\\{${escapeRegExp(paramId)}\\}(?!\\s+AND)`, "i").test(sql)) return "date-range";
19
+ const pairMatch = new RegExp(`\\bBETWEEN\\s+\\$\\{${escapeRegExp(paramId)}\\}\\s+AND\\s+\\$\\{([^}]+)\\}`, "i").exec(sql);
20
+ if (pairMatch && pairMatch[1].trim() !== paramId) return "date";
21
+ if (new RegExp(`\\bLIKE\\s+\\$\\{${escapeRegExp(paramId)}\\}`, "i").test(sql)) return "text";
22
+ if (new RegExp(`[<>=]+\\s+\\$\\{${escapeRegExp(paramId)}\\}|\\$\\{${escapeRegExp(paramId)}\\}\\s*[<>=]+`, "i").test(sql)) return "number";
23
+ return "text";
24
+ }
25
+ function defaultValueForType(type) {
26
+ switch (type) {
27
+ case "number": return 0;
28
+ case "date-range": return ["", ""];
29
+ case "select": return "";
30
+ default: return "";
31
+ }
32
+ }
33
+ /**
34
+ * 从 SQL 构建查询参数定义:提取 `${param}` 占位符 + 上下文类型推断,
35
+ * 再叠加数据集编辑器的元数据覆盖(label / 类型 / 默认值 / 选项)。
36
+ */
37
+ function buildParamDefs(sql, overrides) {
38
+ return extractParamIds(sql).map((id) => {
39
+ const inferred = inferParamTypeFromSql(sql, id);
40
+ const override = overrides?.[id];
41
+ return {
42
+ id,
43
+ label: override?.label ?? id,
44
+ type: override?.type ?? inferred,
45
+ defaultValue: override?.defaultValue ?? defaultValueForType(override?.type ?? inferred),
46
+ options: override?.options
47
+ };
48
+ });
49
+ }
50
+ /** 按绑定的数据集 id 合并查询参数(同名参数先见为准) */
51
+ function resolveBoundDatasetParams(queryParams, boundDatasetIds, getDatasetParams) {
52
+ const map = /* @__PURE__ */ new Map();
53
+ for (const datasetId of boundDatasetIds) {
54
+ const params = getDatasetParams(datasetId);
55
+ for (const param of params) if (!map.has(param.id)) map.set(param.id, param);
56
+ }
57
+ if (map.size > 0) return Array.from(map.values());
58
+ return queryParams;
59
+ }
60
+ //#endregion
61
+ export { buildParamDefs, extractParamIds, resolveBoundDatasetParams };
@@ -0,0 +1,157 @@
1
+ import { enumerateExpansionInstances } from "./coordinate.js";
2
+ //#region src/report/render/aggregate.ts
3
+ function filterRows(rows, filter) {
4
+ if (Object.keys(filter).length === 0) return rows;
5
+ return rows.filter((row) => Object.entries(filter).every(([field, value]) => row[field] === value));
6
+ }
7
+ /** 对数值集求聚合;`avg` 空集返回 `undefined`,`sum` 空集仍为 `0` */
8
+ function aggregateField(rows, field, aggregate) {
9
+ if (aggregate === "count") return rows.length;
10
+ if (aggregate === "list" || aggregate === "group") return rows[0]?.[field];
11
+ const numbers = rows.map((row) => row[field]).map((value) => typeof value === "number" ? value : Number(value)).filter((value) => Number.isFinite(value));
12
+ if (numbers.length === 0) {
13
+ if (aggregate === "avg") return void 0;
14
+ return 0;
15
+ }
16
+ const sum = numbers.reduce((acc, value) => acc + value, 0);
17
+ if (aggregate === "avg") return sum / numbers.length;
18
+ if (aggregate === "max") return Math.max(...numbers);
19
+ if (aggregate === "min") return Math.min(...numbers);
20
+ return sum;
21
+ }
22
+ function isRowExpanding(binding) {
23
+ return binding.expand === "down" && (binding.aggregate === "group" || binding.aggregate === "list");
24
+ }
25
+ function isColExpanding(binding) {
26
+ return binding.expand === "right" && (binding.aggregate === "group" || binding.aggregate === "list");
27
+ }
28
+ function rowExpandingAncestors(binding, index) {
29
+ const chain = [];
30
+ let current = binding.rowParent;
31
+ while (current) {
32
+ const parentBinding = index.bindingAt(current);
33
+ if (parentBinding) chain.unshift({
34
+ addr: current,
35
+ binding: parentBinding
36
+ });
37
+ current = parentBinding?.rowParent;
38
+ }
39
+ return chain.filter((item) => isRowExpanding(item.binding));
40
+ }
41
+ function colExpandingAncestors(binding, index) {
42
+ const chain = [];
43
+ let current = binding.colParent;
44
+ while (current) {
45
+ const parentBinding = index.bindingAt(current);
46
+ if (parentBinding) chain.unshift({
47
+ addr: current,
48
+ binding: parentBinding
49
+ });
50
+ current = parentBinding?.colParent;
51
+ }
52
+ return chain.filter((item) => isColExpanding(item.binding));
53
+ }
54
+ function mergeFilters(rowFilter, colFilter) {
55
+ return {
56
+ ...rowFilter,
57
+ ...colFilter
58
+ };
59
+ }
60
+ function resolveAncestorFilters(binding, placement, index, data) {
61
+ const rowFilter = {};
62
+ const colFilter = {};
63
+ let parentFilter = {};
64
+ const rowAncestors = rowExpandingAncestors(binding, index);
65
+ for (let i = 0; i < rowAncestors.length; i++) {
66
+ const ancestor = rowAncestors[i];
67
+ if (ancestor.binding.dataset !== binding.dataset) continue;
68
+ const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
69
+ const pathIndex = placement.rowPath[i];
70
+ if (pathIndex === void 0) continue;
71
+ const instance = instances[pathIndex];
72
+ if (!instance) continue;
73
+ Object.assign(rowFilter, instance.filter);
74
+ parentFilter = instance.filter;
75
+ }
76
+ parentFilter = {};
77
+ const colAncestors = colExpandingAncestors(binding, index);
78
+ for (let i = 0; i < colAncestors.length; i++) {
79
+ const ancestor = colAncestors[i];
80
+ if (ancestor.binding.dataset !== binding.dataset) continue;
81
+ const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
82
+ const pathIndex = placement.colPath[i];
83
+ if (pathIndex === void 0) continue;
84
+ const instance = instances[pathIndex];
85
+ if (!instance) continue;
86
+ Object.assign(colFilter, instance.filter);
87
+ parentFilter = instance.filter;
88
+ }
89
+ return mergeFilters(rowFilter, colFilter);
90
+ }
91
+ function resolveOwnGroupValue(binding, placement, index, data) {
92
+ const rowAncestors = rowExpandingAncestors(binding, index);
93
+ const colAncestors = colExpandingAncestors(binding, index);
94
+ let parentFilter = {};
95
+ for (let i = 0; i < rowAncestors.length; i++) {
96
+ const ancestor = rowAncestors[i];
97
+ if (ancestor.binding.dataset !== binding.dataset) continue;
98
+ const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
99
+ const pathIndex = placement.rowPath[i];
100
+ if (pathIndex === void 0) continue;
101
+ const instance = instances[pathIndex];
102
+ if (instance) parentFilter = instance.filter;
103
+ }
104
+ for (let i = 0; i < colAncestors.length; i++) {
105
+ const ancestor = colAncestors[i];
106
+ if (ancestor.binding.dataset !== binding.dataset) continue;
107
+ const instances = enumerateExpansionInstances(ancestor.binding, data, parentFilter);
108
+ const pathIndex = placement.colPath[i];
109
+ if (pathIndex === void 0) continue;
110
+ const instance = instances[pathIndex];
111
+ if (instance) parentFilter = instance.filter;
112
+ }
113
+ const instances = enumerateExpansionInstances(binding, data, parentFilter);
114
+ const pathIndex = isRowExpanding(binding) ? placement.rowPath.at(-1) : placement.colPath.at(-1);
115
+ if (pathIndex === void 0) return void 0;
116
+ return instances[pathIndex]?.value;
117
+ }
118
+ /** 按分组字段建索引,避免交叉展开重复 filterRows */
119
+ var AggregateIndex = class {
120
+ datasets = /* @__PURE__ */ new Map();
121
+ filterCache = /* @__PURE__ */ new Map();
122
+ constructor(data) {
123
+ for (const [datasetId, rows] of Object.entries(data)) this.datasets.set(datasetId, rows);
124
+ }
125
+ rowsFor(dataset, filter) {
126
+ const cacheKey = `${dataset}:${JSON.stringify(filter)}`;
127
+ const cached = this.filterCache.get(cacheKey);
128
+ if (cached) return cached;
129
+ const rows = filterRows(this.datasets.get(dataset) ?? [], filter);
130
+ this.filterCache.set(cacheKey, rows);
131
+ return rows;
132
+ }
133
+ aggregate(dataset, filter, field, aggregate) {
134
+ const rows = this.rowsFor(dataset, filter);
135
+ if (aggregate === "list") return rows[0]?.[field];
136
+ return aggregateField(rows, field, aggregate);
137
+ }
138
+ };
139
+ /** 解析单个物理落点的绑定取值 */
140
+ function resolvePlacementValue(placement, index, data, aggregateIndex) {
141
+ const binding = placement.binding;
142
+ if (!binding) return void 0;
143
+ const filter = resolveAncestorFilters(binding, placement, index, data);
144
+ const rows = aggregateIndex.rowsFor(binding.dataset, filter);
145
+ if (binding.aggregate === "group") return filter[binding.field] ?? resolveOwnGroupValue(binding, placement, index, data);
146
+ if (binding.aggregate === "list") return rows[placement.listIndex]?.[binding.field];
147
+ return aggregateField(rows, binding.field, binding.aggregate);
148
+ }
149
+ /** 解析 `list` 明细落点对应的源数据行;非 list 绑定无单条记录上下文 */
150
+ function resolvePlacementRecord(placement, index, data, aggregateIndex) {
151
+ const binding = placement.binding;
152
+ if (!binding || binding.aggregate !== "list") return void 0;
153
+ const filter = resolveAncestorFilters(binding, placement, index, data);
154
+ return aggregateIndex.rowsFor(binding.dataset, filter)[placement.listIndex];
155
+ }
156
+ //#endregion
157
+ export { AggregateIndex, aggregateField, resolvePlacementRecord, resolvePlacementValue };
@@ -0,0 +1,12 @@
1
+ import "../types.js";
2
+ import { ReportColWidthEntry } from "../export-xlsx.js";
3
+ import { TemplateIndex } from "./template-index.js";
4
+ import { ExpansionLayout } from "./coordinate.js";
5
+ import { SheetSnapshot } from "@veltra/sheet-core";
6
+ //#region src/report/render/builder.d.ts
7
+ /**
8
+ * 将模板列宽映射到填充报表物理列:横向展开列继承列方向父格所在模板列宽。
9
+ */
10
+ declare function mapFilledColWidths(templateColWidths: ReadonlyArray<ReportColWidthEntry>, layout: ExpansionLayout, _index: TemplateIndex): ReportColWidthEntry[];
11
+ //#endregion
12
+ export { mapFilledColWidths };