@veltra/sheet 2.2.0 → 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 (84) hide show
  1. package/dist/components/report/binding-badge.js +45 -21
  2. package/dist/components/report/designer/col-widths.js +18 -4
  3. package/dist/components/report/designer/conditional-rules/helpers.js +3 -3
  4. package/dist/components/report/designer/float-panel.js +73 -36
  5. package/dist/components/report/designer/rule-row.js +111 -127
  6. package/dist/components/report/designer/rules-dialog.js +5 -22
  7. package/dist/components/report/preview-grid-size.js +32 -0
  8. package/dist/components/report/report-designer.js +75 -25
  9. package/dist/components/report/report-viewer.js +38 -25
  10. package/dist/components/report/style2.css +44 -39
  11. package/dist/components/report/use-report-designer.js +34 -12
  12. package/dist/components/report/use-report-viewer.js +6 -1
  13. package/dist/components/sheet/popups/border-popup.js +30 -2
  14. package/dist/components/sheet/popups/fill-color-popup.js +2 -2
  15. package/dist/components/sheet/popups/font-color-popup.js +2 -2
  16. package/dist/components/sheet/popups/font-size-popup.js +2 -2
  17. package/dist/components/sheet/sheet-context-menu.js +6 -3
  18. package/dist/components/sheet/sheet.js +8 -0
  19. package/dist/components/sheet/use-sheet-grid.js +14 -4
  20. package/dist/components/sheet/use-sheet-state.js +3 -2
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +2 -2
  23. package/dist/report/binding.d.ts +49 -11
  24. package/dist/report/binding.js +186 -29
  25. package/dist/report/connector.js +1 -1
  26. package/dist/report/export-xlsx.d.ts +3 -5
  27. package/dist/report/export-xlsx.js +7 -10
  28. package/dist/report/index.d.ts +2 -2
  29. package/dist/report/render/aggregate.js +20 -8
  30. package/dist/report/template.d.ts +8 -4
  31. package/dist/report/template.js +5 -2
  32. package/dist/tools/apply-style.js +29 -0
  33. package/dist/tools/builtin.js +17 -17
  34. package/dist/tools/context.d.ts +38 -5
  35. package/dist/tools/context.js +38 -1
  36. package/dist/types/report-designer.d.ts +2 -0
  37. package/dist/types/report-viewer.d.ts +2 -2
  38. package/dist/types/sheet.d.ts +4 -0
  39. package/package.json +6 -6
  40. package/src/components/report/__test__/conditional-rules-helpers.test.ts +1 -0
  41. package/src/components/report/__test__/preview-grid-size.test.ts +63 -0
  42. package/src/components/report/__test__/report-designer.test.ts +76 -0
  43. package/src/components/report/__test__/report-viewer.test.ts +24 -1
  44. package/src/components/report/__test__/use-report-designer.test.ts +142 -10
  45. package/src/components/report/binding-badge.ts +39 -20
  46. package/src/components/report/designer/col-widths.ts +34 -11
  47. package/src/components/report/designer/conditional-rules/helpers.ts +6 -3
  48. package/src/components/report/designer/float-panel.vue +71 -27
  49. package/src/components/report/designer/rule-row.vue +67 -67
  50. package/src/components/report/designer/rules-dialog.vue +3 -19
  51. package/src/components/report/preview-grid-size.ts +33 -0
  52. package/src/components/report/report-designer.vue +79 -15
  53. package/src/components/report/report-viewer.vue +37 -29
  54. package/src/components/report/style-designer.scss +45 -41
  55. package/src/components/report/use-report-designer.ts +63 -14
  56. package/src/components/report/use-report-viewer.ts +11 -2
  57. package/src/components/sheet/__test__/sheet-component.test.ts +37 -0
  58. package/src/components/sheet/__test__/sheet-context-menu.test.ts +3 -2
  59. package/src/components/sheet/popups/border-popup.vue +31 -3
  60. package/src/components/sheet/popups/fill-color-popup.vue +2 -2
  61. package/src/components/sheet/popups/font-color-popup.vue +2 -2
  62. package/src/components/sheet/popups/font-size-popup.vue +2 -2
  63. package/src/components/sheet/sheet-context-menu.ts +8 -2
  64. package/src/components/sheet/sheet.vue +2 -0
  65. package/src/components/sheet/use-sheet-grid.ts +17 -3
  66. package/src/components/sheet/use-sheet-state.ts +8 -3
  67. package/src/report/__test__/binding.test.ts +103 -1
  68. package/src/report/__test__/connector.test.ts +21 -0
  69. package/src/report/__test__/export-xlsx.test.ts +4 -4
  70. package/src/report/__test__/render.test.ts +102 -0
  71. package/src/report/__test__/template.test.ts +11 -0
  72. package/src/report/binding.ts +278 -47
  73. package/src/report/connector.ts +3 -2
  74. package/src/report/export-xlsx.ts +9 -14
  75. package/src/report/render/aggregate.ts +29 -8
  76. package/src/report/template.ts +8 -4
  77. package/src/tools/__test__/apply-style.test.ts +129 -0
  78. package/src/tools/apply-style.ts +41 -0
  79. package/src/tools/builtin.ts +18 -18
  80. package/src/tools/context.ts +67 -4
  81. package/src/tools/index.ts +1 -0
  82. package/src/types/report-designer.ts +2 -0
  83. package/src/types/report-viewer.ts +2 -2
  84. package/src/types/sheet.ts +4 -0
