@veltra/sheet 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/dist/components/report/binding-badge.js +100 -0
  2. package/dist/components/report/designer/cell-coords.js +46 -0
  3. package/dist/components/report/designer/col-widths.js +29 -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 +422 -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 +253 -0
  10. package/dist/components/report/designer/rules-dialog.js +118 -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/preview-grid-size.js +32 -0
  21. package/dist/components/report/report-designer.js +393 -0
  22. package/dist/components/report/report-viewer.js +124 -0
  23. package/dist/components/report/style.d.ts +17 -0
  24. package/dist/components/report/style.js +18 -0
  25. package/dist/components/report/style2.css +874 -0
  26. package/dist/components/report/use-report-designer.js +382 -0
  27. package/dist/components/report/use-report-viewer.js +55 -0
  28. package/dist/{vue → components/sheet}/formula-bar.js +1 -1
  29. package/dist/{vue → components/sheet}/formula-suggest-list.js +1 -1
  30. package/dist/{vue → components/sheet}/import-file.js +1 -1
  31. package/dist/{vue → components/sheet}/insert-count-menu-item.js +1 -1
  32. package/dist/{vue → components/sheet}/insert-image.js +1 -1
  33. package/dist/{vue → components/sheet}/popup-helpers.js +1 -1
  34. package/dist/{vue → components/sheet}/popups/border-popup.js +31 -3
  35. package/dist/{vue → components/sheet}/popups/border-preset-glyph.js +1 -1
  36. package/dist/{vue → components/sheet}/popups/export-popup.js +2 -2
  37. package/dist/{vue → components/sheet}/popups/fill-color-popup.js +3 -3
  38. package/dist/{vue → components/sheet}/popups/find-popup.js +1 -1
  39. package/dist/{vue → components/sheet}/popups/font-color-popup.js +3 -3
  40. package/dist/{vue → components/sheet}/popups/font-size-popup.js +3 -3
  41. package/dist/{vue → components/sheet}/popups/import.worker.d.ts +1 -1
  42. package/dist/{vue → components/sheet}/popups/import.worker.js +1 -1
  43. package/dist/{vue → components/sheet}/popups/insert-image-popup.js +1 -1
  44. package/dist/{vue → components/sheet}/sheet-context-menu.js +7 -4
  45. package/dist/{vue → components/sheet}/sheet-tabs.js +1 -1
  46. package/dist/{vue → components/sheet}/sheet-toolbar.js +1 -1
  47. package/dist/{vue → components/sheet}/sheet.js +16 -1
  48. package/dist/{vue → components/sheet}/use-find-replace.js +1 -1
  49. package/dist/{vue → components/sheet}/use-formula-ref-select.js +1 -1
  50. package/dist/{vue → components/sheet}/use-sheet-grid.js +22 -4
  51. package/dist/{vue → components/sheet}/use-sheet-state.js +6 -5
  52. package/dist/{vue → components/sheet}/use-sheet-tabs-bar.js +1 -1
  53. package/dist/{vue → components/sheet}/use-tool-groups.js +2 -2
  54. package/dist/{vue → components/sheet}/use-tool-popup.js +2 -2
  55. package/dist/{vue → components/sheet}/use-toolbar-scroll.js +1 -1
  56. package/dist/index.d.ts +17 -3
  57. package/dist/index.js +13 -3
  58. package/dist/report/binding.d.ts +83 -0
  59. package/dist/report/binding.js +332 -0
  60. package/dist/report/connector.d.ts +66 -0
  61. package/dist/report/connector.js +159 -0
  62. package/dist/report/export-xlsx.d.ts +17 -0
  63. package/dist/report/export-xlsx.js +92 -0
  64. package/dist/report/filter-bar.d.ts +10 -0
  65. package/dist/report/filter-bar.js +31 -0
  66. package/dist/report/index.d.ts +12 -0
  67. package/dist/report/params.d.ts +13 -0
  68. package/dist/report/params.js +61 -0
  69. package/dist/report/render/aggregate.js +169 -0
  70. package/dist/report/render/builder.d.ts +12 -0
  71. package/dist/report/render/builder.js +139 -0
  72. package/dist/report/render/coordinate.d.ts +25 -0
  73. package/dist/report/render/coordinate.js +733 -0
  74. package/dist/report/render/index.d.ts +14 -0
  75. package/dist/report/render/index.js +21 -0
  76. package/dist/report/render/style-resolver.js +50 -0
  77. package/dist/report/render/template-index.d.ts +24 -0
  78. package/dist/report/render/template-index.js +137 -0
  79. package/dist/report/rules/evaluate.d.ts +25 -0
  80. package/dist/report/rules/evaluate.js +82 -0
  81. package/dist/report/rules/index.d.ts +2 -0
  82. package/dist/report/template.d.ts +63 -0
  83. package/dist/report/template.js +83 -0
  84. package/dist/report/types.d.ts +85 -0
  85. package/dist/tools/apply-style.js +29 -0
  86. package/dist/tools/builtin.js +17 -17
  87. package/dist/tools/context.d.ts +39 -6
  88. package/dist/tools/context.js +38 -1
  89. package/dist/types/index.d.ts +3 -2
  90. package/dist/types/report-designer.d.ts +38 -0
  91. package/dist/types/report-viewer.d.ts +38 -0
  92. package/dist/types/sheet.d.ts +21 -1
  93. package/package.json +6 -8
  94. package/src/components/report/__test__/conditional-rules-helpers.test.ts +88 -0
  95. package/src/components/report/__test__/field-panel-helpers.test.ts +65 -0
  96. package/src/components/report/__test__/float-panel-position.test.ts +45 -0
  97. package/src/components/report/__test__/preview-grid-size.test.ts +63 -0
  98. package/src/components/report/__test__/report-designer.test.ts +464 -0
  99. package/src/components/report/__test__/report-viewer.test.ts +357 -0
  100. package/src/components/report/__test__/topology.test.ts +143 -0
  101. package/src/components/report/__test__/use-report-designer.test.ts +697 -0
  102. package/src/components/report/binding-badge.ts +92 -0
  103. package/src/components/report/designer/cell-coords.ts +94 -0
  104. package/src/components/report/designer/col-widths.ts +56 -0
  105. package/src/components/report/designer/conditional-rules/helpers.ts +189 -0
  106. package/src/components/report/designer/drop-highlight-overlay.vue +74 -0
  107. package/src/components/report/designer/float-panel.vue +431 -0
  108. package/src/components/report/designer/role.ts +32 -0
  109. package/src/components/report/designer/rule-preview.vue +40 -0
  110. package/src/components/report/designer/rule-row.vue +252 -0
  111. package/src/components/report/designer/rules-dialog.vue +110 -0
  112. package/src/components/report/designer/topology-overlay.vue +127 -0
  113. package/src/components/report/designer/topology.ts +124 -0
  114. package/src/components/report/designer/use-grid-overlay.ts +113 -0
  115. package/src/components/report/designer-hub.vue +198 -0
  116. package/src/components/report/field-panel-helpers.ts +44 -0
  117. package/src/components/report/field-panel.vue +136 -0
  118. package/src/components/report/filter-bar.vue +77 -0
  119. package/src/components/report/hub-connection-form.vue +124 -0
  120. package/src/components/report/hub-dataset-editor.vue +369 -0
  121. package/src/components/report/index.ts +2 -0
  122. package/src/components/report/preview-grid-size.ts +33 -0
  123. package/src/components/report/report-designer.vue +420 -0
  124. package/src/components/report/report-viewer.vue +136 -0
  125. package/src/components/report/style-designer.scss +587 -0
  126. package/src/components/report/style-hub.scss +292 -0
  127. package/src/components/report/style-viewer.scss +104 -0
  128. package/src/components/report/style.scss +3 -0
  129. package/src/components/report/style.ts +20 -0
  130. package/src/components/report/use-report-designer.ts +596 -0
  131. package/src/components/report/use-report-viewer.ts +88 -0
  132. package/src/{vue → components/sheet}/__test__/formula-bar.test.ts +37 -18
  133. package/src/{vue → components/sheet}/__test__/insert-image-popup.test.ts +1 -1
  134. package/src/{vue → components/sheet}/__test__/insert-image.test.ts +1 -1
  135. package/src/{vue → components/sheet}/__test__/sheet-component.test.ts +77 -3
  136. package/src/{vue → components/sheet}/__test__/sheet-context-menu.test.ts +4 -3
  137. package/src/{vue → components/sheet}/formula-bar.vue +1 -1
  138. package/src/{vue → components/sheet}/insert-image.ts +1 -1
  139. package/src/{vue → components/sheet}/popup-helpers.ts +1 -1
  140. package/src/{vue → components/sheet}/popups/border-popup.vue +32 -4
  141. package/src/{vue → components/sheet}/popups/export-popup.vue +2 -2
  142. package/src/{vue → components/sheet}/popups/fill-color-popup.vue +3 -3
  143. package/src/{vue → components/sheet}/popups/find-popup.vue +1 -1
  144. package/src/{vue → components/sheet}/popups/font-color-popup.vue +3 -3
  145. package/src/{vue → components/sheet}/popups/font-size-popup.vue +3 -3
  146. package/src/{vue → components/sheet}/popups/insert-image-popup.vue +1 -1
  147. package/src/{vue → components/sheet}/sheet-context-menu.ts +10 -4
  148. package/src/{vue → components/sheet}/sheet-toolbar.vue +2 -2
  149. package/src/{vue → components/sheet}/sheet.vue +6 -3
  150. package/src/{vue → components/sheet}/use-find-replace.ts +1 -1
  151. package/src/{vue → components/sheet}/use-sheet-grid.ts +23 -5
  152. package/src/{vue → components/sheet}/use-sheet-state.ts +11 -6
  153. package/src/{vue → components/sheet}/use-tool-groups.ts +2 -2
  154. package/src/{vue → components/sheet}/use-tool-popup.ts +2 -2
  155. package/src/index.ts +24 -188
  156. package/src/report/__test__/binding.test.ts +320 -0
  157. package/src/report/__test__/connector.test.ts +239 -0
  158. package/src/report/__test__/export-xlsx.test.ts +118 -0
  159. package/src/report/__test__/filter-bar.test.ts +58 -0
  160. package/src/report/__test__/params.test.ts +156 -0
  161. package/src/report/__test__/render.test.ts +830 -0
  162. package/src/report/__test__/rules.test.ts +131 -0
  163. package/src/report/__test__/template.test.ts +366 -0
  164. package/src/report/binding.ts +474 -0
  165. package/src/report/connector.ts +206 -0
  166. package/src/report/export-xlsx.ts +113 -0
  167. package/src/report/filter-bar.ts +36 -0
  168. package/src/report/index.ts +13 -0
  169. package/src/report/params.ts +96 -0
  170. package/src/report/render/__test__/aggregate.test.ts +16 -0
  171. package/src/report/render/__test__/coordinate.test.ts +405 -0
  172. package/src/report/render/aggregate.ts +261 -0
  173. package/src/report/render/builder.ts +211 -0
  174. package/src/report/render/coordinate.ts +1239 -0
  175. package/src/report/render/index.ts +30 -0
  176. package/src/report/render/style-resolver.ts +68 -0
  177. package/src/report/render/template-index.ts +200 -0
  178. package/src/report/rules/evaluate.ts +113 -0
  179. package/src/report/rules/index.ts +7 -0
  180. package/src/report/template.ts +145 -0
  181. package/src/report/types.ts +96 -0
  182. package/src/tools/__test__/apply-style.test.ts +129 -0
  183. package/src/tools/apply-style.ts +41 -0
  184. package/src/tools/builtin.ts +20 -20
  185. package/src/tools/context.ts +67 -4
  186. package/src/tools/index.ts +1 -0
  187. package/src/types/index.ts +2 -6
  188. package/src/types/report-designer.ts +38 -0
  189. package/src/types/report-viewer.ts +37 -0
  190. package/src/types/sheet.ts +26 -1
  191. /package/dist/{vue → components/sheet}/style.d.ts +0 -0
  192. /package/dist/{vue → components/sheet}/style.js +0 -0
  193. /package/dist/{vue → components/sheet}/style2.css +0 -0
  194. /package/dist/{vue → components/sheet}/use-formula-suggest.js +0 -0
  195. /package/src/{vue → components/sheet}/__test__/import-file.test.ts +0 -0
  196. /package/src/{vue → components/sheet}/__test__/insert-count-menu-item.test.ts +0 -0
  197. /package/src/{vue → components/sheet}/__test__/use-formula-ref-select.test.ts +0 -0
  198. /package/src/{vue → components/sheet}/__test__/use-formula-suggest.test.ts +0 -0
  199. /package/src/{vue → components/sheet}/formula-suggest-list.vue +0 -0
  200. /package/src/{vue → components/sheet}/import-file.ts +0 -0
  201. /package/src/{vue → components/sheet}/index.ts +0 -0
  202. /package/src/{vue → components/sheet}/insert-count-menu-item.vue +0 -0
  203. /package/src/{vue → components/sheet}/parsing.ts +0 -0
  204. /package/src/{vue → components/sheet}/popups/border-preset-glyph.vue +0 -0
  205. /package/src/{vue → components/sheet}/popups/import.worker.ts +0 -0
  206. /package/src/{vue → components/sheet}/sheet-tabs.vue +0 -0
  207. /package/src/{vue → components/sheet}/style.scss +0 -0
  208. /package/src/{vue → components/sheet}/style.ts +0 -0
  209. /package/src/{vue → components/sheet}/use-formula-ref-select.ts +0 -0
  210. /package/src/{vue → components/sheet}/use-formula-suggest.ts +0 -0
  211. /package/src/{vue → components/sheet}/use-sheet-tabs-bar.ts +0 -0
  212. /package/src/{vue → components/sheet}/use-toolbar-scroll.ts +0 -0
