@veltra/sheet 2.3.4 → 2.4.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.
- package/dist/components/report/binding-badge.js +6 -0
- package/dist/components/report/designer/drill-dialog.js +258 -0
- package/dist/components/report/designer/float-panel.js +26 -14
- package/dist/components/report/print.js +39 -0
- package/dist/components/report/report-designer.js +56 -21
- package/dist/components/report/report-viewer.js +173 -44
- package/dist/components/report/style2.css +91 -0
- package/dist/components/report/use-report-designer.js +1 -0
- package/dist/components/report/use-report-viewer.js +88 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/report/drill.d.ts +48 -0
- package/dist/report/drill.js +78 -0
- package/dist/report/index.d.ts +4 -2
- package/dist/report/print.d.ts +23 -0
- package/dist/report/print.js +197 -0
- package/dist/report/render/aggregate.js +25 -1
- package/dist/report/types.d.ts +19 -1
- package/dist/types/report-designer.d.ts +13 -0
- package/dist/types/report-viewer.d.ts +19 -0
- package/package.json +6 -6
- package/src/components/report/__test__/report-designer.test.ts +98 -3
- package/src/components/report/__test__/report-drill.test.ts +692 -0
- package/src/components/report/__test__/report-viewer.test.ts +43 -0
- package/src/components/report/__test__/use-report-designer.test.ts +108 -1
- package/src/components/report/binding-badge.ts +5 -0
- package/src/components/report/designer/drill-dialog.vue +245 -0
- package/src/components/report/designer/float-panel.vue +12 -0
- package/src/components/report/print.ts +44 -0
- package/src/components/report/report-designer.vue +35 -2
- package/src/components/report/report-viewer.vue +171 -18
- package/src/components/report/style-designer.scss +66 -0
- package/src/components/report/style-viewer.scss +40 -0
- package/src/components/report/use-report-designer.ts +1 -0
- package/src/components/report/use-report-viewer.ts +150 -11
- package/src/report/__test__/drill.test.ts +194 -0
- package/src/report/__test__/print.test.ts +170 -0
- package/src/report/drill.ts +112 -0
- package/src/report/index.ts +4 -1
- package/src/report/print.ts +234 -0
- package/src/report/render/aggregate.ts +28 -0
- package/src/report/types.ts +20 -0
- package/src/types/report-designer.ts +18 -1
- package/src/types/report-viewer.ts +18 -1
|
@@ -102,6 +102,12 @@ function createBindingBadgeRenderer(getBindingAt, resolveLabel, resolveAlign) {
|
|
|
102
102
|
fontWeight: 500,
|
|
103
103
|
fill: BADGE_LABEL_COLOR
|
|
104
104
|
}));
|
|
105
|
+
if (binding.drill) rootContainer.add(new CustomLayout.Text({
|
|
106
|
+
text: " ↗",
|
|
107
|
+
fontSize: 11,
|
|
108
|
+
fontWeight: 700,
|
|
109
|
+
fill: fg
|
|
110
|
+
}));
|
|
105
111
|
return {
|
|
106
112
|
rootContainer,
|
|
107
113
|
renderDefault: false
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { resolveTemplateParams } from "../../../report/template.js";
|
|
2
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, watch, withCtx } from "vue";
|
|
3
|
+
import { UButton, UDialog, URadioGroup, USelect } from "@veltra/desktop";
|
|
4
|
+
import { bem } from "@veltra/utils";
|
|
5
|
+
//#region src/components/report/designer/drill-dialog.vue
|
|
6
|
+
const _hoisted_1 = { key: 2 };
|
|
7
|
+
const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
8
|
+
name: "UReportDrillDialog",
|
|
9
|
+
__name: "drill-dialog",
|
|
10
|
+
props: {
|
|
11
|
+
modelValue: { type: Boolean },
|
|
12
|
+
templates: {},
|
|
13
|
+
fields: { default: () => [] },
|
|
14
|
+
drill: { default: void 0 },
|
|
15
|
+
resolveTemplate: {
|
|
16
|
+
type: Function,
|
|
17
|
+
default: void 0
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
emits: [
|
|
21
|
+
"update:modelValue",
|
|
22
|
+
"save",
|
|
23
|
+
"remove"
|
|
24
|
+
],
|
|
25
|
+
setup(__props, { emit: __emit }) {
|
|
26
|
+
/** 映射编辑行草稿(保存时折叠为 Record<字段, 参数>) */
|
|
27
|
+
const props = __props;
|
|
28
|
+
const emit = __emit;
|
|
29
|
+
const cls = bem("report-drill-dialog");
|
|
30
|
+
const visible = computed({
|
|
31
|
+
get: () => props.modelValue,
|
|
32
|
+
set: (value) => emit("update:modelValue", value)
|
|
33
|
+
});
|
|
34
|
+
const openModeItems = [{
|
|
35
|
+
value: "switch",
|
|
36
|
+
label: "查看器内切换"
|
|
37
|
+
}, {
|
|
38
|
+
value: "dialog",
|
|
39
|
+
label: "弹框打开(UDialog)"
|
|
40
|
+
}];
|
|
41
|
+
const target = ref("");
|
|
42
|
+
const openMode = ref("switch");
|
|
43
|
+
const mappings = ref([]);
|
|
44
|
+
watch(() => props.modelValue, (open) => {
|
|
45
|
+
if (!open) return;
|
|
46
|
+
target.value = props.drill?.target ?? "";
|
|
47
|
+
openMode.value = props.drill?.openMode ?? "switch";
|
|
48
|
+
mappings.value = Object.entries(props.drill?.mapping ?? {}).map(([field, param]) => ({
|
|
49
|
+
field,
|
|
50
|
+
param
|
|
51
|
+
}));
|
|
52
|
+
resolveTargetParams(target.value);
|
|
53
|
+
});
|
|
54
|
+
const targetParams = ref([]);
|
|
55
|
+
const paramsLoading = ref(false);
|
|
56
|
+
const paramsError = ref("");
|
|
57
|
+
let paramsSeq = 0;
|
|
58
|
+
async function resolveTargetParams(ref) {
|
|
59
|
+
const seq = ++paramsSeq;
|
|
60
|
+
targetParams.value = [];
|
|
61
|
+
paramsError.value = "";
|
|
62
|
+
if (!ref) return;
|
|
63
|
+
const resolve = props.resolveTemplate;
|
|
64
|
+
if (!resolve) {
|
|
65
|
+
paramsError.value = "宿主未提供 resolveTemplate,无法解析目标模板参数";
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
paramsLoading.value = true;
|
|
69
|
+
try {
|
|
70
|
+
const template = await resolve(ref);
|
|
71
|
+
if (seq !== paramsSeq) return;
|
|
72
|
+
targetParams.value = resolveTemplateParams(template);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (seq !== paramsSeq) return;
|
|
75
|
+
paramsError.value = `解析目标模板参数失败:${error instanceof Error ? error.message : String(error)}`;
|
|
76
|
+
} finally {
|
|
77
|
+
if (seq === paramsSeq) paramsLoading.value = false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const templateOptions = computed(() => props.templates.map((item) => ({
|
|
81
|
+
value: item.ref,
|
|
82
|
+
label: item.label
|
|
83
|
+
})));
|
|
84
|
+
const fieldOptions = computed(() => props.fields.map((field) => ({
|
|
85
|
+
value: field.name,
|
|
86
|
+
label: field.label
|
|
87
|
+
})));
|
|
88
|
+
const paramOptions = computed(() => targetParams.value.map((param) => ({
|
|
89
|
+
value: param.id,
|
|
90
|
+
label: param.label && param.label !== param.id ? `${param.label}(${param.id})` : param.id
|
|
91
|
+
})));
|
|
92
|
+
/** 用户改选目标:旧映射的参数 id 未必存在于新模板,直接清空重配 */
|
|
93
|
+
function onTarget(value) {
|
|
94
|
+
target.value = value ?? "";
|
|
95
|
+
mappings.value = [];
|
|
96
|
+
resolveTargetParams(target.value);
|
|
97
|
+
}
|
|
98
|
+
function onOpenMode(value) {
|
|
99
|
+
openMode.value = value;
|
|
100
|
+
}
|
|
101
|
+
function addMapping() {
|
|
102
|
+
mappings.value = [...mappings.value, {
|
|
103
|
+
field: "",
|
|
104
|
+
param: ""
|
|
105
|
+
}];
|
|
106
|
+
}
|
|
107
|
+
function removeMapping(index) {
|
|
108
|
+
mappings.value = mappings.value.filter((_, i) => i !== index);
|
|
109
|
+
}
|
|
110
|
+
function confirm() {
|
|
111
|
+
if (!target.value) return;
|
|
112
|
+
const mapping = {};
|
|
113
|
+
for (const row of mappings.value) if (row.field && row.param) mapping[row.field] = row.param;
|
|
114
|
+
emit("save", {
|
|
115
|
+
target: target.value,
|
|
116
|
+
mapping,
|
|
117
|
+
openMode: openMode.value
|
|
118
|
+
});
|
|
119
|
+
visible.value = false;
|
|
120
|
+
}
|
|
121
|
+
function remove() {
|
|
122
|
+
emit("remove");
|
|
123
|
+
visible.value = false;
|
|
124
|
+
}
|
|
125
|
+
function onClose() {
|
|
126
|
+
visible.value = false;
|
|
127
|
+
}
|
|
128
|
+
return (_ctx, _cache) => {
|
|
129
|
+
return openBlock(), createBlock(unref(UDialog), {
|
|
130
|
+
modelValue: visible.value,
|
|
131
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => visible.value = $event),
|
|
132
|
+
title: "下钻配置",
|
|
133
|
+
style: {
|
|
134
|
+
"width": "min(560px, 92vw)",
|
|
135
|
+
"max-height": "85vh"
|
|
136
|
+
},
|
|
137
|
+
onClose
|
|
138
|
+
}, {
|
|
139
|
+
footer: withCtx(() => [
|
|
140
|
+
__props.drill ? (openBlock(), createBlock(unref(UButton), {
|
|
141
|
+
key: 0,
|
|
142
|
+
size: "small",
|
|
143
|
+
text: "",
|
|
144
|
+
type: "danger",
|
|
145
|
+
style: { "margin-right": "auto" },
|
|
146
|
+
onClick: remove
|
|
147
|
+
}, {
|
|
148
|
+
default: withCtx(() => [..._cache[4] || (_cache[4] = [createTextVNode(" 移除下钻 ", -1)])]),
|
|
149
|
+
_: 1
|
|
150
|
+
})) : createCommentVNode("v-if", true),
|
|
151
|
+
createVNode(unref(UButton), {
|
|
152
|
+
size: "small",
|
|
153
|
+
onClick: _cache[0] || (_cache[0] = ($event) => visible.value = false)
|
|
154
|
+
}, {
|
|
155
|
+
default: withCtx(() => [..._cache[5] || (_cache[5] = [createTextVNode("取消", -1)])]),
|
|
156
|
+
_: 1
|
|
157
|
+
}),
|
|
158
|
+
createVNode(unref(UButton), {
|
|
159
|
+
size: "small",
|
|
160
|
+
type: "primary",
|
|
161
|
+
disabled: !target.value,
|
|
162
|
+
onClick: confirm
|
|
163
|
+
}, {
|
|
164
|
+
default: withCtx(() => [..._cache[6] || (_cache[6] = [createTextVNode("确定", -1)])]),
|
|
165
|
+
_: 1
|
|
166
|
+
}, 8, ["disabled"])
|
|
167
|
+
]),
|
|
168
|
+
default: withCtx(() => [createElementVNode("div", { class: normalizeClass(unref(cls).b) }, [
|
|
169
|
+
createElementVNode("section", { class: normalizeClass(unref(cls).e("section")) }, [
|
|
170
|
+
createElementVNode("div", { class: normalizeClass(unref(cls).e("label")) }, "目标模板", 2),
|
|
171
|
+
createVNode(unref(USelect), {
|
|
172
|
+
size: "small",
|
|
173
|
+
placeholder: "从模板列表选择目标",
|
|
174
|
+
"model-value": target.value,
|
|
175
|
+
options: templateOptions.value,
|
|
176
|
+
"onUpdate:modelValue": onTarget
|
|
177
|
+
}, null, 8, ["model-value", "options"]),
|
|
178
|
+
createElementVNode("p", { class: normalizeClass(unref(cls).e("hint")) }, "目标模板仅从宿主提供的列表选择,不支持手填引用。", 2)
|
|
179
|
+
], 2),
|
|
180
|
+
createElementVNode("section", { class: normalizeClass(unref(cls).e("section")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("label")) }, "打开方式", 2), createVNode(unref(URadioGroup), {
|
|
181
|
+
size: "small",
|
|
182
|
+
items: openModeItems,
|
|
183
|
+
"model-value": openMode.value,
|
|
184
|
+
"onUpdate:modelValue": onOpenMode
|
|
185
|
+
}, null, 8, ["model-value"])], 2),
|
|
186
|
+
createElementVNode("section", { class: normalizeClass(unref(cls).e("section")) }, [createElementVNode("div", { class: normalizeClass(unref(cls).e("label")) }, "字段 → 详情报参数映射", 2), !target.value ? (openBlock(), createElementBlock("p", {
|
|
187
|
+
key: 0,
|
|
188
|
+
class: normalizeClass(unref(cls).e("hint"))
|
|
189
|
+
}, "先选择目标模板,再配置映射。", 2)) : paramsLoading.value ? (openBlock(), createElementBlock("p", {
|
|
190
|
+
key: 1,
|
|
191
|
+
class: normalizeClass(unref(cls).e("hint"))
|
|
192
|
+
}, "正在解析目标模板参数…", 2)) : paramsError.value ? (openBlock(), createElementBlock("p", {
|
|
193
|
+
key: 2,
|
|
194
|
+
class: normalizeClass(unref(cls).e("error"))
|
|
195
|
+
}, toDisplayString(paramsError.value), 3)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [targetParams.value.length === 0 ? (openBlock(), createElementBlock("p", {
|
|
196
|
+
key: 0,
|
|
197
|
+
class: normalizeClass(unref(cls).e("hint"))
|
|
198
|
+
}, " 目标模板没有查询参数,无需配置映射。 ", 2)) : (openBlock(), createElementBlock("ul", {
|
|
199
|
+
key: 1,
|
|
200
|
+
class: normalizeClass(unref(cls).e("list"))
|
|
201
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(mappings.value, (row, index) => {
|
|
202
|
+
return openBlock(), createElementBlock("li", {
|
|
203
|
+
key: index,
|
|
204
|
+
class: normalizeClass(unref(cls).e("mapping"))
|
|
205
|
+
}, [
|
|
206
|
+
createVNode(unref(USelect), {
|
|
207
|
+
size: "small",
|
|
208
|
+
class: normalizeClass(unref(cls).e("field")),
|
|
209
|
+
placeholder: "字段",
|
|
210
|
+
"model-value": row.field,
|
|
211
|
+
options: fieldOptions.value,
|
|
212
|
+
"onUpdate:modelValue": ($event) => row.field = $event
|
|
213
|
+
}, null, 8, [
|
|
214
|
+
"class",
|
|
215
|
+
"model-value",
|
|
216
|
+
"options",
|
|
217
|
+
"onUpdate:modelValue"
|
|
218
|
+
]),
|
|
219
|
+
createElementVNode("span", { class: normalizeClass(unref(cls).e("arrow")) }, "→", 2),
|
|
220
|
+
createVNode(unref(USelect), {
|
|
221
|
+
size: "small",
|
|
222
|
+
class: normalizeClass(unref(cls).e("param")),
|
|
223
|
+
placeholder: "参数",
|
|
224
|
+
"model-value": row.param,
|
|
225
|
+
options: paramOptions.value,
|
|
226
|
+
"onUpdate:modelValue": ($event) => row.param = $event
|
|
227
|
+
}, null, 8, [
|
|
228
|
+
"class",
|
|
229
|
+
"model-value",
|
|
230
|
+
"options",
|
|
231
|
+
"onUpdate:modelValue"
|
|
232
|
+
]),
|
|
233
|
+
createVNode(unref(UButton), {
|
|
234
|
+
size: "small",
|
|
235
|
+
text: "",
|
|
236
|
+
type: "danger",
|
|
237
|
+
onClick: ($event) => removeMapping(index)
|
|
238
|
+
}, {
|
|
239
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode(" 删除 ", -1)])]),
|
|
240
|
+
_: 1
|
|
241
|
+
}, 8, ["onClick"])
|
|
242
|
+
], 2);
|
|
243
|
+
}), 128))], 2)), targetParams.value.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(UButton), {
|
|
244
|
+
size: "small",
|
|
245
|
+
plain: "",
|
|
246
|
+
onClick: addMapping
|
|
247
|
+
}, {
|
|
248
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode("添加映射", -1)])]),
|
|
249
|
+
_: 1
|
|
250
|
+
})])) : createCommentVNode("v-if", true)], 64))], 2)
|
|
251
|
+
], 2)]),
|
|
252
|
+
_: 1
|
|
253
|
+
}, 8, ["modelValue"]);
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
//#endregion
|
|
258
|
+
export { _sfc_main as default };
|
|
@@ -19,6 +19,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
19
19
|
parentPickMode: {},
|
|
20
20
|
rowParentCandidates: {},
|
|
21
21
|
colParentCandidates: {},
|
|
22
|
+
showDrill: { type: Boolean },
|
|
22
23
|
resolveFieldLabel: { type: Function },
|
|
23
24
|
getBindingAt: { type: Function },
|
|
24
25
|
hostEl: {},
|
|
@@ -28,6 +29,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
28
29
|
"patch",
|
|
29
30
|
"remove",
|
|
30
31
|
"open-rules",
|
|
32
|
+
"open-drill",
|
|
31
33
|
"start-parent-pick",
|
|
32
34
|
"cancel-parent-pick",
|
|
33
35
|
"clear-parent"
|
|
@@ -247,8 +249,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
247
249
|
expanded.value ? unref(cls).m("expanded") : ""
|
|
248
250
|
]),
|
|
249
251
|
style: normalizeStyle(panelStyle.value),
|
|
250
|
-
onMousedown: _cache[
|
|
251
|
-
onPointerdown: _cache[
|
|
252
|
+
onMousedown: _cache[9] || (_cache[9] = withModifiers(() => {}, ["stop"])),
|
|
253
|
+
onPointerdown: _cache[10] || (_cache[10] = withModifiers(() => {}, ["stop"]))
|
|
252
254
|
}, [createElementVNode("div", { class: normalizeClass(unref(cls).e("bar")) }, [createElementVNode("div", {
|
|
253
255
|
class: normalizeClass(unref(cls).e("summary")),
|
|
254
256
|
title: summaryText.value
|
|
@@ -289,16 +291,26 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
289
291
|
plain: "",
|
|
290
292
|
onClick: _cache[0] || (_cache[0] = ($event) => emit("open-rules"))
|
|
291
293
|
}, {
|
|
292
|
-
default: withCtx(() => [..._cache[
|
|
294
|
+
default: withCtx(() => [..._cache[11] || (_cache[11] = [createTextVNode("条件样式", -1)])]),
|
|
293
295
|
_: 1
|
|
294
296
|
}),
|
|
297
|
+
__props.showDrill ? (openBlock(), createBlock(unref(UButton), {
|
|
298
|
+
key: 2,
|
|
299
|
+
size: "small",
|
|
300
|
+
plain: "",
|
|
301
|
+
type: __props.binding.drill ? "primary" : void 0,
|
|
302
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("open-drill"))
|
|
303
|
+
}, {
|
|
304
|
+
default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" 下钻 ", -1)])]),
|
|
305
|
+
_: 1
|
|
306
|
+
}, 8, ["type"])) : createCommentVNode("v-if", true),
|
|
295
307
|
createVNode(unref(UButton), {
|
|
296
308
|
size: "small",
|
|
297
309
|
text: "",
|
|
298
310
|
type: "danger",
|
|
299
|
-
onClick: _cache[
|
|
311
|
+
onClick: _cache[2] || (_cache[2] = ($event) => emit("remove"))
|
|
300
312
|
}, {
|
|
301
|
-
default: withCtx(() => [..._cache[
|
|
313
|
+
default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode("删除绑定", -1)])]),
|
|
302
314
|
_: 1
|
|
303
315
|
}),
|
|
304
316
|
createVNode(unref(UButton), {
|
|
@@ -306,7 +318,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
306
318
|
text: "",
|
|
307
319
|
class: normalizeClass(unref(cls).e("expand")),
|
|
308
320
|
title: expanded.value ? "收起" : "展开更多",
|
|
309
|
-
onClick: _cache[
|
|
321
|
+
onClick: _cache[3] || (_cache[3] = ($event) => expanded.value = !expanded.value)
|
|
310
322
|
}, {
|
|
311
323
|
default: withCtx(() => [createTextVNode(toDisplayString(expanded.value ? "收起" : "展开"), 1)]),
|
|
312
324
|
_: 1
|
|
@@ -335,7 +347,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
335
347
|
size: "small",
|
|
336
348
|
plain: "",
|
|
337
349
|
type: __props.parentPickMode === "row" ? "primary" : void 0,
|
|
338
|
-
onClick: _cache[
|
|
350
|
+
onClick: _cache[4] || (_cache[4] = ($event) => emit("start-parent-pick", "row"))
|
|
339
351
|
}, {
|
|
340
352
|
default: withCtx(() => [createTextVNode(toDisplayString(__props.parentPickMode === "row" ? "点选目标格…" : "设置行方向父格"), 1)]),
|
|
341
353
|
_: 1
|
|
@@ -358,9 +370,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
358
370
|
size: "small",
|
|
359
371
|
text: "",
|
|
360
372
|
type: "danger",
|
|
361
|
-
onClick: _cache[
|
|
373
|
+
onClick: _cache[5] || (_cache[5] = ($event) => emit("clear-parent", "row"))
|
|
362
374
|
}, {
|
|
363
|
-
default: withCtx(() => [..._cache[
|
|
375
|
+
default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" 清除 ", -1)])]),
|
|
364
376
|
_: 1
|
|
365
377
|
})) : createCommentVNode("v-if", true)
|
|
366
378
|
], 2)
|
|
@@ -373,7 +385,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
373
385
|
size: "small",
|
|
374
386
|
plain: "",
|
|
375
387
|
type: __props.parentPickMode === "col" ? "primary" : void 0,
|
|
376
|
-
onClick: _cache[
|
|
388
|
+
onClick: _cache[6] || (_cache[6] = ($event) => emit("start-parent-pick", "col"))
|
|
377
389
|
}, {
|
|
378
390
|
default: withCtx(() => [createTextVNode(toDisplayString(__props.parentPickMode === "col" ? "点选目标格…" : "设置列方向父格"), 1)]),
|
|
379
391
|
_: 1
|
|
@@ -396,9 +408,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
396
408
|
size: "small",
|
|
397
409
|
text: "",
|
|
398
410
|
type: "danger",
|
|
399
|
-
onClick: _cache[
|
|
411
|
+
onClick: _cache[7] || (_cache[7] = ($event) => emit("clear-parent", "col"))
|
|
400
412
|
}, {
|
|
401
|
-
default: withCtx(() => [..._cache[
|
|
413
|
+
default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" 清除 ", -1)])]),
|
|
402
414
|
_: 1
|
|
403
415
|
})) : createCommentVNode("v-if", true)
|
|
404
416
|
], 2)
|
|
@@ -409,9 +421,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
409
421
|
}, [createVNode(unref(UButton), {
|
|
410
422
|
size: "small",
|
|
411
423
|
plain: "",
|
|
412
|
-
onClick: _cache[
|
|
424
|
+
onClick: _cache[8] || (_cache[8] = ($event) => emit("cancel-parent-pick"))
|
|
413
425
|
}, {
|
|
414
|
-
default: withCtx(() => [..._cache[
|
|
426
|
+
default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode("取消点选", -1)])]),
|
|
415
427
|
_: 1
|
|
416
428
|
})], 2)) : createCommentVNode("v-if", true)
|
|
417
429
|
], 2)) : createCommentVNode("v-if", true)], 38)), [[vShow, visible.value]]) : createCommentVNode("v-if", true);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/components/report/print.ts
|
|
2
|
+
/**
|
|
3
|
+
* 打印 HTML 文档:隐藏 iframe 装载后调起浏览器打印,结束(或兜底超时)销毁。
|
|
4
|
+
*
|
|
5
|
+
* 路线取舍:相对 `window.open` 不被弹窗拦截;相对 `@media print` 直打宿主页,
|
|
6
|
+
* 不侵入应用布局,也不受网格 canvas 虚拟滚动(只绘制视口)限制。
|
|
7
|
+
* iframe 用 0×0 定位隐藏而非 `display:none`(部分浏览器不打印 none 的 iframe)。
|
|
8
|
+
*/
|
|
9
|
+
function printHtmlDocument(html) {
|
|
10
|
+
const iframe = document.createElement("iframe");
|
|
11
|
+
iframe.setAttribute("aria-hidden", "true");
|
|
12
|
+
iframe.style.cssText = "position:fixed;right:0;bottom:0;width:0;height:0;border:0;";
|
|
13
|
+
document.body.appendChild(iframe);
|
|
14
|
+
const win = iframe.contentWindow;
|
|
15
|
+
const doc = iframe.contentDocument;
|
|
16
|
+
if (!win || !doc || typeof win.print !== "function") {
|
|
17
|
+
iframe.remove();
|
|
18
|
+
throw new Error("当前环境不支持打印");
|
|
19
|
+
}
|
|
20
|
+
let cleaned = false;
|
|
21
|
+
const cleanup = () => {
|
|
22
|
+
if (cleaned) return;
|
|
23
|
+
cleaned = true;
|
|
24
|
+
iframe.remove();
|
|
25
|
+
};
|
|
26
|
+
win.addEventListener("afterprint", cleanup);
|
|
27
|
+
doc.open();
|
|
28
|
+
doc.write(html);
|
|
29
|
+
doc.close();
|
|
30
|
+
const decoding = Array.from(doc.images).map((img) => typeof img.decode === "function" ? img.decode().catch(() => void 0) : Promise.resolve());
|
|
31
|
+
Promise.all(decoding).then(() => {
|
|
32
|
+
if (cleaned) return;
|
|
33
|
+
win.focus();
|
|
34
|
+
win.print();
|
|
35
|
+
setTimeout(cleanup, 6e4);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { printHtmlDocument };
|
|
@@ -3,12 +3,13 @@ import { applyGridColWidths, applySheetColWidths, readGridColWidths } from "./de
|
|
|
3
3
|
import _sfc_main$2 from "./report-viewer.js";
|
|
4
4
|
import _sfc_main$3 from "./designer-hub.js";
|
|
5
5
|
import { resolveGridDropAddress } from "./designer/cell-coords.js";
|
|
6
|
-
import _sfc_main$4 from "./designer/
|
|
7
|
-
import _sfc_main$5 from "./designer/
|
|
8
|
-
import _sfc_main$6 from "./designer/
|
|
9
|
-
import _sfc_main$7 from "./designer/
|
|
6
|
+
import _sfc_main$4 from "./designer/drill-dialog.js";
|
|
7
|
+
import _sfc_main$5 from "./designer/drop-highlight-overlay.js";
|
|
8
|
+
import _sfc_main$6 from "./designer/float-panel.js";
|
|
9
|
+
import _sfc_main$7 from "./designer/rules-dialog.js";
|
|
10
|
+
import _sfc_main$8 from "./designer/topology-overlay.js";
|
|
10
11
|
import { FIELD_DRAG_MIME, parseFieldDragPayload } from "./field-panel-helpers.js";
|
|
11
|
-
import _sfc_main$
|
|
12
|
+
import _sfc_main$9 from "./field-panel.js";
|
|
12
13
|
import { useReportDesigner } from "./use-report-designer.js";
|
|
13
14
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, onScopeDispose, openBlock, ref, renderList, shallowRef, toDisplayString, unref, useTemplateRef, watch, withCtx } from "vue";
|
|
14
15
|
import { UButton, UDrawer } from "@veltra/desktop";
|
|
@@ -24,10 +25,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
24
25
|
connector: {},
|
|
25
26
|
connections: { default: () => [] },
|
|
26
27
|
template: {},
|
|
27
|
-
workbook: {}
|
|
28
|
+
workbook: {},
|
|
29
|
+
drillTemplates: {},
|
|
30
|
+
resolveTemplate: {}
|
|
28
31
|
},
|
|
29
32
|
emits: ["update:connections", "datasets-change"],
|
|
30
33
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
34
|
+
/** 与 `ReportDesignerProps` 交叉显式列出下钻 props,避免 SFC 对跨文件 interface 漏抽 runtime 声明 */
|
|
31
35
|
const props = __props;
|
|
32
36
|
const emit = __emit;
|
|
33
37
|
const cls = bem("report-designer");
|
|
@@ -54,6 +58,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
54
58
|
});
|
|
55
59
|
const hubVisible = ref(false);
|
|
56
60
|
const rulesDialogVisible = ref(false);
|
|
61
|
+
const drillDialogVisible = ref(false);
|
|
62
|
+
/** 宿主传入可下钻模板列表时才出现下钻配置入口(不传则无入口,spec 兼容性要求) */
|
|
63
|
+
const hasDrillTemplates = computed(() => (props.drillTemplates?.length ?? 0) > 0);
|
|
57
64
|
const pickCandidateCells = computed(() => {
|
|
58
65
|
if (!parentPick.value) return [];
|
|
59
66
|
return parentPick.value.mode === "row" ? rowParentCandidates.value : colParentCandidates.value;
|
|
@@ -138,6 +145,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
138
145
|
function saveConditionalRules(rules) {
|
|
139
146
|
patchActiveBinding({ conditionalRules: rules });
|
|
140
147
|
}
|
|
148
|
+
function saveDrill(drill) {
|
|
149
|
+
patchActiveBinding({ drill });
|
|
150
|
+
}
|
|
151
|
+
function removeDrill() {
|
|
152
|
+
patchActiveBinding({ drill: void 0 });
|
|
153
|
+
}
|
|
141
154
|
function clearDropState() {
|
|
142
155
|
isFieldDragging.value = false;
|
|
143
156
|
dropTargetAddr.value = null;
|
|
@@ -188,7 +201,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
188
201
|
plain: "",
|
|
189
202
|
onClick: _cache[0] || (_cache[0] = ($event) => hubVisible.value = true)
|
|
190
203
|
}, {
|
|
191
|
-
default: withCtx(() => [..._cache[
|
|
204
|
+
default: withCtx(() => [..._cache[8] || (_cache[8] = [createTextVNode("数据中枢", -1)])]),
|
|
192
205
|
_: 1
|
|
193
206
|
}),
|
|
194
207
|
createElementVNode("div", {
|
|
@@ -201,7 +214,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
201
214
|
plain: isPreview.value,
|
|
202
215
|
onClick: _cache[1] || (_cache[1] = ($event) => setViewMode("design"))
|
|
203
216
|
}, {
|
|
204
|
-
default: withCtx(() => [..._cache[
|
|
217
|
+
default: withCtx(() => [..._cache[9] || (_cache[9] = [createTextVNode(" 设计模式 ", -1)])]),
|
|
205
218
|
_: 1
|
|
206
219
|
}, 8, ["type", "plain"]), createVNode(unref(UButton), {
|
|
207
220
|
size: "small",
|
|
@@ -209,7 +222,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
209
222
|
plain: !isPreview.value,
|
|
210
223
|
onClick: _cache[2] || (_cache[2] = ($event) => setViewMode("preview"))
|
|
211
224
|
}, {
|
|
212
|
-
default: withCtx(() => [..._cache[
|
|
225
|
+
default: withCtx(() => [..._cache[10] || (_cache[10] = [createTextVNode(" 预览模式 ", -1)])]),
|
|
213
226
|
_: 1
|
|
214
227
|
}, 8, ["type", "plain"])], 2),
|
|
215
228
|
isPreview.value ? (openBlock(), createBlock(unref(UButton), {
|
|
@@ -220,7 +233,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
220
233
|
loading: exporting.value,
|
|
221
234
|
onClick: exportPreviewXlsx
|
|
222
235
|
}, {
|
|
223
|
-
default: withCtx(() => [..._cache[
|
|
236
|
+
default: withCtx(() => [..._cache[11] || (_cache[11] = [createTextVNode(" 导出 XLSX ", -1)])]),
|
|
224
237
|
_: 1
|
|
225
238
|
}, 8, ["loading"])) : createCommentVNode("v-if", true),
|
|
226
239
|
createElementVNode("span", { class: normalizeClass(unref(cls).e("hint")) }, " 在数据中枢配置连接与 SQL 数据集,再将左侧字段点击或拖拽到单元格完成绑定;选中已绑定格可通过悬浮卡片调整预设与条件样式。 ", 2)
|
|
@@ -228,7 +241,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
228
241
|
!isPreview.value ? (openBlock(), createElementBlock("div", {
|
|
229
242
|
key: 0,
|
|
230
243
|
class: normalizeClass(unref(cls).e("body"))
|
|
231
|
-
}, [createVNode(_sfc_main$
|
|
244
|
+
}, [createVNode(_sfc_main$9, {
|
|
232
245
|
class: normalizeClass(unref(cls).e("field-panel")),
|
|
233
246
|
datasets: unref(catalog),
|
|
234
247
|
"selection-label": unref(selectionLabel),
|
|
@@ -266,7 +279,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
266
279
|
"resolve-cell-style",
|
|
267
280
|
"resolve-cell-renderer"
|
|
268
281
|
]),
|
|
269
|
-
createVNode(_sfc_main$
|
|
282
|
+
createVNode(_sfc_main$8, {
|
|
270
283
|
cell: unref(activeCell),
|
|
271
284
|
binding: unref(activeBinding) ?? null,
|
|
272
285
|
entries: unref(bindingEntries),
|
|
@@ -282,7 +295,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
282
295
|
"host-el",
|
|
283
296
|
"get-binding-at"
|
|
284
297
|
]),
|
|
285
|
-
createVNode(_sfc_main$
|
|
298
|
+
createVNode(_sfc_main$5, {
|
|
286
299
|
cell: dropTargetAddr.value,
|
|
287
300
|
"host-el": gridHostEl.value,
|
|
288
301
|
"get-grid": getDesignGrid,
|
|
@@ -295,7 +308,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
295
308
|
"fallback-label"
|
|
296
309
|
]),
|
|
297
310
|
(openBlock(true), createElementBlock(Fragment, null, renderList(pickCandidateCells.value, (addr) => {
|
|
298
|
-
return openBlock(), createBlock(_sfc_main$
|
|
311
|
+
return openBlock(), createBlock(_sfc_main$5, {
|
|
299
312
|
key: `pick-${addr.row}-${addr.col}`,
|
|
300
313
|
cell: addr,
|
|
301
314
|
"host-el": gridHostEl.value,
|
|
@@ -309,7 +322,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
309
322
|
class: normalizeClass(unref(cls).e("pick-hint")),
|
|
310
323
|
role: "status"
|
|
311
324
|
}, toDisplayString(unref(parentPick).mode === "row" ? "点击分组头作为行方向父格" : "点击分组头作为列方向父格"), 3)) : createCommentVNode("v-if", true),
|
|
312
|
-
createVNode(_sfc_main$
|
|
325
|
+
createVNode(_sfc_main$6, {
|
|
313
326
|
cell: unref(activeCell),
|
|
314
327
|
binding: unref(activeBinding) ?? null,
|
|
315
328
|
"resolved-row-parent-label": unref(resolvedRowParentLabel),
|
|
@@ -317,6 +330,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
317
330
|
"parent-pick-mode": unref(parentPick)?.mode ?? null,
|
|
318
331
|
"row-parent-candidates": unref(rowParentCandidates),
|
|
319
332
|
"col-parent-candidates": unref(colParentCandidates),
|
|
333
|
+
"show-drill": hasDrillTemplates.value,
|
|
320
334
|
"resolve-field-label": unref(resolveFieldLabel),
|
|
321
335
|
"get-binding-at": unref(getBindingAt),
|
|
322
336
|
"host-el": gridHostEl.value,
|
|
@@ -324,6 +338,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
324
338
|
onPatch: unref(patchActiveBinding),
|
|
325
339
|
onRemove: unref(removeActiveBinding),
|
|
326
340
|
onOpenRules: _cache[3] || (_cache[3] = ($event) => rulesDialogVisible.value = true),
|
|
341
|
+
onOpenDrill: _cache[4] || (_cache[4] = ($event) => drillDialogVisible.value = true),
|
|
327
342
|
onStartParentPick: unref(startParentPick),
|
|
328
343
|
onCancelParentPick: unref(cancelParentPick),
|
|
329
344
|
onClearParent: unref(clearParent)
|
|
@@ -335,6 +350,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
335
350
|
"parent-pick-mode",
|
|
336
351
|
"row-parent-candidates",
|
|
337
352
|
"col-parent-candidates",
|
|
353
|
+
"show-drill",
|
|
338
354
|
"resolve-field-label",
|
|
339
355
|
"get-binding-at",
|
|
340
356
|
"host-el",
|
|
@@ -352,15 +368,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
352
368
|
ref: previewViewerRef,
|
|
353
369
|
connector: props.connector,
|
|
354
370
|
template: previewTemplate.value,
|
|
355
|
-
workbook: unref(previewWorkbook)
|
|
371
|
+
workbook: unref(previewWorkbook),
|
|
372
|
+
"resolve-template": props.resolveTemplate
|
|
356
373
|
}, null, 8, [
|
|
357
374
|
"connector",
|
|
358
375
|
"template",
|
|
359
|
-
"workbook"
|
|
376
|
+
"workbook",
|
|
377
|
+
"resolve-template"
|
|
360
378
|
])], 2)) : createCommentVNode("v-if", true),
|
|
361
379
|
createVNode(unref(UDrawer), {
|
|
362
380
|
modelValue: hubVisible.value,
|
|
363
|
-
"onUpdate:modelValue": _cache[
|
|
381
|
+
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => hubVisible.value = $event),
|
|
364
382
|
class: normalizeClass(unref(cls).e("hub-drawer")),
|
|
365
383
|
"show-close": ""
|
|
366
384
|
}, {
|
|
@@ -370,9 +388,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
370
388
|
}, null, 8, ["hub"])]),
|
|
371
389
|
_: 1
|
|
372
390
|
}, 8, ["modelValue", "class"]),
|
|
373
|
-
createVNode(_sfc_main$
|
|
391
|
+
createVNode(_sfc_main$7, {
|
|
374
392
|
modelValue: rulesDialogVisible.value,
|
|
375
|
-
"onUpdate:modelValue": _cache[
|
|
393
|
+
"onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => rulesDialogVisible.value = $event),
|
|
376
394
|
rules: unref(activeBinding)?.conditionalRules ?? EMPTY_CONDITIONAL_RULES,
|
|
377
395
|
"binding-field": unref(activeBinding)?.field ?? "",
|
|
378
396
|
"dataset-fields": unref(activeDatasetFields),
|
|
@@ -384,7 +402,24 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
384
402
|
"binding-field",
|
|
385
403
|
"dataset-fields",
|
|
386
404
|
"field-type"
|
|
387
|
-
])
|
|
405
|
+
]),
|
|
406
|
+
hasDrillTemplates.value ? (openBlock(), createBlock(_sfc_main$4, {
|
|
407
|
+
key: 2,
|
|
408
|
+
modelValue: drillDialogVisible.value,
|
|
409
|
+
"onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => drillDialogVisible.value = $event),
|
|
410
|
+
templates: props.drillTemplates ?? [],
|
|
411
|
+
fields: unref(activeDatasetFields),
|
|
412
|
+
drill: unref(activeBinding)?.drill,
|
|
413
|
+
"resolve-template": props.resolveTemplate,
|
|
414
|
+
onSave: saveDrill,
|
|
415
|
+
onRemove: removeDrill
|
|
416
|
+
}, null, 8, [
|
|
417
|
+
"modelValue",
|
|
418
|
+
"templates",
|
|
419
|
+
"fields",
|
|
420
|
+
"drill",
|
|
421
|
+
"resolve-template"
|
|
422
|
+
])) : createCommentVNode("v-if", true)
|
|
388
423
|
], 2);
|
|
389
424
|
};
|
|
390
425
|
}
|