@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,94 @@
1
+ import type { CellAddress, SheetGrid } from '@veltra/sheet-core'
2
+
3
+ export interface CellOverlayRect {
4
+ left: number
5
+ top: number
6
+ right: number
7
+ bottom: number
8
+ width: number
9
+ height: number
10
+ centerX: number
11
+ centerY: number
12
+ }
13
+
14
+ export interface GridOverlayLayout {
15
+ offsetX: number
16
+ offsetY: number
17
+ viewW: number
18
+ viewH: number
19
+ }
20
+
21
+ /** VTable 坐标 = 模型地址 + 行号列/列头偏移(通常 +1) */
22
+ export const TABLE_ADDR_OFFSET = 1
23
+
24
+ export function resolveGridOverlayLayout(
25
+ host: HTMLElement
26
+ ): { gridEl: HTMLElement; layout: GridOverlayLayout } | null {
27
+ const gridEl = host.querySelector('.u-sheet__grid-instance') as HTMLElement | null
28
+ if (!gridEl) return null
29
+
30
+ const hostBox = host.getBoundingClientRect()
31
+ const gridBox = gridEl.getBoundingClientRect()
32
+
33
+ return {
34
+ gridEl,
35
+ layout: {
36
+ offsetX: gridBox.left - hostBox.left,
37
+ offsetY: gridBox.top - hostBox.top,
38
+ viewW: gridEl.clientWidth,
39
+ viewH: gridEl.clientHeight
40
+ }
41
+ }
42
+ }
43
+
44
+ /** 将屏幕坐标换算为网格落点地址(用于字段拖拽 bind) */
45
+ export function resolveGridDropAddress(
46
+ grid: SheetGrid,
47
+ gridEl: HTMLElement,
48
+ clientX: number,
49
+ clientY: number
50
+ ): CellAddress | null {
51
+ const rect = gridEl.getBoundingClientRect()
52
+ return grid.hitTestSheetAddr(clientX - rect.left, clientY - rect.top) ?? null
53
+ }
54
+
55
+ export function getCellOverlayRect(
56
+ grid: SheetGrid,
57
+ cell: CellAddress,
58
+ layout: GridOverlayLayout
59
+ ): CellOverlayRect | null {
60
+ const table = grid.getTable()
61
+ let cellRect: { left: number; top: number; right: number; bottom: number }
62
+ try {
63
+ cellRect = table.getCellRelativeRect(
64
+ cell.col + TABLE_ADDR_OFFSET,
65
+ cell.row + TABLE_ADDR_OFFSET
66
+ ) as { left: number; top: number; right: number; bottom: number }
67
+ } catch {
68
+ return null
69
+ }
70
+
71
+ const left = layout.offsetX + cellRect.left
72
+ const top = layout.offsetY + cellRect.top
73
+ const right = layout.offsetX + cellRect.right
74
+ const bottom = layout.offsetY + cellRect.bottom
75
+
76
+ const outOfView =
77
+ cellRect.bottom < 0 ||
78
+ cellRect.right < 0 ||
79
+ cellRect.top > layout.viewH ||
80
+ cellRect.left > layout.viewW
81
+
82
+ if (outOfView) return null
83
+
84
+ return {
85
+ left,
86
+ top,
87
+ right,
88
+ bottom,
89
+ width: right - left,
90
+ height: bottom - top,
91
+ centerX: (left + right) / 2,
92
+ centerY: (top + bottom) / 2
93
+ }
94
+ }
@@ -0,0 +1,33 @@
1
+ import type { ReportColWidthEntry } from '../../../report/export-xlsx'
2
+ import { TABLE_ADDR_OFFSET } from './cell-coords'
3
+
4
+ /** 列宽读写目标:SheetGrid.getTable() 的最小接口(headless 测试可桩)。
5
+ * sheet-core 列宽未进 SheetSnapshot,只能经 VTable 运行时 set/getColWidth。 */
6
+ export type ColWidthTarget = {
7
+ getTable: () => {
8
+ setColWidth: (col: number, width: number) => void
9
+ getColWidth: (col: number) => number
10
+ }
11
+ }
12
+
13
+ /** 经 SheetGrid → VTable 写入指定列宽 */
14
+ export function applyGridColWidths(
15
+ grid: ColWidthTarget | undefined | null,
16
+ widths: ReadonlyArray<ReportColWidthEntry>
17
+ ): void {
18
+ if (!grid) return
19
+ const table = grid.getTable()
20
+ for (const [sheetCol, width] of widths) {
21
+ table.setColWidth(sheetCol + TABLE_ADDR_OFFSET, width)
22
+ }
23
+ }
24
+
25
+ /** 从当前网格读取指定模型列宽度;网格未就绪时返回 null */
26
+ export function readGridColWidths(
27
+ grid: ColWidthTarget | undefined | null,
28
+ cols: ReadonlyArray<number>
29
+ ): Array<[number, number]> | null {
30
+ if (!grid) return null
31
+ const table = grid.getTable()
32
+ return cols.map((sheetCol) => [sheetCol, table.getColWidth(sheetCol + TABLE_ADDR_OFFSET)])
33
+ }
@@ -0,0 +1,186 @@
1
+ import type { ConditionalOperator, ConditionalRule, DatasetField } from '../../../../report/types'
2
+
3
+ export interface DraftRuleItem {
4
+ id: string
5
+ rule: ConditionalRule
6
+ }
7
+
8
+ export const OPERATOR_LABELS: Record<ConditionalOperator, string> = {
9
+ gt: '大于',
10
+ gte: '大于等于',
11
+ lt: '小于',
12
+ lte: '小于等于',
13
+ eq: '等于',
14
+ between: '介于',
15
+ contains: '包含'
16
+ }
17
+
18
+ export const RULE_SCOPE_OPTIONS = [
19
+ { value: 'cell' as const, label: '本格' },
20
+ { value: 'row' as const, label: '整行' }
21
+ ]
22
+
23
+ /** 求值字段下拉:缺省项表示本格绑定字段 */
24
+ export function ruleEvalFieldOptions(
25
+ bindingField: string,
26
+ datasetFields: readonly DatasetField[]
27
+ ): Array<{ value: string | undefined; label: string }> {
28
+ return [
29
+ { value: undefined, label: '本格字段' },
30
+ ...datasetFields
31
+ .filter((field) => field.name !== bindingField)
32
+ .map((field) => ({ value: field.name, label: field.label || field.name }))
33
+ ]
34
+ }
35
+
36
+ /** 按规则所选求值字段解析字段类型(运算符映射用) */
37
+ export function resolveEvalFieldType(
38
+ rule: ConditionalRule,
39
+ bindingField: string,
40
+ datasetFields: readonly DatasetField[]
41
+ ): DatasetField['type'] {
42
+ const fieldName = rule.field ?? bindingField
43
+ return datasetFields.find((field) => field.name === fieldName)?.type ?? 'number'
44
+ }
45
+
46
+ const NUMERIC_OPERATORS: ConditionalOperator[] = ['gt', 'gte', 'lt', 'lte', 'eq', 'between']
47
+ const STRING_OPERATORS: ConditionalOperator[] = ['eq', 'contains']
48
+
49
+ let draftIdSeq = 0
50
+
51
+ function nextDraftId(): string {
52
+ draftIdSeq += 1
53
+ return `rule-${draftIdSeq}`
54
+ }
55
+
56
+ /** 按字段类型返回可用运算符 */
57
+ export function operatorsForFieldType(
58
+ fieldType: DatasetField['type']
59
+ ): Array<{ value: ConditionalOperator; label: string }> {
60
+ const ops = fieldType === 'string' ? STRING_OPERATORS : NUMERIC_OPERATORS
61
+ return ops.map((value) => ({ value, label: OPERATOR_LABELS[value] }))
62
+ }
63
+
64
+ export function isNumericFieldType(fieldType: DatasetField['type']): boolean {
65
+ return fieldType === 'number' || fieldType === 'date'
66
+ }
67
+
68
+ export function defaultRuleValue(
69
+ operator: ConditionalOperator,
70
+ fieldType: DatasetField['type']
71
+ ): unknown {
72
+ if (operator === 'between') {
73
+ return isNumericFieldType(fieldType) ? [0, 100] : ['', '']
74
+ }
75
+ if (operator === 'contains' || (operator === 'eq' && fieldType === 'string')) {
76
+ return ''
77
+ }
78
+ return 0
79
+ }
80
+
81
+ export function defaultRuleStyle(): ConditionalRule['style'] {
82
+ return { fill: { color: '#FEE2E2' }, font: { color: '#DC2626' } }
83
+ }
84
+
85
+ export function createDraftItem(
86
+ rule?: ConditionalRule,
87
+ fieldType: DatasetField['type'] = 'number',
88
+ _bindingField?: string
89
+ ): DraftRuleItem {
90
+ if (rule) {
91
+ return { id: nextDraftId(), rule: cloneRule(rule) }
92
+ }
93
+ const operator = operatorsForFieldType(fieldType)[0]?.value ?? 'eq'
94
+ return {
95
+ id: nextDraftId(),
96
+ rule: { operator, value: defaultRuleValue(operator, fieldType), style: defaultRuleStyle() }
97
+ }
98
+ }
99
+
100
+ export function initDraftFromRules(
101
+ rules: readonly ConditionalRule[],
102
+ fieldType: DatasetField['type'],
103
+ bindingField?: string
104
+ ): DraftRuleItem[] {
105
+ if (rules.length === 0) return []
106
+ return rules.map((rule) => createDraftItem(rule, fieldType, bindingField))
107
+ }
108
+
109
+ export function cloneRule(rule: ConditionalRule): ConditionalRule {
110
+ return {
111
+ operator: rule.operator,
112
+ value: cloneRuleValue(rule.value),
113
+ field: rule.field,
114
+ scope: rule.scope,
115
+ style: {
116
+ ...rule.style,
117
+ fill: rule.style.fill ? { ...rule.style.fill } : undefined,
118
+ font: rule.style.font ? { ...rule.style.font } : undefined
119
+ }
120
+ }
121
+ }
122
+
123
+ function cloneRuleValue(value: unknown): unknown {
124
+ if (Array.isArray(value)) return [...value]
125
+ return value
126
+ }
127
+
128
+ export function cloneRulesFromDraft(items: readonly DraftRuleItem[]): ConditionalRule[] {
129
+ return items.map((item) => cloneRule(item.rule))
130
+ }
131
+
132
+ /** 运算符切换时重置比较值为合理缺省 */
133
+ export function coerceValueForOperator(
134
+ operator: ConditionalOperator,
135
+ fieldType: DatasetField['type'],
136
+ current: unknown
137
+ ): unknown {
138
+ if (operator === 'between') {
139
+ if (Array.isArray(current) && current.length === 2) return [...current]
140
+ return defaultRuleValue('between', fieldType)
141
+ }
142
+ if (operator === 'contains') {
143
+ return typeof current === 'string' ? current : ''
144
+ }
145
+ if (isNumericFieldType(fieldType)) {
146
+ const n = typeof current === 'number' && Number.isFinite(current) ? current : Number(current)
147
+ return Number.isFinite(n) ? n : 0
148
+ }
149
+ return typeof current === 'string' ? current : ''
150
+ }
151
+
152
+ function toDisplayString(value: unknown): string {
153
+ if (typeof value === 'string') return value
154
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
155
+ return String(value)
156
+ }
157
+ return ''
158
+ }
159
+
160
+ export function readBetweenValue(
161
+ value: unknown,
162
+ index: 0 | 1,
163
+ fieldType: DatasetField['type']
164
+ ): number | string {
165
+ const pair =
166
+ Array.isArray(value) && value.length === 2 ? value : defaultRuleValue('between', fieldType)
167
+ const raw = (pair as [unknown, unknown])[index]
168
+ if (isNumericFieldType(fieldType)) {
169
+ const n = typeof raw === 'number' ? raw : Number(raw)
170
+ return Number.isFinite(n) ? n : 0
171
+ }
172
+ return typeof raw === 'string' ? raw : toDisplayString(raw)
173
+ }
174
+
175
+ export function writeBetweenValue(
176
+ value: unknown,
177
+ index: 0 | 1,
178
+ next: number | string,
179
+ fieldType: DatasetField['type']
180
+ ): [unknown, unknown] {
181
+ const current = readBetweenValue(value, 0, fieldType)
182
+ const currentEnd = readBetweenValue(value, 1, fieldType)
183
+ const pair: [unknown, unknown] = [current, currentEnd]
184
+ pair[index] = next
185
+ return pair
186
+ }
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <div v-if="cell && visible" :class="cls.b" :style="highlightStyle" aria-hidden="true" />
3
+ <div v-else-if="showFallback" :class="cls.e('fallback')" role="status">
4
+ 松开将绑定到当前选区 {{ fallbackLabel }}
5
+ </div>
6
+ </template>
7
+
8
+ <script lang="ts" setup>
9
+ import type { CellAddress, SheetGrid } from '@veltra/sheet-core'
10
+ import { bem } from '@veltra/utils'
11
+ import { computed, ref, toRef } from 'vue'
12
+
13
+ import { readCellOverlayRect, useGridOverlaySync } from './use-grid-overlay'
14
+
15
+ defineOptions({ name: 'UReportDropHighlightOverlay' })
16
+
17
+ const props = defineProps<{
18
+ cell: CellAddress | null
19
+ hostEl: HTMLElement | null
20
+ getGrid: () => SheetGrid | undefined
21
+ /** 字段拖拽进行中(dragover 时为 true) */
22
+ dragging: boolean
23
+ /** hit-test 落空时提示回退的选区标签(如 A1) */
24
+ fallbackLabel: string
25
+ }>()
26
+
27
+ const cls = bem('report-drop-highlight')
28
+
29
+ const hostEl = toRef(props, 'hostEl')
30
+
31
+ const rectLeft = ref(0)
32
+ const rectTop = ref(0)
33
+ const rectWidth = ref(0)
34
+ const rectHeight = ref(0)
35
+ const inView = ref(false)
36
+
37
+ const visible = computed(() => !!props.cell && inView.value)
38
+ const showFallback = computed(() => props.dragging && !props.cell)
39
+
40
+ const highlightStyle = computed(() => ({
41
+ left: `${rectLeft.value}px`,
42
+ top: `${rectTop.value}px`,
43
+ width: `${rectWidth.value}px`,
44
+ height: `${rectHeight.value}px`
45
+ }))
46
+
47
+ function updateHighlight(): void {
48
+ const cell = props.cell
49
+ const host = props.hostEl
50
+ if (!cell || !host) {
51
+ inView.value = false
52
+ return
53
+ }
54
+
55
+ const rect = readCellOverlayRect(cell, host, props.getGrid)
56
+ if (!rect) {
57
+ inView.value = false
58
+ return
59
+ }
60
+
61
+ inView.value = true
62
+ rectLeft.value = Math.round(rect.left)
63
+ rectTop.value = Math.round(rect.top)
64
+ rectWidth.value = Math.round(rect.width)
65
+ rectHeight.value = Math.round(rect.height)
66
+ }
67
+
68
+ useGridOverlaySync({
69
+ hostEl,
70
+ getGrid: () => props.getGrid(),
71
+ watchSources: () => [props.cell?.row, props.cell?.col, props.hostEl, props.dragging] as const,
72
+ update: updateHighlight
73
+ })
74
+ </script>