@@ -1,16 +1,14 @@
1
1
  import _sfc_main$1 from "../sheet/sheet.js";
2
2
  import { exportFilledReportXlsx } from "../../report/export-xlsx.js";
3
- import { applyGridColWidths, readGridColWidths } from "./designer/col-widths.js";
3
+ import { applyGridColWidths, applySheetColWidths } from "./designer/col-widths.js";
4
4
  import _sfc_main$2 from "./filter-bar.js";
5
+ import { previewGridSize } from "./preview-grid-size.js";
5
6
  import { useReportViewer } from "./use-report-viewer.js";
6
7
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, toDisplayString, unref, useTemplateRef, watch } from "vue";
7
8
  import { bem } from "@veltra/utils";
8
9
  import { saveBlob } from "@cat-kit/fe";
9
10
  import { Workbook } from "@veltra/sheet-core";
10
11
  //#region src/components/report/report-viewer.vue
11
- const MIN_RENDER_ROWS = 50;
12
- const MIN_RENDER_COLS = 10;
13
- /** 取数未完成时拒绝导出的可读错误 */
14
12
  const EXPORT_NOT_READY_MESSAGE = "报表数据尚未就绪,请等待取数完成后再导出";
15
13
  const EXPORT_LOADING_MESSAGE = "报表数据加载中,请稍后再导出";
16
14
  /** 查看器工作簿:宿主可注入(同 USheet `workbook?` 先例),缺省内部自建;模板 / 填充结果都 restore 进活动 sheet 只读展示 */
