@veltra/sheet 2.4.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/sheet/formula-bar.js +50 -7
- package/dist/components/sheet/style2.css +2 -2
- package/dist/index.d.ts +2 -19
- package/dist/index.js +2 -15
- package/dist/types/index.d.ts +1 -3
- package/package.json +5 -6
- package/src/components/sheet/__test__/formula-bar.test.ts +29 -0
- package/src/components/sheet/formula-bar.vue +67 -6
- package/src/components/sheet/style.scss +1 -1
- package/src/index.ts +1 -27
- package/src/types/index.ts +0 -2
- package/dist/components/report/binding-badge.js +0 -118
- package/dist/components/report/designer/cell-coords.js +0 -46
- package/dist/components/report/designer/col-widths.js +0 -29
- package/dist/components/report/designer/conditional-rules/helpers.js +0 -139
- package/dist/components/report/designer/drill-dialog.js +0 -258
- package/dist/components/report/designer/drop-highlight-overlay.js +0 -76
- package/dist/components/report/designer/float-panel.js +0 -434
- package/dist/components/report/designer/role.js +0 -17
- package/dist/components/report/designer/rule-preview.js +0 -33
- package/dist/components/report/designer/rule-row.js +0 -253
- package/dist/components/report/designer/rules-dialog.js +0 -118
- package/dist/components/report/designer/topology-overlay.js +0 -122
- package/dist/components/report/designer/topology.js +0 -64
- package/dist/components/report/designer/use-grid-overlay.js +0 -75
- package/dist/components/report/designer-hub.js +0 -177
- package/dist/components/report/field-panel-helpers.js +0 -33
- package/dist/components/report/field-panel.js +0 -132
- package/dist/components/report/filter-bar.js +0 -74
- package/dist/components/report/hub-connection-form.js +0 -145
- package/dist/components/report/hub-dataset-editor.js +0 -409
- package/dist/components/report/preview-grid-size.js +0 -32
- package/dist/components/report/print.js +0 -39
- package/dist/components/report/report-designer.js +0 -428
- package/dist/components/report/report-viewer.js +0 -253
- package/dist/components/report/style.d.ts +0 -17
- package/dist/components/report/style.js +0 -18
- package/dist/components/report/style2.css +0 -965
- package/dist/components/report/use-report-designer.js +0 -387
- package/dist/components/report/use-report-viewer.js +0 -140
- package/dist/report/binding.d.ts +0 -83
- package/dist/report/binding.js +0 -334
- package/dist/report/connector.d.ts +0 -66
- package/dist/report/connector.js +0 -159
- package/dist/report/drill.d.ts +0 -48
- package/dist/report/drill.js +0 -78
- package/dist/report/export-xlsx.d.ts +0 -13
- package/dist/report/export-xlsx.js +0 -13
- package/dist/report/filter-bar.d.ts +0 -10
- package/dist/report/filter-bar.js +0 -31
- package/dist/report/index.d.ts +0 -14
- package/dist/report/params.d.ts +0 -13
- package/dist/report/params.js +0 -61
- package/dist/report/print.d.ts +0 -23
- package/dist/report/print.js +0 -197
- package/dist/report/render/aggregate.js +0 -193
- package/dist/report/render/builder.d.ts +0 -12
- package/dist/report/render/builder.js +0 -139
- package/dist/report/render/coordinate.d.ts +0 -25
- package/dist/report/render/coordinate.js +0 -733
- package/dist/report/render/index.d.ts +0 -14
- package/dist/report/render/index.js +0 -21
- package/dist/report/render/style-resolver.js +0 -50
- package/dist/report/render/template-index.d.ts +0 -24
- package/dist/report/render/template-index.js +0 -137
- package/dist/report/rules/evaluate.d.ts +0 -25
- package/dist/report/rules/evaluate.js +0 -82
- package/dist/report/rules/index.d.ts +0 -2
- package/dist/report/template.d.ts +0 -63
- package/dist/report/template.js +0 -83
- package/dist/report/types.d.ts +0 -103
- package/dist/types/report-designer.d.ts +0 -51
- package/dist/types/report-viewer.d.ts +0 -57
- package/src/components/report/__test__/binding-badge.test.ts +0 -92
- package/src/components/report/__test__/conditional-rules-helpers.test.ts +0 -88
- package/src/components/report/__test__/field-panel-helpers.test.ts +0 -65
- package/src/components/report/__test__/float-panel-position.test.ts +0 -45
- package/src/components/report/__test__/preview-grid-size.test.ts +0 -63
- package/src/components/report/__test__/report-designer.test.ts +0 -559
- package/src/components/report/__test__/report-drill.test.ts +0 -692
- package/src/components/report/__test__/report-viewer.test.ts +0 -400
- package/src/components/report/__test__/topology.test.ts +0 -143
- package/src/components/report/__test__/use-report-designer.test.ts +0 -804
- package/src/components/report/binding-badge.ts +0 -122
- package/src/components/report/designer/cell-coords.ts +0 -95
- package/src/components/report/designer/col-widths.ts +0 -56
- package/src/components/report/designer/conditional-rules/helpers.ts +0 -189
- package/src/components/report/designer/drill-dialog.vue +0 -245
- package/src/components/report/designer/drop-highlight-overlay.vue +0 -75
- package/src/components/report/designer/float-panel.vue +0 -444
- package/src/components/report/designer/role.ts +0 -32
- package/src/components/report/designer/rule-preview.vue +0 -40
- package/src/components/report/designer/rule-row.vue +0 -252
- package/src/components/report/designer/rules-dialog.vue +0 -110
- package/src/components/report/designer/topology-overlay.vue +0 -128
- package/src/components/report/designer/topology.ts +0 -124
- package/src/components/report/designer/use-grid-overlay.ts +0 -114
- package/src/components/report/designer-hub.vue +0 -198
- package/src/components/report/field-panel-helpers.ts +0 -44
- package/src/components/report/field-panel.vue +0 -136
- package/src/components/report/filter-bar.vue +0 -77
- package/src/components/report/hub-connection-form.vue +0 -124
- package/src/components/report/hub-dataset-editor.vue +0 -387
- package/src/components/report/index.ts +0 -2
- package/src/components/report/preview-grid-size.ts +0 -33
- package/src/components/report/print.ts +0 -44
- package/src/components/report/report-designer.vue +0 -454
- package/src/components/report/report-viewer.vue +0 -289
- package/src/components/report/style-designer.scss +0 -653
- package/src/components/report/style-hub.scss +0 -292
- package/src/components/report/style-viewer.scss +0 -144
- package/src/components/report/style.scss +0 -3
- package/src/components/report/style.ts +0 -20
- package/src/components/report/use-report-designer.ts +0 -603
- package/src/components/report/use-report-viewer.ts +0 -227
- package/src/report/__test__/binding.test.ts +0 -320
- package/src/report/__test__/connector.test.ts +0 -239
- package/src/report/__test__/drill.test.ts +0 -194
- package/src/report/__test__/export-xlsx.test.ts +0 -96
- package/src/report/__test__/filter-bar.test.ts +0 -58
- package/src/report/__test__/params.test.ts +0 -156
- package/src/report/__test__/print.test.ts +0 -170
- package/src/report/__test__/render.test.ts +0 -856
- package/src/report/__test__/rules.test.ts +0 -131
- package/src/report/__test__/template.test.ts +0 -366
- package/src/report/binding.ts +0 -474
- package/src/report/connector.ts +0 -206
- package/src/report/drill.ts +0 -112
- package/src/report/export-xlsx.ts +0 -15
- package/src/report/filter-bar.ts +0 -36
- package/src/report/index.ts +0 -16
- package/src/report/params.ts +0 -96
- package/src/report/print.ts +0 -234
- package/src/report/render/__test__/aggregate.test.ts +0 -16
- package/src/report/render/__test__/coordinate.test.ts +0 -405
- package/src/report/render/aggregate.ts +0 -289
- package/src/report/render/builder.ts +0 -211
- package/src/report/render/coordinate.ts +0 -1239
- package/src/report/render/index.ts +0 -30
- package/src/report/render/style-resolver.ts +0 -68
- package/src/report/render/template-index.ts +0 -200
- package/src/report/rules/evaluate.ts +0 -113
- package/src/report/rules/index.ts +0 -7
- package/src/report/template.ts +0 -145
- package/src/report/types.ts +0 -116
- package/src/types/report-designer.ts +0 -55
- package/src/types/report-viewer.ts +0 -54
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import { REPORT_META_NAMESPACE, applyReportPreset, createReportBinding, formatCellAddress, inferDropPreset, inferParentsForPreset, isColGroupBinding, isHorizontalExpandBinding, isRowGroupBinding, isVerticalExpandBinding, listColParentCandidates, listRowParentCandidates, prefersGroupParent, presetStillApplies } from "../../report/binding.js";
|
|
2
|
-
import { buildParamDefs } from "../../report/params.js";
|
|
3
|
-
import { assertCompatibleTemplateVersion, createReportTemplate, getTemplateDatasets, resolveParamDefaults } from "../../report/template.js";
|
|
4
|
-
import { createBindingBadgeRenderer, createBindingBadgeStyleResolver } from "./binding-badge.js";
|
|
5
|
-
import { computed, onScopeDispose, ref, watch } from "vue";
|
|
6
|
-
import { Workbook } from "@veltra/sheet-core";
|
|
7
|
-
//#region src/components/report/use-report-designer.ts
|
|
8
|
-
/**
|
|
9
|
-
* UReportDesigner 的 headless 编排:连接 / 数据集状态、绑定写 Cell Meta、
|
|
10
|
-
* 角色徽章渲染 hook、`getTemplate()` 模板吐出。不持有 DOM / 网格引用。
|
|
11
|
-
*/
|
|
12
|
-
function useReportDesigner(options) {
|
|
13
|
-
const { props, connections } = options;
|
|
14
|
-
/** 设计态工作簿:宿主可注入(USheet / UReportViewer 先例),缺省内部自建 */
|
|
15
|
-
const internalWorkbook = new Workbook();
|
|
16
|
-
const workbook = computed(() => props.workbook ?? internalWorkbook);
|
|
17
|
-
const datasets = ref([]);
|
|
18
|
-
/** meta 变更计数:boundKeys 等派生状态的响应式触发(绑定经命令系统写入后由模型发 meta-change) */
|
|
19
|
-
const metaTick = ref(0);
|
|
20
|
-
const parentPick = ref(null);
|
|
21
|
-
const offMeta = workbook.value.activeSheet.on("meta-change", () => {
|
|
22
|
-
metaTick.value++;
|
|
23
|
-
});
|
|
24
|
-
onScopeDispose(offMeta);
|
|
25
|
-
/** 稳定选区地址引用(值未变时不替换对象,避免触发下游 watcher) */
|
|
26
|
-
const activeCell = ref(null);
|
|
27
|
-
function syncActiveCell() {
|
|
28
|
-
const next = workbook.value.activeSheet.getSelection().activeCell ?? null;
|
|
29
|
-
const prev = activeCell.value;
|
|
30
|
-
if (!next) {
|
|
31
|
-
activeCell.value = null;
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (prev && prev.row === next.row && prev.col === next.col) return;
|
|
35
|
-
activeCell.value = {
|
|
36
|
-
row: next.row,
|
|
37
|
-
col: next.col
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const offSelection = workbook.value.activeSheet.on("selection-change", syncActiveCell);
|
|
41
|
-
onScopeDispose(offSelection);
|
|
42
|
-
syncActiveCell();
|
|
43
|
-
const selectionLabel = computed(() => activeCell.value ? formatCellAddress(activeCell.value) : "—");
|
|
44
|
-
const catalog = computed(() => datasets.value.map((dataset) => ({
|
|
45
|
-
id: dataset.id,
|
|
46
|
-
label: dataset.label,
|
|
47
|
-
fields: (dataset.fields ?? []).map((field) => ({
|
|
48
|
-
...field,
|
|
49
|
-
label: dataset.fieldOverrides?.[field.name]?.label ?? field.label
|
|
50
|
-
}))
|
|
51
|
-
})));
|
|
52
|
-
/** 字段 label 的 O(1) 查找表(徽章 hook 性能契约) */
|
|
53
|
-
const fieldLabelMap = computed(() => {
|
|
54
|
-
const map = /* @__PURE__ */ new Map();
|
|
55
|
-
for (const dataset of catalog.value) for (const field of dataset.fields) map.set(`${dataset.id}:${field.name}`, field.label);
|
|
56
|
-
return map;
|
|
57
|
-
});
|
|
58
|
-
function resolveFieldLabel(datasetId, fieldName) {
|
|
59
|
-
return fieldLabelMap.value.get(`${datasetId}:${fieldName}`) ?? fieldName;
|
|
60
|
-
}
|
|
61
|
-
const boundKeys = computed(() => {
|
|
62
|
-
metaTick.value;
|
|
63
|
-
const keys = /* @__PURE__ */ new Set();
|
|
64
|
-
for (const [, namespace, payload] of workbook.value.activeSheet.entriesCellMeta()) {
|
|
65
|
-
if (namespace !== "report") continue;
|
|
66
|
-
const binding = payload;
|
|
67
|
-
keys.add(`${binding.dataset}:${binding.field}`);
|
|
68
|
-
}
|
|
69
|
-
return keys;
|
|
70
|
-
});
|
|
71
|
-
function getBindingAt(addr) {
|
|
72
|
-
return workbook.value.activeSheet.getCellMeta(addr, REPORT_META_NAMESPACE);
|
|
73
|
-
}
|
|
74
|
-
function bindField(datasetId, fieldName, addr) {
|
|
75
|
-
const dataset = catalog.value.find((item) => item.id === datasetId);
|
|
76
|
-
if (!dataset) return;
|
|
77
|
-
const field = dataset.fields.find((item) => item.name === fieldName);
|
|
78
|
-
const target = addr ?? workbook.value.activeSheet.getSelection().activeCell;
|
|
79
|
-
if (!target) return;
|
|
80
|
-
const preset = inferDropPreset(target, field?.type ?? "string", getBindingAt);
|
|
81
|
-
let binding = createReportBinding(dataset, fieldName);
|
|
82
|
-
binding = applyReportPreset(binding, preset);
|
|
83
|
-
const parents = inferParentsForPreset(target, preset, getBindingAt);
|
|
84
|
-
if (parents.rowParent) binding.rowParent = parents.rowParent;
|
|
85
|
-
if (parents.colParent) binding.colParent = parents.colParent;
|
|
86
|
-
workbook.value.activeSheet.setCellMeta(target, REPORT_META_NAMESPACE, binding);
|
|
87
|
-
}
|
|
88
|
-
const activeBinding = computed(() => {
|
|
89
|
-
metaTick.value;
|
|
90
|
-
const cell = activeCell.value;
|
|
91
|
-
if (!cell) return void 0;
|
|
92
|
-
return getBindingAt(cell);
|
|
93
|
-
});
|
|
94
|
-
const activeFieldType = computed(() => {
|
|
95
|
-
const binding = activeBinding.value;
|
|
96
|
-
if (!binding) return "number";
|
|
97
|
-
return (catalog.value.find((item) => item.id === binding.dataset)?.fields.find((item) => item.name === binding.field))?.type ?? "number";
|
|
98
|
-
});
|
|
99
|
-
const activeDatasetFields = computed(() => {
|
|
100
|
-
const binding = activeBinding.value;
|
|
101
|
-
if (!binding) return [];
|
|
102
|
-
return catalog.value.find((item) => item.id === binding.dataset)?.fields ?? [];
|
|
103
|
-
});
|
|
104
|
-
const resolvedRowParentLabel = computed(() => {
|
|
105
|
-
metaTick.value;
|
|
106
|
-
const binding = activeBinding.value;
|
|
107
|
-
if (!binding?.rowParent) return "—";
|
|
108
|
-
return formatCellAddress(binding.rowParent);
|
|
109
|
-
});
|
|
110
|
-
const resolvedColParentLabel = computed(() => {
|
|
111
|
-
metaTick.value;
|
|
112
|
-
const binding = activeBinding.value;
|
|
113
|
-
if (!binding?.colParent) return "—";
|
|
114
|
-
return formatCellAddress(binding.colParent);
|
|
115
|
-
});
|
|
116
|
-
const rowParentCandidates = computed(() => {
|
|
117
|
-
metaTick.value;
|
|
118
|
-
const binding = activeBinding.value;
|
|
119
|
-
if (!binding) return [];
|
|
120
|
-
return listRowParentCandidates(binding, bindingEntries.value, { preferGroup: prefersGroupParent(binding) });
|
|
121
|
-
});
|
|
122
|
-
const colParentCandidates = computed(() => {
|
|
123
|
-
metaTick.value;
|
|
124
|
-
const binding = activeBinding.value;
|
|
125
|
-
if (!binding) return [];
|
|
126
|
-
return listColParentCandidates(binding, bindingEntries.value, { preferGroup: prefersGroupParent(binding) });
|
|
127
|
-
});
|
|
128
|
-
const bindingEntries = computed(() => {
|
|
129
|
-
metaTick.value;
|
|
130
|
-
const entries = [];
|
|
131
|
-
for (const [addr, namespace, payload] of workbook.value.activeSheet.entriesCellMeta()) {
|
|
132
|
-
if (namespace !== "report") continue;
|
|
133
|
-
entries.push({
|
|
134
|
-
addr,
|
|
135
|
-
binding: payload
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
return entries;
|
|
139
|
-
});
|
|
140
|
-
function parentNeedsCorrection(addr) {
|
|
141
|
-
if (!addr) return true;
|
|
142
|
-
const parent = getBindingAt(addr);
|
|
143
|
-
return !parent || parent.aggregate === "list";
|
|
144
|
-
}
|
|
145
|
-
function patchActiveBinding(patch) {
|
|
146
|
-
const cell = activeCell.value;
|
|
147
|
-
const binding = activeBinding.value;
|
|
148
|
-
if (!cell || !binding) return;
|
|
149
|
-
const next = {
|
|
150
|
-
...binding,
|
|
151
|
-
...patch
|
|
152
|
-
};
|
|
153
|
-
if ("rowParent" in patch && patch.rowParent === void 0) delete next.rowParent;
|
|
154
|
-
if ("colParent" in patch && patch.colParent === void 0) delete next.colParent;
|
|
155
|
-
if ("drill" in patch && patch.drill === void 0) delete next.drill;
|
|
156
|
-
if (("aggregate" in patch || "expand" in patch) && !("preset" in patch) && !presetStillApplies(next)) delete next.preset;
|
|
157
|
-
if (patch.preset === "subtotal") {
|
|
158
|
-
const inferred = inferParentsForPreset(cell, "subtotal", getBindingAt);
|
|
159
|
-
if (parentNeedsCorrection(next.rowParent)) {
|
|
160
|
-
if (inferred.rowParent) next.rowParent = inferred.rowParent;
|
|
161
|
-
else delete next.rowParent;
|
|
162
|
-
}
|
|
163
|
-
if (parentNeedsCorrection(next.colParent)) {
|
|
164
|
-
if (inferred.colParent) next.colParent = inferred.colParent;
|
|
165
|
-
else delete next.colParent;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
workbook.value.activeSheet.setCellMeta(cell, REPORT_META_NAMESPACE, next);
|
|
169
|
-
}
|
|
170
|
-
function startParentPick(mode) {
|
|
171
|
-
const cell = activeCell.value;
|
|
172
|
-
if (!cell || !activeBinding.value) return;
|
|
173
|
-
parentPick.value = {
|
|
174
|
-
mode,
|
|
175
|
-
source: {
|
|
176
|
-
row: cell.row,
|
|
177
|
-
col: cell.col
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function cancelParentPick() {
|
|
182
|
-
parentPick.value = null;
|
|
183
|
-
}
|
|
184
|
-
function isValidParentTarget(mode, source, target) {
|
|
185
|
-
if (!target) return false;
|
|
186
|
-
if (target.dataset !== source.dataset) return false;
|
|
187
|
-
const groupOnly = prefersGroupParent(source);
|
|
188
|
-
if (mode === "row") return groupOnly ? isRowGroupBinding(target) : isVerticalExpandBinding(target);
|
|
189
|
-
return groupOnly ? isColGroupBinding(target) : isHorizontalExpandBinding(target);
|
|
190
|
-
}
|
|
191
|
-
function pickParentAt(target) {
|
|
192
|
-
const pick = parentPick.value;
|
|
193
|
-
if (!pick) return;
|
|
194
|
-
if (target.row === pick.source.row && target.col === pick.source.col) return;
|
|
195
|
-
const sourceBinding = getBindingAt(pick.source);
|
|
196
|
-
if (!sourceBinding) {
|
|
197
|
-
parentPick.value = null;
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const targetBinding = getBindingAt(target);
|
|
201
|
-
if (!isValidParentTarget(pick.mode, sourceBinding, targetBinding)) {
|
|
202
|
-
workbook.value.activeSheet.selectCell(pick.source);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
const patch = pick.mode === "row" ? { rowParent: { ...target } } : { colParent: { ...target } };
|
|
206
|
-
const next = {
|
|
207
|
-
...sourceBinding,
|
|
208
|
-
...patch
|
|
209
|
-
};
|
|
210
|
-
workbook.value.activeSheet.setCellMeta(pick.source, REPORT_META_NAMESPACE, next);
|
|
211
|
-
parentPick.value = null;
|
|
212
|
-
workbook.value.activeSheet.selectCell(pick.source);
|
|
213
|
-
}
|
|
214
|
-
function clearParent(mode) {
|
|
215
|
-
if (mode === "row") patchActiveBinding({ rowParent: void 0 });
|
|
216
|
-
else patchActiveBinding({ colParent: void 0 });
|
|
217
|
-
}
|
|
218
|
-
function removeActiveBinding() {
|
|
219
|
-
const cell = activeCell.value;
|
|
220
|
-
if (!cell) return;
|
|
221
|
-
workbook.value.activeSheet.clearCellMeta(cell, REPORT_META_NAMESPACE);
|
|
222
|
-
}
|
|
223
|
-
function addConnection(connection) {
|
|
224
|
-
connections.value = [...connections.value, connection];
|
|
225
|
-
}
|
|
226
|
-
function updateConnection(connection) {
|
|
227
|
-
connections.value = connections.value.map((item) => item.id === connection.id ? connection : item);
|
|
228
|
-
}
|
|
229
|
-
function removeConnection(connectionId) {
|
|
230
|
-
connections.value = connections.value.filter((item) => item.id !== connectionId);
|
|
231
|
-
datasets.value = datasets.value.filter((dataset) => dataset.connectionId !== connectionId);
|
|
232
|
-
}
|
|
233
|
-
let datasetSeq = 0;
|
|
234
|
-
function addDataset(connectionId) {
|
|
235
|
-
const dataset = {
|
|
236
|
-
id: `dataset-${Date.now()}-${datasetSeq++}`,
|
|
237
|
-
label: "新数据集",
|
|
238
|
-
connectionId,
|
|
239
|
-
sql: ""
|
|
240
|
-
};
|
|
241
|
-
datasets.value = [...datasets.value, dataset];
|
|
242
|
-
return dataset;
|
|
243
|
-
}
|
|
244
|
-
function updateDataset(datasetId, patch) {
|
|
245
|
-
datasets.value = datasets.value.map((item) => item.id === datasetId ? {
|
|
246
|
-
...item,
|
|
247
|
-
...patch
|
|
248
|
-
} : item);
|
|
249
|
-
}
|
|
250
|
-
function removeDataset(datasetId) {
|
|
251
|
-
datasets.value = datasets.value.filter((item) => item.id !== datasetId);
|
|
252
|
-
}
|
|
253
|
-
function resolveDatasetConnection(dataset) {
|
|
254
|
-
return connections.value.find((item) => item.id === dataset.connectionId);
|
|
255
|
-
}
|
|
256
|
-
function datasetNotFound() {
|
|
257
|
-
return {
|
|
258
|
-
ok: false,
|
|
259
|
-
error: {
|
|
260
|
-
code: "DATASET_NOT_FOUND",
|
|
261
|
-
message: "数据集不存在"
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
function connectionNotFound() {
|
|
266
|
-
return {
|
|
267
|
-
ok: false,
|
|
268
|
-
error: {
|
|
269
|
-
code: "CONNECTION_NOT_FOUND",
|
|
270
|
-
message: "数据集所属连接不存在"
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
function testConnection(connection) {
|
|
275
|
-
return props.connector.test(connection);
|
|
276
|
-
}
|
|
277
|
-
async function describeDataset(datasetId) {
|
|
278
|
-
const dataset = datasets.value.find((item) => item.id === datasetId);
|
|
279
|
-
if (!dataset) return datasetNotFound();
|
|
280
|
-
const connection = resolveDatasetConnection(dataset);
|
|
281
|
-
if (!connection) return connectionNotFound();
|
|
282
|
-
const sql = dataset.sql;
|
|
283
|
-
const result = await props.connector.describe(connection, sql);
|
|
284
|
-
if (result.ok) {
|
|
285
|
-
const current = datasets.value.find((item) => item.id === datasetId);
|
|
286
|
-
if (current && current.sql === sql) updateDataset(datasetId, { fields: result.data });
|
|
287
|
-
}
|
|
288
|
-
return result;
|
|
289
|
-
}
|
|
290
|
-
async function previewDataset(datasetId) {
|
|
291
|
-
const dataset = datasets.value.find((item) => item.id === datasetId);
|
|
292
|
-
if (!dataset) return datasetNotFound();
|
|
293
|
-
const connection = resolveDatasetConnection(dataset);
|
|
294
|
-
if (!connection) return connectionNotFound();
|
|
295
|
-
const values = resolveParamDefaults(buildParamDefs(dataset.sql, dataset.paramOverrides));
|
|
296
|
-
return props.connector.query(connection, dataset.sql, values);
|
|
297
|
-
}
|
|
298
|
-
const resolveCellStyle = createBindingBadgeStyleResolver(getBindingAt);
|
|
299
|
-
const resolveCellRenderer = createBindingBadgeRenderer(getBindingAt, resolveFieldLabel, (addr) => workbook.value.activeSheet.getEffectiveStyle(addr)?.align);
|
|
300
|
-
function getTemplate() {
|
|
301
|
-
const resolved = datasets.value.flatMap((dataset) => {
|
|
302
|
-
const connection = resolveDatasetConnection(dataset);
|
|
303
|
-
if (!connection) return [];
|
|
304
|
-
return [{
|
|
305
|
-
id: dataset.id,
|
|
306
|
-
label: dataset.label,
|
|
307
|
-
connection: { ...connection },
|
|
308
|
-
sql: dataset.sql,
|
|
309
|
-
...dataset.paramOverrides ? { paramOverrides: dataset.paramOverrides } : {},
|
|
310
|
-
...dataset.fieldOverrides ? { fieldOverrides: dataset.fieldOverrides } : {}
|
|
311
|
-
}];
|
|
312
|
-
});
|
|
313
|
-
return createReportTemplate(workbook.value.activeSheet.snapshot(), resolved);
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* 载入既有 Report Template 继续设计(`template` prop):
|
|
317
|
-
* 快照恢复网格绑定(restore + restoreContent 与查看器同路径);
|
|
318
|
-
* 内嵌数据集定义还原为设计态(connectionId 引用),内嵌连接按 id 合并进
|
|
319
|
-
* v-model 连接列表(仅缺省追加,宿主列表是单一事实源);
|
|
320
|
-
* describe 恢复字段缓存(字段面板数据源),业务错误忽略(字段留空,可在数据中枢重试)。
|
|
321
|
-
*/
|
|
322
|
-
function loadTemplate(template) {
|
|
323
|
-
assertCompatibleTemplateVersion(template);
|
|
324
|
-
const sheet = workbook.value.activeSheet;
|
|
325
|
-
sheet.restore(template);
|
|
326
|
-
sheet.restoreContent(template);
|
|
327
|
-
sheet.history.clear();
|
|
328
|
-
syncActiveCell();
|
|
329
|
-
const defs = getTemplateDatasets(template);
|
|
330
|
-
datasets.value = defs.map((def) => ({
|
|
331
|
-
id: def.id,
|
|
332
|
-
label: def.label,
|
|
333
|
-
connectionId: def.connection.id,
|
|
334
|
-
sql: def.sql,
|
|
335
|
-
...def.paramOverrides ? { paramOverrides: def.paramOverrides } : {},
|
|
336
|
-
...def.fieldOverrides ? { fieldOverrides: def.fieldOverrides } : {}
|
|
337
|
-
}));
|
|
338
|
-
const missing = defs.map((def) => def.connection).filter((connection) => !connections.value.some((item) => item.id === connection.id));
|
|
339
|
-
if (missing.length > 0) connections.value = [...connections.value, ...missing.map((connection) => ({ ...connection }))];
|
|
340
|
-
for (const dataset of datasets.value) if (dataset.sql.trim()) describeDataset(dataset.id);
|
|
341
|
-
}
|
|
342
|
-
watch(() => props.template, (template) => {
|
|
343
|
-
if (template) loadTemplate(template);
|
|
344
|
-
}, { immediate: true });
|
|
345
|
-
return {
|
|
346
|
-
workbook,
|
|
347
|
-
connections,
|
|
348
|
-
datasets,
|
|
349
|
-
catalog,
|
|
350
|
-
boundKeys,
|
|
351
|
-
activeCell,
|
|
352
|
-
selectionLabel,
|
|
353
|
-
activeBinding,
|
|
354
|
-
activeFieldType,
|
|
355
|
-
activeDatasetFields,
|
|
356
|
-
resolvedRowParentLabel,
|
|
357
|
-
resolvedColParentLabel,
|
|
358
|
-
parentPick,
|
|
359
|
-
rowParentCandidates,
|
|
360
|
-
colParentCandidates,
|
|
361
|
-
bindingEntries,
|
|
362
|
-
metaTick,
|
|
363
|
-
getBindingAt,
|
|
364
|
-
resolveFieldLabel,
|
|
365
|
-
bindField,
|
|
366
|
-
patchActiveBinding,
|
|
367
|
-
startParentPick,
|
|
368
|
-
cancelParentPick,
|
|
369
|
-
pickParentAt,
|
|
370
|
-
clearParent,
|
|
371
|
-
removeActiveBinding,
|
|
372
|
-
resolveCellStyle,
|
|
373
|
-
resolveCellRenderer,
|
|
374
|
-
getTemplate,
|
|
375
|
-
addConnection,
|
|
376
|
-
updateConnection,
|
|
377
|
-
removeConnection,
|
|
378
|
-
addDataset,
|
|
379
|
-
updateDataset,
|
|
380
|
-
removeDataset,
|
|
381
|
-
testConnection,
|
|
382
|
-
describeDataset,
|
|
383
|
-
previewDataset
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
//#endregion
|
|
387
|
-
export { useReportDesigner };
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { buildDrillHitMap, createDrillStack, currentDrillLayer, popDrillLayer, pushDrillLayer, resolveDrillParams } from "../../report/drill.js";
|
|
2
|
-
import { renderReport, resolveFilledColWidths } from "../../report/render/index.js";
|
|
3
|
-
import { fetchTemplateRecords, resolveParamDefaults, resolveTemplateParams } from "../../report/template.js";
|
|
4
|
-
import { computed, ref, shallowRef, watch } from "vue";
|
|
5
|
-
import { cellKey } from "@veltra/sheet-core";
|
|
6
|
-
//#region src/components/report/use-report-viewer.ts
|
|
7
|
-
/**
|
|
8
|
-
* UReportViewer 的 headless 编排:参数提取 → 取数 → renderReport 展开。
|
|
9
|
-
* 不持有 DOM / 网格引用;填充快照经 `filledSnapshot` 交给组件壳应用。
|
|
10
|
-
* 下钻:openMode 'switch' 栈式切换当前层;'dialog' 由组件壳解析目标后嵌套独立查看器。
|
|
11
|
-
* 导出 / 打印始终作用于当前可见层。
|
|
12
|
-
*/
|
|
13
|
-
function useReportViewer(props) {
|
|
14
|
-
const loading = ref(false);
|
|
15
|
-
const error = shallowRef(null);
|
|
16
|
-
const filledSnapshot = shallowRef(null);
|
|
17
|
-
const filledColWidths = shallowRef(void 0);
|
|
18
|
-
const drillStack = shallowRef(null);
|
|
19
|
-
const drillHits = shallowRef(/* @__PURE__ */ new Map());
|
|
20
|
-
const currentTemplate = computed(() => {
|
|
21
|
-
const stack = drillStack.value;
|
|
22
|
-
return stack ? currentDrillLayer(stack).template : props.template;
|
|
23
|
-
});
|
|
24
|
-
const drillDepth = computed(() => (drillStack.value?.length ?? 1) - 1);
|
|
25
|
-
const canDrillBack = computed(() => drillDepth.value > 0);
|
|
26
|
-
const params = computed(() => resolveTemplateParams(currentTemplate.value));
|
|
27
|
-
const values = shallowRef({});
|
|
28
|
-
let fetchSeq = 0;
|
|
29
|
-
async function refresh() {
|
|
30
|
-
const current = ++fetchSeq;
|
|
31
|
-
const template = currentTemplate.value;
|
|
32
|
-
loading.value = true;
|
|
33
|
-
error.value = null;
|
|
34
|
-
const result = await fetchTemplateRecords(props.connector, template, values.value);
|
|
35
|
-
if (current !== fetchSeq) return;
|
|
36
|
-
loading.value = false;
|
|
37
|
-
if (!result.ok) {
|
|
38
|
-
error.value = result.error;
|
|
39
|
-
filledColWidths.value = void 0;
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
filledSnapshot.value = renderReport(template, result.data);
|
|
43
|
-
filledColWidths.value = template.colWidths?.length ? resolveFilledColWidths(template, result.data, template.colWidths) : void 0;
|
|
44
|
-
drillHits.value = props.resolveTemplate ? buildDrillHitMap(template, result.data) : /* @__PURE__ */ new Map();
|
|
45
|
-
}
|
|
46
|
-
/** 切层共有收尾:清填充结果与命中索引,写入新层参数并重新取数 */
|
|
47
|
-
function transitionTo(layerParams) {
|
|
48
|
-
filledSnapshot.value = null;
|
|
49
|
-
filledColWidths.value = void 0;
|
|
50
|
-
drillHits.value = /* @__PURE__ */ new Map();
|
|
51
|
-
values.value = layerParams;
|
|
52
|
-
return refresh();
|
|
53
|
-
}
|
|
54
|
-
async function resolveDrillTarget(config, record) {
|
|
55
|
-
const resolve = props.resolveTemplate;
|
|
56
|
-
if (!resolve) return null;
|
|
57
|
-
let target;
|
|
58
|
-
try {
|
|
59
|
-
target = await resolve(config.target);
|
|
60
|
-
} catch (err) {
|
|
61
|
-
error.value = {
|
|
62
|
-
code: "DRILL_RESOLVE_FAILED",
|
|
63
|
-
message: err instanceof Error ? err.message : String(err)
|
|
64
|
-
};
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
if (!target) {
|
|
68
|
-
error.value = {
|
|
69
|
-
code: "DRILL_RESOLVE_FAILED",
|
|
70
|
-
message: `下钻目标模板解析失败:${config.target}`
|
|
71
|
-
};
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
error.value = null;
|
|
75
|
-
return {
|
|
76
|
-
template: target,
|
|
77
|
-
params: {
|
|
78
|
-
...resolveParamDefaults(resolveTemplateParams(target)),
|
|
79
|
-
...resolveDrillParams(config, record)
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
async function drillInto(config, record) {
|
|
84
|
-
const next = await resolveDrillTarget(config, record);
|
|
85
|
-
if (!next) return;
|
|
86
|
-
const base = drillStack.value ?? createDrillStack({
|
|
87
|
-
template: props.template,
|
|
88
|
-
params: values.value
|
|
89
|
-
});
|
|
90
|
-
drillStack.value = pushDrillLayer(base, {
|
|
91
|
-
template: next.template,
|
|
92
|
-
params: next.params
|
|
93
|
-
}, values.value);
|
|
94
|
-
await transitionTo(next.params);
|
|
95
|
-
}
|
|
96
|
-
async function drillBack() {
|
|
97
|
-
const stack = drillStack.value;
|
|
98
|
-
if (!stack || stack.length <= 1) return;
|
|
99
|
-
const next = popDrillLayer(stack);
|
|
100
|
-
drillStack.value = next;
|
|
101
|
-
await transitionTo({ ...currentDrillLayer(next).params });
|
|
102
|
-
}
|
|
103
|
-
function resolveDrillHit(addr) {
|
|
104
|
-
return drillHits.value.get(cellKey(addr)) ?? null;
|
|
105
|
-
}
|
|
106
|
-
function setValues(next) {
|
|
107
|
-
values.value = next;
|
|
108
|
-
refresh();
|
|
109
|
-
}
|
|
110
|
-
watch(() => props.template, () => {
|
|
111
|
-
drillStack.value = null;
|
|
112
|
-
drillHits.value = /* @__PURE__ */ new Map();
|
|
113
|
-
filledSnapshot.value = null;
|
|
114
|
-
filledColWidths.value = void 0;
|
|
115
|
-
values.value = {
|
|
116
|
-
...resolveParamDefaults(params.value),
|
|
117
|
-
...props.initialValues
|
|
118
|
-
};
|
|
119
|
-
refresh();
|
|
120
|
-
}, { immediate: true });
|
|
121
|
-
return {
|
|
122
|
-
params,
|
|
123
|
-
values,
|
|
124
|
-
loading,
|
|
125
|
-
error,
|
|
126
|
-
filledSnapshot,
|
|
127
|
-
filledColWidths,
|
|
128
|
-
currentTemplate,
|
|
129
|
-
drillDepth,
|
|
130
|
-
canDrillBack,
|
|
131
|
-
resolveDrillHit,
|
|
132
|
-
resolveDrillTarget,
|
|
133
|
-
drillInto,
|
|
134
|
-
drillBack,
|
|
135
|
-
refresh,
|
|
136
|
-
setValues
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
140
|
-
export { useReportViewer };
|
package/dist/report/binding.d.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { DatasetCatalogItem, ReportAggregate, ReportBinding, ReportPreset } from "./types.js";
|
|
2
|
-
import { CellAddress } from "@veltra/sheet-core";
|
|
3
|
-
//#region src/report/binding.d.ts
|
|
4
|
-
declare function setBindingCatalog(catalog: DatasetCatalogItem[]): void;
|
|
5
|
-
declare const REPORT_META_NAMESPACE = "report";
|
|
6
|
-
/** 预设 → 绑定字段补丁(父格除 grandTotal 外均保留推断值) */
|
|
7
|
-
declare function presetBindingPatch(preset: ReportPreset, options?: {
|
|
8
|
-
transpose?: boolean;
|
|
9
|
-
}): Partial<ReportBinding>;
|
|
10
|
-
/** 将预设写入绑定(grandTotal 清空双父格;其余保留既有父格) */
|
|
11
|
-
declare function applyReportPreset(binding: ReportBinding, preset: ReportPreset, options?: {
|
|
12
|
-
transpose?: boolean;
|
|
13
|
-
}): ReportBinding;
|
|
14
|
-
declare function isVerticalExpandBinding(binding: ReportBinding): boolean;
|
|
15
|
-
declare function isHorizontalExpandBinding(binding: ReportBinding): boolean;
|
|
16
|
-
declare function isRowGroupBinding(binding: ReportBinding): boolean;
|
|
17
|
-
declare function isColGroupBinding(binding: ReportBinding): boolean;
|
|
18
|
-
declare function isReductionAggregate(aggregate: ReportAggregate): boolean;
|
|
19
|
-
/** 小计 / 汇总 / 交叉格的父格候选只列分组头 */
|
|
20
|
-
declare function prefersGroupParent(binding: ReportBinding): boolean;
|
|
21
|
-
/** 当前 expand / aggregate 是否仍属于已写入的预设族(同族内改聚合不掉到「自定义」) */
|
|
22
|
-
declare function presetStillApplies(binding: ReportBinding): boolean;
|
|
23
|
-
type GetBindingAt = (addr: CellAddress) => ReportBinding | undefined;
|
|
24
|
-
interface InferParentOptions {
|
|
25
|
-
/** 小计落格:必须优先分组头,禁止把同列/同行明细当成父格 */
|
|
26
|
-
preferGroup?: boolean;
|
|
27
|
-
}
|
|
28
|
-
/** 指定模板行是否含纵向扩展绑定(展开带行) */
|
|
29
|
-
declare function isExpansionBandRow(row: number, getBindingAt: GetBindingAt, scanCols?: number): boolean;
|
|
30
|
-
/** 指定模板列是否含横向扩展绑定(展开带列) */
|
|
31
|
-
declare function isExpansionBandCol(col: number, getBindingAt: GetBindingAt, scanRows?: number): boolean;
|
|
32
|
-
/** 落格时推断预设:默认明细;数值字段且位于展开带正下方或正右相邻 → 小计 */
|
|
33
|
-
declare function inferDropPreset(addr: CellAddress, fieldType: DatasetCatalogItem['fields'][number]['type'], getBindingAt: GetBindingAt): ReportPreset;
|
|
34
|
-
interface ListParentCandidateOptions {
|
|
35
|
-
preferGroup?: boolean;
|
|
36
|
-
}
|
|
37
|
-
/** 同数据集纵向扩展绑定格(行方向父格下拉候选) */
|
|
38
|
-
declare function listRowParentCandidates(binding: ReportBinding, entries: ReadonlyArray<{
|
|
39
|
-
addr: CellAddress;
|
|
40
|
-
binding: ReportBinding;
|
|
41
|
-
}>, options?: ListParentCandidateOptions): CellAddress[];
|
|
42
|
-
/** 同数据集横向扩展绑定格(列方向父格下拉候选) */
|
|
43
|
-
declare function listColParentCandidates(binding: ReportBinding, entries: ReadonlyArray<{
|
|
44
|
-
addr: CellAddress;
|
|
45
|
-
binding: ReportBinding;
|
|
46
|
-
}>, options?: ListParentCandidateOptions): CellAddress[];
|
|
47
|
-
/**
|
|
48
|
-
* 行方向父格推断:
|
|
49
|
-
* 1. 同行向左:先找分组头,否则最近纵向扩展格
|
|
50
|
-
* 2. 上方各行整行扫描:每行先找分组头,再退回任意纵向扩展格
|
|
51
|
-
* 小计(preferGroup)禁止把明细当成父格
|
|
52
|
-
*/
|
|
53
|
-
declare function inferRowParentCandidate(addr: CellAddress, getBindingAt: GetBindingAt, options?: InferParentOptions): CellAddress | null;
|
|
54
|
-
/**
|
|
55
|
-
* 列方向父格推断(与行方向对称):
|
|
56
|
-
* 1. 同列向上:先找列分组头,否则最近横向扩展格
|
|
57
|
-
* 2. 左侧各列整列扫描:每列先找列分组头
|
|
58
|
-
* 列小计(preferGroup)禁止把交叉格/明细当成列父格
|
|
59
|
-
*/
|
|
60
|
-
declare function inferColParentCandidate(addr: CellAddress, getBindingAt: GetBindingAt, options?: InferParentOptions): CellAddress | null;
|
|
61
|
-
/**
|
|
62
|
-
* 按预设写入落格父格:明细/分组/交叉双方向推断;小计按「下方行小计 / 右侧列小计」只挂对应轴。
|
|
63
|
-
*/
|
|
64
|
-
declare function inferParentsForPreset(addr: CellAddress, preset: ReportPreset, getBindingAt: GetBindingAt): Pick<ReportBinding, 'rowParent' | 'colParent'>;
|
|
65
|
-
/** 从绑定字段推断预设;不匹配任何预设时返回 null(自定义) */
|
|
66
|
-
declare function inferReportPreset(binding: ReportBinding): ReportPreset | null;
|
|
67
|
-
/** 默认明细 + 纵向扩展 */
|
|
68
|
-
declare function createReportBinding(dataset: DatasetCatalogItem, fieldName: string): ReportBinding;
|
|
69
|
-
/** 设计地址 → A1 标签(支持多字母列) */
|
|
70
|
-
declare function formatCellAddress(addr: CellAddress): string;
|
|
71
|
-
/** A1 标签 → 设计地址;非法输入返回 null */
|
|
72
|
-
declare function parseCellAddress(label: string): CellAddress | null;
|
|
73
|
-
/** Binding Placeholder 分段文案(聚合标签 + 字段标签),供徽章分色渲染等场景使用 */
|
|
74
|
-
declare function formatBindingPlaceholderParts(binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): {
|
|
75
|
-
tag: string;
|
|
76
|
-
label: string;
|
|
77
|
-
};
|
|
78
|
-
/** Binding Placeholder 中文可读文案(如「分组 · 客户」) */
|
|
79
|
-
declare function formatBindingPlaceholder(binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): string;
|
|
80
|
-
/** 父格下拉候选文案(如「分组 · 客户 (A2)」) */
|
|
81
|
-
declare function formatParentCandidateLabel(addr: CellAddress, binding: ReportBinding, resolveLabel?: (datasetId: string, fieldName: string) => string): string;
|
|
82
|
-
//#endregion
|
|
83
|
-
export { 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 };
|