@@ -0,0 +1,431 @@
1
+ <template>
2
+ <div
3
+ v-if="binding && cell"
4
+ v-show="visible"
5
+ ref="panelRef"
6
+ :class="[cls.b, cls.m(placement), expanded ? cls.m('expanded') : '']"
7
+ :style="panelStyle"
8
+ @mousedown.stop
9
+ @pointerdown.stop
10
+ >
11
+ <div :class="cls.e('bar')">
12
+ <div :class="cls.e('summary')" :title="summaryText">
13
+ {{ summaryText }}
14
+ </div>
15
+ <div :class="cls.e('toolbar')">
16
+ <u-select
17
+ size="small"
18
+ :class="[cls.e('select'), cls.em('select', 'role')]"
19
+ :model-value="currentPresetValue"
20
+ :options="presetOptions"
21
+ @update:model-value="onPreset"
22
+ />
23
+ <u-select
24
+ v-if="showAggregateSelect"
25
+ size="small"
26
+ :class="[cls.e('select'), cls.em('select', 'aggregate')]"
27
+ :model-value="binding.aggregate"
28
+ :options="aggregateOptions"
29
+ @update:model-value="onAggregate"
30
+ />
31
+ <u-select
32
+ v-if="showExpandSelect"
33
+ size="small"
34
+ :class="[cls.e('select'), cls.em('select', 'expand')]"
35
+ :model-value="binding.expand"
36
+ :options="expandOptions"
37
+ @update:model-value="onExpand"
38
+ />
39
+ <u-button size="small" plain @click="emit('open-rules')">条件样式</u-button>
40
+ <u-button size="small" text type="danger" @click="emit('remove')">删除绑定</u-button>
41
+ <u-button
42
+ size="small"
43
+ text
44
+ :class="cls.e('expand')"
45
+ :title="expanded ? '收起' : '展开更多'"
46
+ @click="expanded = !expanded"
47
+ >
48
+ {{ expanded ? '收起' : '展开' }}
49
+ </u-button>
50
+ </div>
51
+ </div>
52
+
53
+ <div v-if="expanded" :class="cls.e('body')">
54
+ <section :class="cls.e('section')">
55
+ <div :class="cls.e('section-label')">数据集</div>
56
+ <p :class="cls.e('hint')">{{ binding.dataset }}</p>
57
+ </section>
58
+
59
+ <section :class="cls.e('section')">
60
+ <div :class="cls.e('section-label')">排序</div>
61
+ <u-radio-group
62
+ size="small"
63
+ :items="sortOptions"
64
+ :model-value="binding.sort ?? 'none'"
65
+ @update:model-value="onSort"
66
+ />
67
+ </section>
68
+
69
+ <section :class="cls.e('section')">
70
+ <div :class="cls.e('section-label')">扩展实例合并单元格</div>
71
+ <u-switch
72
+ size="small"
73
+ :model-value="binding.mergeSpan !== false"
74
+ @update:model-value="onMergeSpan"
75
+ />
76
+ </section>
77
+
78
+ <section :class="cls.e('section')">
79
+ <div :class="cls.e('section-label')">行方向父格</div>
80
+ <p :class="cls.e('hint')">当前:{{ resolvedRowParentLabel }}</p>
81
+ <div :class="cls.e('parent-actions')">
82
+ <u-button
83
+ size="small"
84
+ plain
85
+ :type="parentPickMode === 'row' ? 'primary' : undefined"
86
+ @click="emit('start-parent-pick', 'row')"
87
+ >
88
+ {{ parentPickMode === 'row' ? '点选目标格…' : '设置行方向父格' }}
89
+ </u-button>
90
+ <u-select
91
+ v-if="rowParentOptions.length > 0"
92
+ size="small"
93
+ :class="cls.e('parent-select')"
94
+ placeholder="候选格"
95
+ :model-value="rowParentSelectValue"
96
+ :options="rowParentOptions"
97
+ @update:model-value="onRowParentSelect"
98
+ />
99
+ <u-button
100
+ v-if="binding.rowParent"
101
+ size="small"
102
+ text
103
+ type="danger"
104
+ @click="emit('clear-parent', 'row')"
105
+ >
106
+ 清除
107
+ </u-button>
108
+ </div>
109
+ </section>
110
+
111
+ <section :class="cls.e('section')">
112
+ <div :class="cls.e('section-label')">列方向父格</div>
113
+ <p :class="cls.e('hint')">当前:{{ resolvedColParentLabel }}</p>
114
+ <div :class="cls.e('parent-actions')">
115
+ <u-button
116
+ size="small"
117
+ plain
118
+ :type="parentPickMode === 'col' ? 'primary' : undefined"
119
+ @click="emit('start-parent-pick', 'col')"
120
+ >
121
+ {{ parentPickMode === 'col' ? '点选目标格…' : '设置列方向父格' }}
122
+ </u-button>
123
+ <u-select
124
+ v-if="colParentOptions.length > 0"
125
+ size="small"
126
+ :class="cls.e('parent-select')"
127
+ placeholder="候选格"
128
+ :model-value="colParentSelectValue"
129
+ :options="colParentOptions"
130
+ @update:model-value="onColParentSelect"
131
+ />
132
+ <u-button
133
+ v-if="binding.colParent"
134
+ size="small"
135
+ text
136
+ type="danger"
137
+ @click="emit('clear-parent', 'col')"
138
+ >
139
+ 清除
140
+ </u-button>
141
+ </div>
142
+ </section>
143
+
144
+ <footer v-if="parentPickMode" :class="cls.e('footer')">
145
+ <u-button size="small" plain @click="emit('cancel-parent-pick')">取消点选</u-button>
146
+ </footer>
147
+ </div>
148
+ </div>
149
+ </template>
150
+
151
+ <script lang="ts" setup>
152
+ import { UButton, URadioGroup, USelect, USwitch } from '@veltra/desktop'
153
+ import type { CellAddress, SheetGrid } from '@veltra/sheet-core'
154
+ import { bem } from '@veltra/utils'
155
+ import { computed, nextTick, ref, toRef, watch } from 'vue'
156
+
157
+ import {
158
+ formatBindingPlaceholder,
159
+ formatCellAddress,
160
+ formatParentCandidateLabel,
161
+ inferReportPreset,
162
+ isReductionAggregate
163
+ } from '../../../report/binding'
164
+ import type {
165
+ ReportAggregate,
166
+ ReportBinding,
167
+ ReportExpand,
168
+ ReportPreset,
169
+ ReportSort
170
+ } from '../../../report/types'
171
+ import type { ParentPickMode } from '../use-report-designer'
172
+ import { resolveGridOverlayLayout } from './cell-coords'
173
+ import { REPORT_PRESET_OPTIONS, presetBindingDefaults } from './role'
174
+ import {
175
+ readCellOverlayRect,
176
+ resolveBindingFloatPanelPosition,
177
+ useGridOverlaySync
178
+ } from './use-grid-overlay'
179
+
180
+ defineOptions({ name: 'UReportFloatPanel' })
181
+
182
+ const CUSTOM_PRESET_VALUE = '__custom__'
183
+
184
+ const props = defineProps<{
185
+ cell: CellAddress | null
186
+ binding: ReportBinding | null
187
+ resolvedRowParentLabel: string
188
+ resolvedColParentLabel: string
189
+ parentPickMode: ParentPickMode | null
190
+ rowParentCandidates: CellAddress[]
191
+ colParentCandidates: CellAddress[]
192
+ resolveFieldLabel?: (datasetId: string, fieldName: string) => string
193
+ getBindingAt?: (addr: CellAddress) => ReportBinding | undefined
194
+ hostEl: HTMLElement | null
195
+ getGrid: () => SheetGrid | undefined
196
+ }>()
197
+
198
+ const emit = defineEmits<{
199
+ patch: [patch: Partial<ReportBinding>]
200
+ remove: []
201
+ 'open-rules': []
202
+ 'start-parent-pick': [mode: ParentPickMode]
203
+ 'cancel-parent-pick': []
204
+ 'clear-parent': [mode: ParentPickMode]
205
+ }>()
206
+
207
+ const cls = bem('report-float-panel')
208
+
209
+ const hostEl = toRef(props, 'hostEl')
210
+ const panelRef = ref<HTMLElement | null>(null)
211
+ const expanded = ref(false)
212
+ const placement = ref<'above' | 'below'>('above')
213
+
214
+ const presetOptions = computed(() => {
215
+ const options = REPORT_PRESET_OPTIONS.map((item) => ({ ...item }))
216
+ if (props.binding && inferReportPreset(props.binding) === null) {
217
+ options.unshift({ value: CUSTOM_PRESET_VALUE as ReportPreset, label: '自定义' })
218
+ }
219
+ return options
220
+ })
221
+
222
+ const ALL_AGGREGATE_OPTIONS = [
223
+ { value: 'list' as const, label: '明细' },
224
+ { value: 'group' as const, label: '分组' },
225
+ { value: 'sum' as const, label: '求和' },
226
+ { value: 'avg' as const, label: '平均' },
227
+ { value: 'count' as const, label: '计数' },
228
+ { value: 'max' as const, label: '最大' },
229
+ { value: 'min' as const, label: '最小' }
230
+ ]
231
+
232
+ const REDUCTION_AGGREGATE_OPTIONS = ALL_AGGREGATE_OPTIONS.filter((item) =>
233
+ isReductionAggregate(item.value)
234
+ )
235
+
236
+ const expandOptions = [
237
+ { value: 'down' as const, label: '向下' },
238
+ { value: 'right' as const, label: '向右' },
239
+ { value: 'none' as const, label: '不展开' }
240
+ ]
241
+
242
+ const sortOptions = [
243
+ { value: 'none' as const, label: '无' },
244
+ { value: 'asc' as const, label: '升序' },
245
+ { value: 'desc' as const, label: '降序' }
246
+ ]
247
+
248
+ const panelLeft = ref(0)
249
+ const panelTop = ref(0)
250
+ const inView = ref(false)
251
+
252
+ const currentPresetValue = computed(() => {
253
+ if (!props.binding) return 'detail'
254
+ return inferReportPreset(props.binding) ?? CUSTOM_PRESET_VALUE
255
+ })
256
+
257
+ const showAggregateSelect = computed(() => {
258
+ const preset = currentPresetValue.value
259
+ return (
260
+ preset === CUSTOM_PRESET_VALUE ||
261
+ preset === 'subtotal' ||
262
+ preset === 'grandTotal' ||
263
+ preset === 'cross'
264
+ )
265
+ })
266
+
267
+ const showExpandSelect = computed(() => {
268
+ const preset = currentPresetValue.value
269
+ return preset === CUSTOM_PRESET_VALUE || preset === 'groupHeader' || preset === 'detail'
270
+ })
271
+
272
+ const aggregateOptions = computed(() =>
273
+ currentPresetValue.value === CUSTOM_PRESET_VALUE
274
+ ? ALL_AGGREGATE_OPTIONS
275
+ : REDUCTION_AGGREGATE_OPTIONS
276
+ )
277
+
278
+ const summaryText = computed(() => {
279
+ if (!props.binding) return ''
280
+ const parts = [formatBindingPlaceholder(props.binding, props.resolveFieldLabel)]
281
+ if (props.binding.rowParent && props.resolvedRowParentLabel !== '—') {
282
+ const parent = props.getBindingAt?.(props.binding.rowParent)
283
+ const name = parent
284
+ ? (props.resolveFieldLabel?.(parent.dataset, parent.field) ?? parent.field)
285
+ : props.resolvedRowParentLabel
286
+ parts.push(`行父格 ${name} ${props.resolvedRowParentLabel}`)
287
+ }
288
+ if (props.binding.colParent && props.resolvedColParentLabel !== '—') {
289
+ const parent = props.getBindingAt?.(props.binding.colParent)
290
+ const name = parent
291
+ ? (props.resolveFieldLabel?.(parent.dataset, parent.field) ?? parent.field)
292
+ : props.resolvedColParentLabel
293
+ parts.push(`列父格 ${name} ${props.resolvedColParentLabel}`)
294
+ }
295
+ return parts.join(' · ')
296
+ })
297
+
298
+ function candidateOption(addr: CellAddress): { value: string; label: string } {
299
+ const value = formatCellAddress(addr)
300
+ const binding = props.getBindingAt?.(addr)
301
+ return {
302
+ value,
303
+ label: binding ? formatParentCandidateLabel(addr, binding, props.resolveFieldLabel) : value
304
+ }
305
+ }
306
+
307
+ const rowParentOptions = computed(() => props.rowParentCandidates.map(candidateOption))
308
+
309
+ const colParentOptions = computed(() => props.colParentCandidates.map(candidateOption))
310
+
311
+ const rowParentSelectValue = computed(() =>
312
+ props.binding?.rowParent ? formatCellAddress(props.binding.rowParent) : undefined
313
+ )
314
+
315
+ const colParentSelectValue = computed(() =>
316
+ props.binding?.colParent ? formatCellAddress(props.binding.colParent) : undefined
317
+ )
318
+
319
+ const visible = computed(() => !!props.binding && !!props.cell && inView.value)
320
+
321
+ const panelStyle = computed(() => ({ left: `${panelLeft.value}px`, top: `${panelTop.value}px` }))
322
+
323
+ watch(
324
+ () => [props.cell?.row, props.cell?.col] as const,
325
+ () => {
326
+ if (props.parentPickMode) return
327
+ expanded.value = false
328
+ }
329
+ )
330
+
331
+ watch(
332
+ () => props.parentPickMode,
333
+ (mode) => {
334
+ if (mode) expanded.value = true
335
+ }
336
+ )
337
+
338
+ watch(expanded, () => {
339
+ nextTick(() => updatePosition())
340
+ })
341
+
342
+ watch(visible, (show) => {
343
+ if (!show) return
344
+ nextTick(() => updatePosition())
345
+ })
346
+
347
+ function onPreset(preset: ReportPreset | typeof CUSTOM_PRESET_VALUE): void {
348
+ if (preset === CUSTOM_PRESET_VALUE) return
349
+ emit('patch', presetBindingDefaults(preset))
350
+ }
351
+
352
+ function aggregateDefaultExpand(aggregate: ReportAggregate): ReportExpand {
353
+ return isReductionAggregate(aggregate) ? 'none' : 'down'
354
+ }
355
+
356
+ function onAggregate(aggregate: ReportAggregate): void {
357
+ emit('patch', { aggregate, expand: aggregateDefaultExpand(aggregate) })
358
+ }
359
+
360
+ function onExpand(expand: ReportExpand): void {
361
+ emit('patch', { expand })
362
+ }
363
+
364
+ function onSort(value: ReportSort): void {
365
+ emit('patch', { sort: value })
366
+ }
367
+
368
+ function onMergeSpan(merged: boolean): void {
369
+ emit('patch', { mergeSpan: merged })
370
+ }
371
+
372
+ function onRowParentSelect(label: string): void {
373
+ const addr = props.rowParentCandidates.find((item) => formatCellAddress(item) === label)
374
+ if (!addr) return
375
+ emit('patch', { rowParent: { ...addr } })
376
+ }
377
+
378
+ function onColParentSelect(label: string): void {
379
+ const addr = props.colParentCandidates.find((item) => formatCellAddress(item) === label)
380
+ if (!addr) return
381
+ emit('patch', { colParent: { ...addr } })
382
+ }
383
+
384
+ function updatePosition(): void {
385
+ const cell = props.cell
386
+ const host = props.hostEl
387
+ if (!cell || !host) {
388
+ inView.value = false
389
+ return
390
+ }
391
+
392
+ const layoutResolved = resolveGridOverlayLayout(host)
393
+ const rect = readCellOverlayRect(cell, host, props.getGrid)
394
+ if (!rect || !layoutResolved) {
395
+ inView.value = false
396
+ return
397
+ }
398
+
399
+ inView.value = true
400
+
401
+ const panelEl = panelRef.value
402
+ const panelWidth = panelEl?.offsetWidth ?? 340
403
+ const panelHeight = panelEl?.offsetHeight ?? (expanded.value ? 360 : 68)
404
+ const position = resolveBindingFloatPanelPosition(
405
+ rect,
406
+ layoutResolved.layout,
407
+ panelWidth,
408
+ panelHeight,
409
+ host.clientWidth
410
+ )
411
+
412
+ placement.value = position.placement
413
+ panelLeft.value = position.left
414
+ panelTop.value = position.top
415
+ }
416
+
417
+ useGridOverlaySync({
418
+ hostEl,
419
+ getGrid: () => props.getGrid(),
420
+ watchSources: () =>
421
+ [
422
+ props.cell?.row,
423
+ props.cell?.col,
424
+ props.binding,
425
+ props.hostEl,
426
+ expanded.value,
427
+ props.parentPickMode
428
+ ] as const,
429
+ update: updatePosition
430
+ })
431
+ </script>
@@ -0,0 +1,32 @@
1
+ import { presetBindingPatch } from '../../../report/binding'
2
+ import type { ReportBinding, ReportPreset } from '../../../report/types'
3
+
4
+ const PRESET_LABELS: Record<ReportPreset, string> = {
5
+ groupHeader: '分组头',
6
+ detail: '明细行',
7
+ subtotal: '小计行',
8
+ grandTotal: '总计行',
9
+ cross: '交叉格'
10
+ }
11
+
12
+ export const REPORT_PRESET_OPTIONS = (
13
+ Object.entries(PRESET_LABELS) as Array<[ReportPreset, string]>
14
+ ).map(([value, label]) => ({ value, label }))
15
+
16
+ /** @deprecated 05 将更名;暂保留别名供 float-panel 消费 */
17
+ export const REPORT_ROLE_OPTIONS = REPORT_PRESET_OPTIONS
18
+
19
+ export function presetLabel(preset: ReportPreset): string {
20
+ return PRESET_LABELS[preset]
21
+ }
22
+
23
+ /** @deprecated 05 将更名 */
24
+ export const roleLabel = presetLabel
25
+
26
+ /** 切换预设时写入 expand / aggregate / 父格组合(父格除 grandTotal 外保留既有值) */
27
+ export function presetBindingDefaults(preset: ReportPreset): Partial<ReportBinding> {
28
+ return presetBindingPatch(preset)
29
+ }
30
+
31
+ /** @deprecated 05 将更名 */
32
+ export const roleBindingDefaults = presetBindingDefaults
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <span
3
+ :class="[cls.b, rule.scope === 'row' && cls.m('row')]"
4
+ :style="previewStyle"
5
+ :title="previewTitle"
6
+ >
7
+ {{ previewLabel }}
8
+ </span>
9
+ </template>
10
+
11
+ <script lang="ts" setup>
12
+ import { bem } from '@veltra/utils'
13
+ import { computed } from 'vue'
14
+
15
+ import type { ConditionalRule } from '../../../report/types'
16
+
17
+ defineOptions({ name: 'UReportRulePreview' })
18
+
19
+ const props = defineProps<{ rule: ConditionalRule }>()
20
+
21
+ const cls = bem('report-rule-preview')
22
+
23
+ const previewStyle = computed(() => {
24
+ const { fill, font } = props.rule.style
25
+ return {
26
+ backgroundColor: fill?.color || 'transparent',
27
+ color: font?.color || 'inherit',
28
+ fontWeight: font?.bold ? '700' : '400',
29
+ fontStyle: font?.italic ? 'italic' : 'normal'
30
+ }
31
+ })
32
+
33
+ const previewLabel = computed(() => (props.rule.scope === 'row' ? '整行' : 'Aa'))
34
+
35
+ const previewTitle = computed(() =>
36
+ props.rule.scope === 'row'
37
+ ? '整行作用范围:命中后染满物理输出行(交叉表会染满整行,明细行报表更合适)'
38
+ : '本格作用范围'
39
+ )
40
+ </script>