@@ -26,43 +24,56 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
26
24
  setup(__props, { expose: __expose }) {
27
25
  const props = __props;
28
26
  const cls = bem("report-viewer");
29
- /** 网格最小渲染尺寸(与 playground 预览态一致);Filled Report 超出时按快照尺寸放大 */
27
+ /** 取数未完成时拒绝导出的可读错误 */
30
28
  const internalWorkbook = new Workbook();
31
29
  const workbook = computed(() => props.workbook ?? internalWorkbook);
32
30
  const sheetRef = useTemplateRef("sheetRef");
33
- const { params, values, loading, error, filledSnapshot, refresh, setValues } = useReportViewer(props);
34
- const renderRows = computed(() => Math.max(MIN_RENDER_ROWS, filledSnapshot.value?.rows ?? 0, props.template.rows));
35
- const renderCols = computed(() => Math.max(MIN_RENDER_COLS, filledSnapshot.value?.cols ?? 0, props.template.cols));
36
- function exportColIndexes() {
37
- return Array.from({ length: renderCols.value }, (_, col) => col);
38
- }
39
- /** 将宿主传入的列宽写入 VTable 运行时(sheet-core 列宽未进快照) */
31
+ const { params, values, loading, error, filledSnapshot, filledColWidths, refresh, setValues } = useReportViewer(props);
32
+ const renderSize = computed(() => {
33
+ const filled = filledSnapshot.value;
34
+ if (filled) return previewGridSize(filled, "filled");
35
+ return previewGridSize(props.template, "template");
36
+ });
37
+ /** 宿主显式传入优先;否则取数完成后用展开映射列宽;再回落模板设计态列宽 */
38
+ const effectiveColWidths = computed(() => {
39
+ if (props.colWidths?.length) return props.colWidths;
40
+ if (filledColWidths.value?.length) return filledColWidths.value;
41
+ return props.template.colWidths;
42
+ });
43
+ /** 将运行时列宽写入模型与 VTable(模型为单一事实源;grid 构造/content-reset 也会回放) */
40
44
  function applyRuntimeColWidths() {
41
- if (!props.colWidths?.length) return;
42
- applyGridColWidths(sheetRef.value?.getGrid(), props.colWidths);
45
+ if (!effectiveColWidths.value?.length) return;
46
+ const sheet = workbook.value.activeSheet;
47
+ applySheetColWidths(sheet, effectiveColWidths.value);
48
+ applyGridColWidths(sheetRef.value?.getGrid(), effectiveColWidths.value);
43
49
  }
44
50
  /**
45
- * restore 负责尺寸/冻结/行高/选区(静默),restoreContent 发 content-reset
51
+ * restore 负责尺寸/冻结/行高/列宽/选区(静默),restoreContent 发 content-reset
46
52
  * 触发网格全量刷新(grid 层订阅直刷,无需手动 flush);history.clear 使填充不进 undo
47
53
  */
48
- function applySnapshot(snapshot) {
54
+ function applySnapshot(snapshot, mode) {
55
+ const size = previewGridSize(snapshot, mode);
56
+ const trimmed = {
57
+ ...snapshot,
58
+ rows: size.rows,
59
+ cols: size.cols
60
+ };
49
61
  const sheet = workbook.value.activeSheet;
50
- sheet.restore(snapshot);
51
- sheet.restoreContent(snapshot);
62
+ sheet.restore(trimmed);
63
+ sheet.restoreContent(trimmed);
52
64
  sheet.history.clear();
53
65
  nextTick(applyRuntimeColWidths);
54
66
  }
55
- watch(() => props.template, applySnapshot, { immediate: true });
67
+ watch(() => props.template, (template) => applySnapshot(template, "template"), { immediate: true });
56
68
  watch(filledSnapshot, (filled) => {
57
- if (filled) applySnapshot(filled);
69
+ if (filled) applySnapshot(filled, "filled");
58
70
  });
59
- watch(() => props.colWidths, applyRuntimeColWidths);
71
+ watch(effectiveColWidths, applyRuntimeColWidths);
60
72
  async function exportXlsx() {
61
73
  if (loading.value) throw new Error(EXPORT_LOADING_MESSAGE);
62
74
  if (!filledSnapshot.value) throw new Error(EXPORT_NOT_READY_MESSAGE);
63
75
  const sheet = workbook.value.activeSheet;
64
- const colWidths = readGridColWidths(sheetRef.value?.getGrid(), exportColIndexes()) ?? [];
65
- const buffer = await exportFilledReportXlsx(sheet, colWidths);
76
+ const buffer = await exportFilledReportXlsx(sheet);
66
77
  saveBlob(new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), `${sheet.name || "报表"}.xlsx`);
67
78
  }
68
79
  __expose({
@@ -92,11 +103,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
92
103
  ref: sheetRef,
93
104
  class: normalizeClass(unref(cls).e("sheet")),
94
105
  workbook: workbook.value,
95
- rows: renderRows.value,
96
- cols: renderCols.value,
106
+ rows: renderSize.value.rows,
107
+ cols: renderSize.value.cols,
97
108
  "show-toolbar": false,
98
109
  "show-formula-bar": false,
99
110
  "show-tabs": false,
111
+ "show-row-header": false,
112
+ "show-col-header": false,
100
113
  readonly: ""
101
114
  }, null, 8, [
102
115
  "class",
@@ -166,6 +166,21 @@
166
166
  min-height: 0;
167
167
  min-width: 0;
168
168
  }
169
+ .u-report-designer__pick-hint {
170
+ position: absolute;
171
+ left: 50%;
172
+ bottom: var(--u-gap-small);
173
+ z-index: 17;
174
+ transform: translateX(-50%);
175
+ padding: 4px var(--u-gap-small);
176
+ border-radius: var(--u-radius-default);
177
+ background: color-mix(in srgb, var(--u-bg-color-top) 92%, transparent);
178
+ border: 1px dashed var(--u-color-primary);
179
+ font-size: var(--u-font-size-main-small);
180
+ color: var(--u-text-color-second);
181
+ pointer-events: none;
182
+ white-space: nowrap;
183
+ }
169
184
  .u-report-designer {
170
185
  /* 数据中枢 drawer 面板宽度(class 经 $attrs 落到 .u-drawer 面板;须压过 .u-drawer.is-right 的 320px) */
171
186
  }
@@ -222,7 +237,7 @@
222
237
  white-space: nowrap;
223
238
  }
224
239
 
225
- /* Action Pill:选中绑定格上方的悬浮编辑卡(角色 / 聚合 / 条件样式 / 排序 / 清除绑定) */
240
+ /* Action Pill:选中绑定格上方的悬浮编辑卡(预设 + 互补的展开/聚合 / 条件样式 / 排序 / 清除绑定) */
226
241
  .u-report-float-panel {
227
242
  position: absolute;
228
243
  z-index: 18;
@@ -308,7 +323,7 @@
308
323
  flex-wrap: wrap;
309
324
  }
310
325
  .u-report-float-panel__parent-select {
311
- width: 88px;
326
+ width: 180px;
312
327
  flex: none;
313
328
  }
314
329
  .u-report-float-panel__select--expand {
@@ -326,11 +341,12 @@
326
341
  .u-report-rules-dialog {
327
342
  display: flex;
328
343
  flex-direction: column;
329
- gap: 12px;
344
+ gap: 10px;
330
345
  }
331
346
  .u-report-rules-dialog__hint {
332
347
  margin: 0;
333
348
  font-size: 12px;
349
+ line-height: 1.5;
334
350
  color: var(--u-text-color-second);
335
351
  }
336
352
  .u-report-rules-dialog__list {
@@ -356,17 +372,18 @@
356
372
  display: flex;
357
373
  align-items: flex-start;
358
374
  gap: 8px;
359
- padding: 10px;
375
+ padding: 10px 10px 10px 6px;
360
376
  border: var(--u-border-muted);
361
377
  border-radius: 8px;
362
- background: var(--u-bg-color-top);
378
+ background: var(--u-bg-color-middle);
363
379
  }
364
380
  .u-report-rule-row__handle {
365
381
  flex: none;
366
- width: 20px;
367
- margin-top: 4px;
368
- color: var(--u-text-color-second);
369
- font-size: 16px;
382
+ width: 16px;
383
+ margin-top: 6px;
384
+ color: var(--u-text-color-placeholder);
385
+ font-size: 12px;
386
+ letter-spacing: -1px;
370
387
  line-height: 1;
371
388
  cursor: grab;
372
389
  user-select: none;
@@ -382,28 +399,29 @@
382
399
  flex-direction: column;
383
400
  gap: 8px;
384
401
  }
385
- .u-report-rule-row__meta {
402
+ .u-report-rule-row__when {
386
403
  display: flex;
387
404
  align-items: center;
388
- gap: 8px;
405
+ gap: 6px;
389
406
  flex-wrap: wrap;
390
407
  }
391
- .u-report-rule-row__field-select {
392
- width: 120px;
393
- flex: none;
408
+ .u-report-rule-row__then {
409
+ display: flex;
410
+ align-items: center;
411
+ gap: 6px;
412
+ flex-wrap: wrap;
394
413
  }
395
- .u-report-rule-row__scope-select {
396
- width: 72px;
414
+ .u-report-rule-row__lead {
397
415
  flex: none;
416
+ font-size: 12px;
417
+ color: var(--u-text-color-second);
398
418
  }
399
- .u-report-rule-row__condition {
400
- display: grid;
401
- grid-template-columns: 72px minmax(0, 1fr) auto;
402
- align-items: center;
403
- gap: 8px;
419
+ .u-report-rule-row__field-select {
420
+ width: 128px;
421
+ flex: none;
404
422
  }
405
423
  .u-report-rule-row__operator {
406
- width: 72px;
424
+ width: 96px;
407
425
  flex: none;
408
426
  }
409
427
  .u-report-rule-row__value {
@@ -414,40 +432,27 @@
414
432
  min-width: 0;
415
433
  }
416
434
  .u-report-rule-row__scalar-input {
417
- width: 112px;
435
+ width: 120px;
418
436
  flex: none;
419
437
  }
420
438
  .u-report-rule-row__between-input {
421
- width: 96px;
439
+ width: 88px;
422
440
  flex: none;
423
441
  }
424
442
  .u-report-rule-row__between-sep {
425
443
  font-size: 12px;
426
444
  color: var(--u-text-color-second);
427
445
  }
428
- .u-report-rule-row__style {
429
- display: flex;
430
- align-items: center;
431
- gap: 8px;
432
- flex-wrap: wrap;
433
- }
434
- .u-report-rule-row__style-label {
435
- font-size: 12px;
436
- color: var(--u-text-color-second);
437
- }
438
446
  .u-report-rule-row__toggle {
439
447
  min-width: 28px;
440
448
  padding-inline: 6px;
441
449
  }
442
450
  .u-report-rule-row__preview {
443
451
  flex: none;
444
- margin-top: 2px;
445
452
  }
446
- .u-report-rule-row__actions {
453
+ .u-report-rule-row__remove {
447
454
  flex: none;
448
- display: flex;
449
- flex-direction: column;
450
- gap: 2px;
455
+ margin-top: 2px;
451
456
  }
452
457
 
453
458
  .u-report-rule-preview {
@@ -1,4 +1,4 @@
1
- import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatCellAddress, inferColParentCandidate, inferDropPreset, inferRowParentCandidate, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates } from "../../report/binding.js";
1
+ import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatCellAddress, inferDropPreset, inferParentsForPreset, isColGroupBinding, isHorizontalExpandBinding, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, prefersGroupParent, presetStillApplies } from "../../report/binding.js";
2
2
  import { buildParamDefs } from "../../report/params.js";
3
3
  import { assertCompatibleTemplateVersion, createReportTemplate, getTemplateDatasets, resolveParamDefaults } from "../../report/template.js";
4
4
  import { createBindingBadgeRenderer, createBindingBadgeStyleResolver } from "./binding-badge.js";
@@ -80,10 +80,9 @@ function useReportDesigner(options) {
80
80
  const preset = inferDropPreset(target, field?.type ?? "string", getBindingAt);
81
81
  let binding = createReportBinding(dataset, fieldName);
82
82
  binding = applyReportPreset(binding, preset);
83
- const rowParent = inferRowParentCandidate(target, getBindingAt);
84
- if (rowParent) binding.rowParent = rowParent;
85
- const colParent = inferColParentCandidate(target, getBindingAt);
86
- if (colParent) binding.colParent = colParent;
83
+ const parents = inferParentsForPreset(target, preset, getBindingAt);
84
+ if (parents.rowParent) binding.rowParent = parents.rowParent;
85
+ if (parents.colParent) binding.colParent = parents.colParent;
87
86
  workbook.value.activeSheet.setCellMeta(target, REPORT_META_NAMESPACE, binding);
88
87
  }
89
88
  const activeBinding = computed(() => {
@@ -118,13 +117,13 @@ function useReportDesigner(options) {
118
117
  metaTick.value;
119
118
  const binding = activeBinding.value;
120
119
  if (!binding) return [];
121
- return listRowParentCandidates(binding, bindingEntries.value);
120
+ return listRowParentCandidates(binding, bindingEntries.value, { preferGroup: prefersGroupParent(binding) });
122
121
  });
123
122
  const colParentCandidates = computed(() => {
124
123
  metaTick.value;
125
124
  const binding = activeBinding.value;
126
125
  if (!binding) return [];
127
- return listColParentCandidates(binding, bindingEntries.value);
126
+ return listColParentCandidates(binding, bindingEntries.value, { preferGroup: prefersGroupParent(binding) });
128
127
  });
129
128
  const bindingEntries = computed(() => {
130
129
  metaTick.value;
@@ -138,6 +137,11 @@ function useReportDesigner(options) {
138
137
  }
139
138
  return entries;
140
139
  });
140
+ function parentNeedsCorrection(addr) {
141
+ if (!addr) return true;
142
+ const parent = getBindingAt(addr);
143
+ return !parent || parent.aggregate === "list";
144
+ }
141
145
  function patchActiveBinding(patch) {
142
146
  const cell = activeCell.value;
143
147
  const binding = activeBinding.value;
@@ -148,7 +152,14 @@ function useReportDesigner(options) {
148
152
  };
149
153
  if ("rowParent" in patch && patch.rowParent === void 0) delete next.rowParent;
150
154
  if ("colParent" in patch && patch.colParent === void 0) delete next.colParent;
151
- if (("aggregate" in patch || "expand" in patch) && !("preset" in patch)) delete next.preset;
155
+ if (("aggregate" in patch || "expand" in patch) && !("preset" in patch) && !presetStillApplies(next)) delete next.preset;
156
+ if (patch.preset === "subtotal") {
157
+ const inferred = inferParentsForPreset(cell, "subtotal", getBindingAt);
158
+ if (parentNeedsCorrection(next.rowParent)) if (inferred.rowParent) next.rowParent = inferred.rowParent;
159
+ else delete next.rowParent;
160
+ if (parentNeedsCorrection(next.colParent)) if (inferred.colParent) next.colParent = inferred.colParent;
161
+ else delete next.colParent;
162
+ }
152
163
  workbook.value.activeSheet.setCellMeta(cell, REPORT_META_NAMESPACE, next);
153
164
  }
154
165
  function startParentPick(mode) {
@@ -165,16 +176,27 @@ function useReportDesigner(options) {
165
176
  function cancelParentPick() {
166
177
  parentPick.value = null;
167
178
  }
179
+ function isValidParentTarget(mode, source, target) {
180
+ if (!target) return false;
181
+ if (target.dataset !== source.dataset) return false;
182
+ const groupOnly = prefersGroupParent(source);
183
+ if (mode === "row") return groupOnly ? isRowGroupBinding(target) : isVerticalExpandBinding(target);
184
+ return groupOnly ? isColGroupBinding(target) : isHorizontalExpandBinding(target);
185
+ }
168
186
  function pickParentAt(target) {
169
187
  const pick = parentPick.value;
170
188
  if (!pick) return;
171
189
  if (target.row === pick.source.row && target.col === pick.source.col) return;
172
190
  const sourceBinding = getBindingAt(pick.source);
191
+ if (!sourceBinding) {
192
+ parentPick.value = null;
193
+ return;
194
+ }
173
195
  const targetBinding = getBindingAt(target);
174
- if (!sourceBinding || !targetBinding) return;
175
- if (targetBinding.dataset !== sourceBinding.dataset) return;
176
- if (pick.mode === "row" && !isVerticalExpandBinding(targetBinding)) return;
177
- if (pick.mode === "col" && !isHorizontalExpandBinding(targetBinding)) return;
196
+ if (!isValidParentTarget(pick.mode, sourceBinding, targetBinding)) {
197
+ workbook.value.activeSheet.selectCell(pick.source);
198
+ return;
199
+ }
178
200
  const patch = pick.mode === "row" ? { rowParent: { ...target } } : { colParent: { ...target } };
179
201
  const next = {
180
202
  ...sourceBinding,
@@ -1,4 +1,4 @@
1
- import { renderReport } from "../../report/render/index.js";
1
+ import { renderReport, resolveFilledColWidths } from "../../report/render/index.js";
2
2
  import { fetchTemplateRecords, resolveParamDefaults, resolveTemplateParams } from "../../report/template.js";
3
3
  import { computed, ref, shallowRef, watch } from "vue";
4
4
  //#region src/components/report/use-report-viewer.ts
@@ -10,6 +10,7 @@ function useReportViewer(props) {
10
10
  const loading = ref(false);
11
11
  const error = shallowRef(null);
12
12
  const filledSnapshot = shallowRef(null);
13
+ const filledColWidths = shallowRef(void 0);
13
14
  const params = computed(() => resolveTemplateParams(props.template));
14
15
  const values = shallowRef({});
15
16
  let fetchSeq = 0;
@@ -23,9 +24,11 @@ function useReportViewer(props) {
23
24
  loading.value = false;
24
25
  if (!result.ok) {
25
26
  error.value = result.error;
27
+ filledColWidths.value = void 0;
26
28
  return;
27
29
  }
28
30
  filledSnapshot.value = renderReport(template, result.data);
31
+ filledColWidths.value = template.colWidths?.length ? resolveFilledColWidths(template, result.data, template.colWidths) : void 0;
29
32
  }
30
33
  function setValues(next) {
31
34
  values.value = next;
@@ -33,6 +36,7 @@ function useReportViewer(props) {
33
36
  }
34
37
  watch(() => props.template, () => {
35
38
  filledSnapshot.value = null;
39
+ filledColWidths.value = void 0;
36
40
  values.value = resolveParamDefaults(params.value);
37
41
  refresh();
38
42
  }, { immediate: true });
@@ -42,6 +46,7 @@ function useReportViewer(props) {
42
46
  loading,
43
47
  error,
44
48
  filledSnapshot,
49
+ filledColWidths,
45
50
  refresh,
46
51
  setValues
47
52
  };
@@ -18,13 +18,36 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
18
18
  * 预设补丁由 core/style/border-presets 生成(含邻居格共享边同步,对齐
19
19
  * Excel「写入时同步、最近设置生效」);面板打开期间的写入由
20
20
  * use-tool-popup 事务包裹为一个 undo 单元。
21
+ * 整行/整列选区下,均匀预设(all/none/单侧)走 applyStyle → 行列默认样式。
21
22
  */
22
23
  const props = __props;
23
24
  const cls = bem("sheet");
24
25
  /** 当前线型 / 颜色 */
25
26
  const borderLineStyle = ref("thin");
26
27
  const borderColor = ref("#000000");
27
- /** 应用边框预设:一次 executeCommand(items 批量,含邻居同步补丁)= 一个 undo 单元 */
28
+ /** 均匀边框补丁(可写进行/列默认样式);outer/inner 几何相关 → null */
29
+ function uniformBorderPatch(preset, edge) {
30
+ switch (preset) {
31
+ case "all": return { border: {
32
+ top: edge,
33
+ right: edge,
34
+ bottom: edge,
35
+ left: edge
36
+ } };
37
+ case "none": return { border: {
38
+ top: null,
39
+ right: null,
40
+ bottom: null,
41
+ left: null
42
+ } };
43
+ case "top": return { border: { top: edge } };
44
+ case "bottom": return { border: { bottom: edge } };
45
+ case "left": return { border: { left: edge } };
46
+ case "right": return { border: { right: edge } };
47
+ default: return null;
48
+ }
49
+ }
50
+ /** 应用边框预设:整行/整列均匀预设走 applyStyle;其余逐格批量(含邻居同步) */
28
51
  function applyBorderPreset(preset) {
29
52
  const range = currentRange(props.context);
30
53
  if (!range) return;
@@ -33,7 +56,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
33
56
  width: BORDER_STYLE_WIDTH[borderLineStyle.value],
34
57
  color: borderColor.value
35
58
  };
36
- const items = buildBorderPresetItems(range, preset, edge, (addr) => props.context.getCellStyle(addr)).map(({ addr, patch }) => ({
59
+ const uniform = props.context.resolveStyleTarget(range) !== "cell" ? uniformBorderPatch(preset, edge) : null;
60
+ if (uniform) {
61
+ props.context.applyStyle(range, uniform);
62
+ return;
63
+ }
64
+ const items = buildBorderPresetItems(range, preset, edge, (addr) => props.context.getEffectiveStyle(addr)).map(({ addr, patch }) => ({
37
65
  addr,
38
66
  partial: patch
39
67
  }));
@@ -16,14 +16,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
16
16
  const fillColor = ref("");
17
17
  onMounted(() => {
18
18
  const active = props.context.getSelection().activeCell;
19
- const style = active ? props.context.getCellStyle(active) : void 0;
19
+ const style = active ? props.context.getEffectiveStyle(active) : void 0;
20
20
  fillColor.value = style?.fill?.color ?? "";
21
21
  });
22
22
  /** 填充颜色变化('' = 无填充:清除 fill 保留边框) */
23
23
  function applyFillColor(color) {
24
24
  const range = currentRange(props.context);
25
25
  if (!range) return;
26
- props.context.setCellStyle(range, color ? { fill: { color } } : { fill: {} });
26
+ props.context.applyStyle(range, color ? { fill: { color } } : { fill: {} });
27
27
  }
28
28
  return (_ctx, _cache) => {
29
29
  return openBlock(), createBlock(unref(UPalette), {
@@ -16,14 +16,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
16
16
  const fontColor = ref("");
17
17
  onMounted(() => {
18
18
  const active = props.context.getSelection().activeCell;
19
- const style = active ? props.context.getCellStyle(active) : void 0;
19
+ const style = active ? props.context.getEffectiveStyle(active) : void 0;
20
20
  fontColor.value = style?.font?.color ?? "";
21
21
  });
22
22
  /** 字体颜色变化('' = 清除 color) */
23
23
  function applyFontColor(color) {
24
24
  const range = currentRange(props.context);
25
25
  if (!range) return;
26
- props.context.setCellStyle(range, color ? { font: { color } } : { font: { color: null } });
26
+ props.context.applyStyle(range, color ? { font: { color } } : { font: { color: null } });
27
27
  }
28
28
  return (_ctx, _cache) => {
29
29
  return openBlock(), createBlock(unref(UPalette), {
@@ -32,14 +32,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
32
32
  const currentSize = ref(void 0);
33
33
  onMounted(() => {
34
34
  const active = props.context.getSelection().activeCell;
35
- const style = active ? props.context.getCellStyle(active) : void 0;
35
+ const style = active ? props.context.getEffectiveStyle(active) : void 0;
36
36
  currentSize.value = style?.font?.size;
37
37
  });
38
38
  function applyFontSize(size) {
39
39
  const range = currentRange(props.context);
40
40
  if (!range) return;
41
41
  currentSize.value = size;
42
- props.context.setCellStyle(range, { font: { size } });
42
+ props.context.applyStyle(range, { font: { size } });
43
43
  }
44
44
  return (_ctx, _cache) => {
45
45
  return openBlock(), createElementBlock(Fragment, null, [createCommentVNode(" 下拉排列:每行一个字号;滚动用 desktop UScroll(自定义滚动条) "), createVNode(unref(UScroll), {
@@ -38,11 +38,14 @@ function wholeColRange(col, rowCount) {
38
38
  col
39
39
  });
40
40
  }
41
- /** 渲染尺寸 = max(props, sheet.rows/cols),与 SheetGrid 一致 */
41
+ /**
42
+ * 渲染尺寸:模型已声明时以模型为准(删行可低于 props);未声明时回落 props。
43
+ * 与 SheetGrid / useSheetGrid 一致——避免 ensureTableSize(props) 把删行结果撑回。
44
+ */
42
45
  function resolveRenderSize(propsRows, propsCols, sheetRows, sheetCols) {
43
46
  return {
44
- rows: Math.max(propsRows ?? 100, sheetRows),
45
- cols: Math.max(propsCols ?? 26, sheetCols)
47
+ rows: sheetRows > 0 ? sheetRows : propsRows ?? 100,
48
+ cols: sheetCols > 0 ? sheetCols : propsCols ?? 26
46
49
  };
47
50
  }
48
51
  function insertCountRender(options) {
@@ -39,6 +39,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
39
39
  type: Boolean,
40
40
  default: true
41
41
  },
42
+ showRowHeader: {
43
+ type: Boolean,
44
+ default: true
45
+ },
46
+ showColHeader: {
47
+ type: Boolean,
48
+ default: true
49
+ },
42
50
  readonly: {
43
51
  type: Boolean,
44
52
  default: false
@@ -57,12 +57,15 @@ function useSheetGrid(options) {
57
57
  const el = document.createElement("div");
58
58
  el.className = "u-sheet__grid-instance";
59
59
  host.appendChild(el);
60
+ const { rows, cols } = resolveRenderSize(props.rows, props.cols, sheet.rows, sheet.cols);
60
61
  const grid = new SheetGrid({
61
62
  container: el,
62
63
  sheet,
63
- rows: props.rows,
64
- cols: props.cols,
64
+ rows,
65
+ cols,
65
66
  readonly: props.readonly,
67
+ showRowHeader: props.showRowHeader,
68
+ showColHeader: props.showColHeader,
66
69
  resolveDisplayValue: props.resolveDisplayValue,
67
70
  resolveCellStyle: props.resolveCellStyle,
68
71
  resolveCellRenderer: props.resolveCellRenderer,
@@ -172,8 +175,15 @@ function useSheetGrid(options) {
172
175
  watch(() => [
173
176
  props.rows,
174
177
  props.cols,
175
- props.readonly
176
- ], rebuildGrid);
178
+ props.readonly,
179
+ props.showRowHeader,
180
+ props.showColHeader
181
+ ], ([nextRows, nextCols]) => {
182
+ const sheet = getActiveSheet();
183
+ if (nextRows != null) sheet.ensureTableSize(nextRows, 0);
184
+ if (nextCols != null) sheet.ensureTableSize(0, nextCols);
185
+ rebuildGrid();
186
+ });
177
187
  onBeforeUnmount(() => {
178
188
  invalidateAll();
179
189
  });
@@ -1,5 +1,6 @@
1
1
  import { defaultToolRegistry } from "../../tools/registry.js";
2
2
  import { createSheetContext } from "../../tools/context.js";
3
+ import { resolveRenderSize } from "./sheet-context-menu.js";
3
4
  import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue";
4
5
  import { Workbook } from "@veltra/sheet-core/core/workbook";
5
6
  //#region src/components/sheet/use-sheet-state.ts
@@ -19,8 +20,8 @@ function useSheetState(props, emit, hooks) {
19
20
  /** sheet 列表(tabs 渲染;由 sheets-change 同步) */
20
21
  const sheetList = shallowRef(workbook.value.getSheets());
21
22
  const activeSheet = computed(() => sheetList.value[activeIndex.value] ?? workbook.value.activeSheet);
22
- /** 工具上下文:动态解析活动 sheet 与当前工作簿,tab 切换 / workbook prop 切换后自动指向最新值 */
23
- const context = createSheetContext(() => activeSheet.value, () => workbook.value);
23
+ /** 工具上下文:动态解析活动 sheet / 工作簿 / 渲染尺寸,tab 切换后自动指向最新值 */
24
+ const context = createSheetContext(() => activeSheet.value, () => workbook.value, { resolveGridSize: () => resolveRenderSize(props.rows, props.cols, activeSheet.value.rows, activeSheet.value.cols) });
24
25
  /** 工具栏状态版本号:visible/disabled/active 是 (ctx) => boolean 纯函数,状态源变化时 bump 触发重算 */
25
26
  const stateTick = ref(0);
26
27
  const bump = () => {
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import { SheetContext, createSheetContext } from "./tools/context.js";
5
5
  import { SheetTool, SheetToolGroup, SheetToolPopupType, defaultToolRegistry, registerTool, unregisterTool } from "./tools/registry.js";
6
6
  import { SheetEmits, SheetExposed, SheetProps, _SheetExposed } from "./types/sheet.js";
7
7
  import { ConditionalOperator, ConditionalRule, DatasetCatalogItem, DatasetField, DatasetRecords, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, ReportAggregate, ReportBinding, ReportExpand, ReportPreset, ReportSort } from "./report/types.js";
8
- import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog } from "./report/binding.js";
8
+ import { InferParentOptions, ListParentCandidateOptions, REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, prefersGroupParent, presetBindingPatch, presetStillApplies, setBindingCatalog } from "./report/binding.js";
9
9
  import { ConditionalEvalContext, evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./report/rules/evaluate.js";
10
10
  import { buildParamDefs, extractParamIds, resolveBoundDatasetParams } from "./report/params.js";
11
11
  import { ReportColWidthEntry, buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth } from "./report/export-xlsx.js";
@@ -18,4 +18,4 @@ import "./report/index.js";
18
18
  import { ReportViewerExposed, ReportViewerProps, _ReportViewerExposed } from "./types/report-viewer.js";
19
19
  import { ReportDesignerEmits, ReportDesignerExposed, ReportDesignerProps, _ReportDesignerExposed } from "./types/report-designer.js";
20
20
  import "./types/index.js";
21
- 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, type ReportDesignerEmits, type ReportDesignerExposed, type ReportDesignerProps, ReportExpand, ReportPreset, ReportSort, ReportTemplate, type ReportViewerExposed, type ReportViewerProps, Result, type SheetContext, type SheetEmits, type SheetExposed, type SheetProps, type SheetTool, type SheetToolGroup, type SheetToolPopupType, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, type _ReportDesignerExposed, type _ReportViewerExposed, type _SheetExposed, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatCellAddress, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, presetBindingPatch, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
21
+ export { type ConditionalEvalContext, ConditionalOperator, ConditionalRule, ConnectionType, ConnectorError, CreateHttpConnectorOptions, DEFAULT_CONNECTION_PORTS, DataConnection, DataConnector, DatasetCatalogItem, DatasetField, DatasetRecords, IncompatibleTemplateVersionError, InferParentOptions, ListParentCandidateOptions, ParamValues, QueryParamDef, QueryParamOption, QueryParamType, QueryResult, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, ReportAggregate, ReportBinding, ReportColWidthEntry, ReportDatasetDef, type ReportDesignerEmits, type ReportDesignerExposed, type ReportDesignerProps, ReportExpand, ReportPreset, ReportSort, ReportTemplate, type ReportViewerExposed, type ReportViewerProps, Result, type SheetContext, type SheetEmits, type SheetExposed, type SheetProps, type SheetTool, type SheetToolGroup, type SheetToolPopupType, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, type _ReportDesignerExposed, type _ReportViewerExposed, type _SheetExposed, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, prefersGroupParent, presetBindingPatch, presetStillApplies, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { createSheetContext } from "./tools/context.js";
4
4
  import _sfc_main$2 from "./components/sheet/sheet.js";
5
5
  import { buildColumnDefs, exportFilledReportXlsx, pxToExcelColWidth } from "./report/export-xlsx.js";
6
6
  import { parseDateRangeValue, patchParamValues, resolveNumberParamValue } from "./report/filter-bar.js";
7
- import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatCellAddress, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, presetBindingPatch, setBindingCatalog } from "./report/binding.js";
7
+ import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, parseCellAddress, prefersGroupParent, presetBindingPatch, presetStillApplies, setBindingCatalog } from "./report/binding.js";
8
8
  import { evaluateCondition, evaluateConditionalStyle, resolveRuleCompareValue, toComparableNumber } from "./report/rules/evaluate.js";
9
9
  import { mapFilledColWidths } from "./report/render/builder.js";
10
10
  import { renderReport, resolveFilledColWidths } from "./report/render/index.js";
@@ -13,4 +13,4 @@ import { IncompatibleTemplateVersionError, REPORT_TEMPLATE_VERSION, assertCompat
13
13
  import _sfc_main$1 from "./components/report/report-viewer.js";
14
14
  import { DEFAULT_CONNECTION_PORTS, createHttpConnector, resolvePortOnTypeChange } from "./report/connector.js";
15
15
  import _sfc_main from "./components/report/report-designer.js";
16
- export { DEFAULT_CONNECTION_PORTS, IncompatibleTemplateVersionError, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatCellAddress, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferReportPreset, inferRowParentCandidate, isExpansionBandRow, isHorizontalExpandBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, presetBindingPatch, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };
16
+ export { DEFAULT_CONNECTION_PORTS, IncompatibleTemplateVersionError, REPORT_META_NAMESPACE, REPORT_TEMPLATE_VERSION, _sfc_main as UReportDesigner, _sfc_main$1 as UReportViewer, _sfc_main$2 as USheet, applyReportPreset, assertCompatibleTemplateVersion, buildColumnDefs, buildParamDefs, createHttpConnector, createReportBinding, createReportTemplate, createSheetContext, defaultToolRegistry, evaluateCondition, evaluateConditionalStyle, exportFilledReportXlsx, extractParamIds, fetchTemplateRecords, formatBindingPlaceholder, formatBindingPlaceholderParts, formatCellAddress, formatParentCandidateLabel, getBoundDatasetIds, getTemplateDatasets, inferColParentCandidate, inferDropPreset, inferParentsForPreset, inferReportPreset, inferRowParentCandidate, isColGroupBinding, isExpansionBandCol, isExpansionBandRow, isHorizontalExpandBinding, isReductionAggregate, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, mapFilledColWidths, parseCellAddress, parseDateRangeValue, patchParamValues, prefersGroupParent, presetBindingPatch, presetStillApplies, pxToExcelColWidth, registerTool, renderReport, resolveBoundDatasetParams, resolveFilledColWidths, resolveNumberParamValue, resolveParamDefaults, resolvePortOnTypeChange, resolveRuleCompareValue, resolveTemplateParams, setBindingCatalog, toComparableNumber, unregisterTool };