n20-common-lib 3.1.4 → 3.1.6

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.
@@ -0,0 +1,518 @@
1
+ <template>
2
+ <!-- 右侧维度配置 -->
3
+ <div class="pivot-sidebar-right" :class="{ collapsed: isCollapsed }">
4
+ <div class="sidebar-header">
5
+ <template v-if="!isCollapsed">
6
+ <i class="v3-icon-move-right sidebar-header-collapse" @click="handleToggleCollapse"></i>
7
+ <span class="sidebar-title">维度配置</span>
8
+ </template>
9
+ </div>
10
+ <div class="config-form">
11
+ <!-- 报表标题 -->
12
+ <div class="form-item">
13
+ <label class="form-label">报表标题</label>
14
+ <el-input :value="reportName" size="small" placeholder="请输入报表名称" @input="handleNameChange" />
15
+ </div>
16
+
17
+ <!-- 统计类型 -->
18
+ <div class="form-item">
19
+ <label class="form-label">统计类型</label>
20
+ <div class="radio-group">
21
+ <ViewToggle
22
+ :value="statType"
23
+ :itemWidth="120"
24
+ :options="statTypeOptions"
25
+ @change="handleStatTypeChange"
26
+ />
27
+ </div>
28
+ </div>
29
+
30
+ <!-- 展示形式 - 仅分组统计 + 图表视图时显示 -->
31
+ <div v-if="!isCrossMode && viewMode === 'chart'" class="form-item">
32
+ <label class="form-label">展示形式</label>
33
+ <div
34
+ class="select-wrapper"
35
+ :class="{ active: showChartTypeDropdown }"
36
+ @click="showChartTypeDropdown = !showChartTypeDropdown"
37
+ >
38
+ <div class="select-value">
39
+ <i :class="getChartTypeIcon(chartType)" class="report-icon"></i>
40
+ <span>{{ getChartTypeLabel(chartType) }}</span>
41
+ </div>
42
+ <svg class="select-arrow" width="10" height="10" viewBox="0 0 10 10" fill="none">
43
+ <path
44
+ d="M2 3L5 7L8 3"
45
+ stroke="currentColor"
46
+ stroke-width="1.5"
47
+ stroke-linecap="round"
48
+ stroke-linejoin="round"
49
+ />
50
+ </svg>
51
+ <div v-if="showChartTypeDropdown" class="dropdown-menu chart-type-dropdown">
52
+ <div
53
+ v-for="type in chartTypes"
54
+ :key="type.value"
55
+ class="dropdown-item chart-type-item"
56
+ :class="{ active: chartType === type.value }"
57
+ @click.stop="handleChartTypeChange(type.value)"
58
+ >
59
+ <i :class="getChartTypeIcon(type.value)" class="report-icon"></i>
60
+ <span>{{ type.label }}</span>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="form-divider"></div>
67
+
68
+ <!-- 分组维度 - 仅分组统计显示,单选 -->
69
+ <div v-if="!isCrossMode" class="form-item">
70
+ <label class="form-label">
71
+ 分组维度
72
+ <el-tooltip content="选择维度字段作为分组依据" placement="top">
73
+ <i class="v3-icon-help"></i>
74
+ </el-tooltip>
75
+ </label>
76
+ <div
77
+ class="select-wrapper"
78
+ :class="{ active: showDimensionDropdown }"
79
+ @click="showDimensionDropdown = !showDimensionDropdown"
80
+ >
81
+ <div class="select-value">
82
+ <span v-if="!selectedDimension" class="placeholder">请选择</span>
83
+ <span v-else>{{ getDimensionLabel(selectedDimension) }}</span>
84
+ </div>
85
+ <svg class="select-arrow" width="10" height="10" viewBox="0 0 10 10" fill="none">
86
+ <path
87
+ d="M2 3L5 7L8 3"
88
+ stroke="currentColor"
89
+ stroke-width="1.5"
90
+ stroke-linecap="round"
91
+ stroke-linejoin="round"
92
+ />
93
+ </svg>
94
+ <div v-if="showDimensionDropdown" class="dropdown-menu dimension-dropdown">
95
+ <div
96
+ v-for="dim in availableDimensions"
97
+ :key="dim.prop"
98
+ class="dropdown-item"
99
+ :class="{ active: selectedDimension === dim.prop }"
100
+ @click.stop="handleDimensionSelect(dim.prop)"
101
+ >
102
+ <span>{{ dim.label }}</span>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- 行维度 - 仅交叉统计显示 -->
109
+ <div v-if="isCrossMode" class="form-item">
110
+ <label class="form-label">
111
+ 行维度
112
+ <el-tooltip content="选择维度字段作为行分组依据" placement="top">
113
+ <i class="v3-icon-help"></i>
114
+ </el-tooltip>
115
+ </label>
116
+ <div
117
+ class="select-wrapper"
118
+ :class="{ active: showRowDimensionDropdown }"
119
+ @click="showRowDimensionDropdown = !showRowDimensionDropdown"
120
+ >
121
+ <div class="select-value">
122
+ <span v-if="!rowDimension" class="placeholder">请选择</span>
123
+ <span v-else>{{ getDimensionLabel(rowDimension) }}</span>
124
+ </div>
125
+ <svg class="select-arrow" width="10" height="10" viewBox="0 0 10 10" fill="none">
126
+ <path
127
+ d="M2 3L5 7L8 3"
128
+ stroke="currentColor"
129
+ stroke-width="1.5"
130
+ stroke-linecap="round"
131
+ stroke-linejoin="round"
132
+ />
133
+ </svg>
134
+ <div v-if="showRowDimensionDropdown" class="dropdown-menu dimension-dropdown">
135
+ <div
136
+ v-for="dim in availableDimensions"
137
+ :key="dim.prop"
138
+ class="dropdown-item"
139
+ :class="{ active: rowDimension === dim.prop }"
140
+ @click.stop="handleRowDimensionChange(dim.prop)"
141
+ >
142
+ <span>{{ dim.label }}</span>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </div>
147
+
148
+ <div v-if="isCrossMode" class="form-divider"></div>
149
+
150
+ <!-- 列维度 - 仅交叉统计显示 -->
151
+ <div v-if="isCrossMode" class="form-item">
152
+ <label class="form-label">
153
+ 列维度
154
+ <el-tooltip content="选择维度字段作为列分组依据" placement="top">
155
+ <i class="v3-icon-help"></i>
156
+ </el-tooltip>
157
+ </label>
158
+ <div
159
+ class="select-wrapper"
160
+ :class="{ active: showColumnDimensionDropdown }"
161
+ @click="showColumnDimensionDropdown = !showColumnDimensionDropdown"
162
+ >
163
+ <div class="select-value">
164
+ <span v-if="!columnDimension" class="placeholder">请选择</span>
165
+ <span v-else>{{ getDimensionLabel(columnDimension) }}</span>
166
+ </div>
167
+ <svg class="select-arrow" width="10" height="10" viewBox="0 0 10 10" fill="none">
168
+ <path
169
+ d="M2 3L5 7L8 3"
170
+ stroke="currentColor"
171
+ stroke-width="1.5"
172
+ stroke-linecap="round"
173
+ stroke-linejoin="round"
174
+ />
175
+ </svg>
176
+ <div v-if="showColumnDimensionDropdown" class="dropdown-menu dimension-dropdown">
177
+ <div
178
+ v-for="dim in availableDimensions"
179
+ :key="dim.prop"
180
+ class="dropdown-item"
181
+ :class="{ active: columnDimension === dim.prop }"
182
+ @click.stop="handleColumnDimensionChange(dim.prop)"
183
+ >
184
+ <span>{{ dim.label }}</span>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ <div class="form-divider"></div>
191
+
192
+ <!-- 计算指标 -->
193
+ <div class="form-item">
194
+ <div class="form-label-row">
195
+ <div class="form-label-group">
196
+ <label class="form-label">
197
+ 计算指标
198
+ <el-tooltip content="选择数值字段作为计算指标,支持多种聚合方式" placement="top">
199
+ <i class="v3-icon-help"></i>
200
+ </el-tooltip>
201
+ </label>
202
+ </div>
203
+ <div class="aggregate-dropdown" @click="showAggregateDropdown = !showAggregateDropdown">
204
+ <span>自定义</span>
205
+ <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
206
+ <path
207
+ d="M2 3L5 7L8 3"
208
+ stroke="currentColor"
209
+ stroke-width="1.5"
210
+ stroke-linecap="round"
211
+ stroke-linejoin="round"
212
+ />
213
+ </svg>
214
+ <div v-if="showAggregateDropdown" class="dropdown-menu aggregate-dropdown-menu">
215
+ <div
216
+ v-for="agg in aggregateTypes"
217
+ :key="agg.value"
218
+ class="dropdown-item"
219
+ :class="{ active: globalAggregateType === agg.value }"
220
+ @click.stop="handleGlobalAggregateChange(agg.value)"
221
+ >
222
+ {{ agg.label }}
223
+ </div>
224
+ </div>
225
+ </div>
226
+ </div>
227
+
228
+ <!-- 已选指标行列表 -->
229
+ <div class="metric-rows">
230
+ <div
231
+ v-for="metric in metrics"
232
+ :key="metric.prop"
233
+ class="metric-row"
234
+ :class="{ active: activeMetricKey === metric.prop }"
235
+ >
236
+ <div class="metric-select-box">
237
+ <div class="metric-select-value">{{ getMetricLabel(metric.prop) }}</div>
238
+ <div class="metric-select-tag" @click.stop="handleToggleMetricAggregate(metric.prop)">
239
+ {{ getAggregateLabel(metric.aggregateType) }}
240
+ </div>
241
+ </div>
242
+ <div class="metric-delete-btn" @click="handleRemoveMetric(metric.prop)">
243
+ <i class="v3-icon-delete"></i>
244
+ </div>
245
+ <!-- 单个指标聚合类型下拉 -->
246
+ <div v-if="activeMetricKey === metric.prop" class="dropdown-menu metric-aggregate-dropdown">
247
+ <div
248
+ v-for="agg in aggregateTypes"
249
+ :key="agg.value"
250
+ class="dropdown-item"
251
+ :class="{ active: metric.aggregateType === agg.value }"
252
+ @click.stop="handleMetricAggregateChange(metric.prop, agg.value)"
253
+ >
254
+ {{ agg.label }}
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+
260
+ <div class="add-field-btn" @click="showMetricAddDropdown = !showMetricAddDropdown">
261
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
262
+ <path d="M7 1V13M1 7H13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
263
+ </svg>
264
+ <span>添加字段</span>
265
+ <!-- 添加字段下拉 -->
266
+ <div v-if="showMetricAddDropdown" class="dropdown-menu metric-add-dropdown">
267
+ <div
268
+ v-for="metric in availableMetricsForAdd"
269
+ :key="metric.prop"
270
+ class="dropdown-item"
271
+ @click.stop="handleAddMetric(metric.prop)"
272
+ >
273
+ {{ metric.label }}
274
+ </div>
275
+ <div v-if="availableMetricsForAdd.length === 0" class="dropdown-item disabled">无可用字段</div>
276
+ </div>
277
+ </div>
278
+ </div>
279
+ </div>
280
+ </div>
281
+ </template>
282
+
283
+ <script>
284
+ import ViewToggle from '../ViewToggle/index.vue'
285
+
286
+ export default {
287
+ name: 'ConfigSidebar',
288
+ components: {
289
+ ViewToggle
290
+ },
291
+ props: {
292
+ // 是否折叠
293
+ isCollapsed: {
294
+ type: Boolean,
295
+ default: false
296
+ },
297
+ // 报表名称
298
+ reportName: {
299
+ type: String,
300
+ default: ''
301
+ },
302
+ // 统计类型
303
+ statType: {
304
+ type: String,
305
+ default: 'group'
306
+ },
307
+ // 统计类型选项
308
+ statTypeOptions: {
309
+ type: Array,
310
+ default: () => []
311
+ },
312
+ // 图表类型
313
+ chartType: {
314
+ type: String,
315
+ default: 'bar'
316
+ },
317
+ // 图表类型选项
318
+ chartTypes: {
319
+ type: Array,
320
+ default: () => []
321
+ },
322
+ // 是否交叉统计模式
323
+ isCrossMode: {
324
+ type: Boolean,
325
+ default: false
326
+ },
327
+ // 视图模式(chart/table)
328
+ viewMode: {
329
+ type: String,
330
+ default: 'chart'
331
+ },
332
+ // 分组维度(单选)
333
+ selectedDimension: {
334
+ type: String,
335
+ default: null
336
+ },
337
+ // 行维度
338
+ rowDimension: {
339
+ type: String,
340
+ default: null
341
+ },
342
+ // 列维度
343
+ columnDimension: {
344
+ type: String,
345
+ default: null
346
+ },
347
+ // 指标列表
348
+ metrics: {
349
+ type: Array,
350
+ default: () => []
351
+ },
352
+ // 可用维度
353
+ availableDimensions: {
354
+ type: Array,
355
+ default: () => []
356
+ },
357
+ // 可添加的指标
358
+ availableMetricsForAdd: {
359
+ type: Array,
360
+ default: () => []
361
+ },
362
+ // 所有可用指标(用于显示标签)
363
+ availableMetrics: {
364
+ type: Array,
365
+ default: () => []
366
+ },
367
+ // 全局聚合类型
368
+ globalAggregateType: {
369
+ type: String,
370
+ default: 'sum'
371
+ },
372
+ // 聚合类型选项
373
+ aggregateTypes: {
374
+ type: Array,
375
+ default: () => []
376
+ }
377
+ },
378
+ data() {
379
+ return {
380
+ showChartTypeDropdown: false,
381
+ showDimensionDropdown: false,
382
+ showRowDimensionDropdown: false,
383
+ showColumnDimensionDropdown: false,
384
+ showAggregateDropdown: false,
385
+ showMetricAddDropdown: false,
386
+ activeMetricKey: null
387
+ }
388
+ },
389
+ methods: {
390
+ // 获取图表类型图标
391
+ getChartTypeIcon(type) {
392
+ const iconMap = {
393
+ bar: 'v3-icon-chart-histogram',
394
+ line: 'v3-icon-chart-line',
395
+ pie: 'v3-icon-chart-pie',
396
+ horizontalBar: 'v3-icon-histogram'
397
+ }
398
+ return iconMap[type] || 'v3-icon-chart-histogram'
399
+ },
400
+
401
+ // 获取图表类型标签
402
+ getChartTypeLabel(type) {
403
+ const chart = this.chartTypes.find((t) => t.value === type)
404
+ return chart ? chart.label : '柱状图'
405
+ },
406
+
407
+ // 获取维度标签
408
+ getDimensionLabel(dimKey) {
409
+ const dim = this.availableDimensions.find((d) => d.prop === dimKey)
410
+ return dim ? dim.label : dimKey
411
+ },
412
+
413
+ // 获取维度标签列表
414
+ getDimensionLabels(dimKeys) {
415
+ return dimKeys.map((k) => this.getDimensionLabel(k)).join(', ')
416
+ },
417
+
418
+ // 获取指标标签
419
+ getMetricLabel(metricProp) {
420
+ // 优先从所有可用指标中查找
421
+ const metric = this.availableMetrics.find((m) => m.prop === metricProp)
422
+ if (metric) return metric.label
423
+ // 其次从可添加指标中查找
424
+ const metricForAdd = this.availableMetricsForAdd.find((m) => m.prop === metricProp)
425
+ if (metricForAdd) return metricForAdd.label
426
+ // 最后返回 prop
427
+ return metricProp
428
+ },
429
+
430
+ // 获取聚合类型标签
431
+ getAggregateLabel(type) {
432
+ const agg = this.aggregateTypes.find((t) => t.value === type)
433
+ return agg ? agg.label : '求和'
434
+ },
435
+
436
+ // 切换折叠状态
437
+ handleToggleCollapse() {
438
+ this.$emit('toggle-collapse')
439
+ },
440
+
441
+ // 报表名称变更
442
+ handleNameChange(value) {
443
+ this.$emit('name-change', value)
444
+ },
445
+
446
+ // 统计类型变更
447
+ handleStatTypeChange(type) {
448
+ this.$emit('stat-type-change', type)
449
+ },
450
+
451
+ // 图表类型变更
452
+ handleChartTypeChange(type) {
453
+ this.showChartTypeDropdown = false
454
+ this.$emit('chart-type-change', type)
455
+ },
456
+
457
+ // 分组维度选择(单选)
458
+ handleDimensionSelect(dimKey) {
459
+ this.showDimensionDropdown = false
460
+ this.$emit('dimension-select', dimKey)
461
+ },
462
+
463
+ // 行维度变更
464
+ handleRowDimensionChange(dimKey) {
465
+ this.showRowDimensionDropdown = false
466
+ this.$emit('row-dimension-change', dimKey)
467
+ },
468
+
469
+ // 列维度变更
470
+ handleColumnDimensionChange(dimKey) {
471
+ this.showColumnDimensionDropdown = false
472
+ this.$emit('column-dimension-change', dimKey)
473
+ },
474
+
475
+ // 切换单个指标聚合类型下拉
476
+ handleToggleMetricAggregate(metricProp) {
477
+ this.activeMetricKey = this.activeMetricKey === metricProp ? null : metricProp
478
+ },
479
+
480
+ // 修改单个指标的聚合类型
481
+ handleMetricAggregateChange(metricProp, aggregateType) {
482
+ this.activeMetricKey = null
483
+ this.$emit('metric-aggregate-change', { prop: metricProp, aggregateType })
484
+ },
485
+
486
+ // 全局聚合类型变更
487
+ handleGlobalAggregateChange(type) {
488
+ this.showAggregateDropdown = false
489
+ this.$emit('global-aggregate-change', type)
490
+ },
491
+
492
+ // 添加指标
493
+ handleAddMetric(metricProp) {
494
+ this.showMetricAddDropdown = false
495
+ this.$emit('add-metric', metricProp)
496
+ },
497
+
498
+ // 删除指标
499
+ handleRemoveMetric(metricProp) {
500
+ if (this.activeMetricKey === metricProp) {
501
+ this.activeMetricKey = null
502
+ }
503
+ this.$emit('remove-metric', metricProp)
504
+ },
505
+
506
+ // 关闭所有下拉菜单(供外部调用)
507
+ closeAllDropdowns() {
508
+ this.showChartTypeDropdown = false
509
+ this.showDimensionDropdown = false
510
+ this.showRowDimensionDropdown = false
511
+ this.showColumnDimensionDropdown = false
512
+ this.showAggregateDropdown = false
513
+ this.showMetricAddDropdown = false
514
+ this.activeMetricKey = null
515
+ }
516
+ }
517
+ }
518
+ </script>
@@ -0,0 +1,160 @@
1
+ <template>
2
+ <!-- 内容头部工具栏 -->
3
+ <div class="main-toolbar">
4
+ <div class="toolbar-left">
5
+ <div class="toolbar-left-top">
6
+ <h2 class="report-title">{{ reportName }}</h2>
7
+ <div class="add-to-home-btn" @click="handleAddToHome">
8
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
9
+ <path
10
+ d="M5.8335 7.58496C6.1554 7.58514 6.41633 7.84606 6.4165 8.16797V12.252C6.41615 12.5737 6.1553 12.8348 5.8335 12.835H1.74951C1.42771 12.8348 1.16686 12.5737 1.1665 12.252V8.16797C1.16668 7.84606 1.4276 7.58514 1.74951 7.58496H5.8335ZM10.7915 9.62598H12.5415V10.793H10.7915V12.543H9.62451V10.793H7.87451V9.62598H9.62451V7.87598H10.7915V9.62598ZM2.3335 11.668H5.24951V8.75195H2.3335V11.668ZM5.8335 1.16797C6.1554 1.16814 6.41633 1.42907 6.4165 1.75098V5.83496C6.41633 6.15687 6.1554 6.41779 5.8335 6.41797H1.74951C1.4276 6.41779 1.16668 6.15687 1.1665 5.83496V1.75098C1.16668 1.42907 1.4276 1.16814 1.74951 1.16797H5.8335ZM12.2505 1.16797C12.5722 1.16832 12.8333 1.42918 12.8335 1.75098V5.83496C12.8333 6.15676 12.5722 6.41762 12.2505 6.41797H8.1665C7.8446 6.41779 7.58367 6.15687 7.5835 5.83496V1.75098C7.58367 1.42907 7.8446 1.16814 8.1665 1.16797H12.2505ZM2.3335 5.25098H5.24951V2.33496H2.3335V5.25098ZM8.75049 5.25098H11.6665V2.33496H8.75049V5.25098Z"
11
+ fill="#007AFF"
12
+ />
13
+ </svg>
14
+ <span>添加到首页</span>
15
+ </div>
16
+ </div>
17
+ <div class="report-stats">
18
+ <span class="stat-item">计算耗时:{{ calculateTime }} ms</span>
19
+ <span class="stat-divider"></span>
20
+ <span class="stat-item">数据条数:{{ dataCount }}</span>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="toolbar-right">
25
+ <ViewToggle
26
+ v-model="viewMode"
27
+ :options="viewModeOptions"
28
+ :disabled="isCrossMode"
29
+ @change="handleViewModeChange"
30
+ />
31
+ <span class="toolbar-divider"></span>
32
+ <div class="action-buttons">
33
+ <div class="action-btn" @click="handleRefresh" title="刷新">
34
+ <i class="n20-icon-shuaxin"></i>
35
+ </div>
36
+ <div class="action-btn more-btn" :class="{ active: showMoreMenu }" @click="toggleMoreMenu" title="更多">
37
+ <i class="v3-icon-more"></i>
38
+ <div v-if="showMoreMenu" class="more-dropdown-menu" @click.stop>
39
+ <div v-if="isRightSidebarCollapsed" class="dropdown-menu-item" @click="handleConfig">
40
+ <i class="v3-icon-setting"></i>
41
+ <span>配置</span>
42
+ </div>
43
+ <div class="dropdown-menu-item" @click="handleAddToHome">
44
+ <i class="v3-icon-add-menu"></i>
45
+ <span>添加到首页</span>
46
+ </div>
47
+ <div class="dropdown-menu-item" @click="handleExport">
48
+ <i class="v3-icon-upload"></i>
49
+ <span>导出</span>
50
+ </div>
51
+ <div class="dropdown-divider"></div>
52
+ <div class="dropdown-menu-item danger" @click.stop="handleDeleteReport">
53
+ <i class="v3-icon-delete"></i>
54
+ <span>删除</span>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </template>
62
+
63
+ <script>
64
+ import ViewToggle from '../ViewToggle/index.vue'
65
+
66
+ export default {
67
+ name: 'MainToolbar',
68
+ components: {
69
+ ViewToggle
70
+ },
71
+ props: {
72
+ // 报表名称
73
+ reportName: {
74
+ type: String,
75
+ default: ''
76
+ },
77
+ // 计算耗时
78
+ calculateTime: {
79
+ type: Number,
80
+ default: 0
81
+ },
82
+ // 数据条数
83
+ dataCount: {
84
+ type: Number,
85
+ default: 0
86
+ },
87
+ // 视图模式
88
+ viewMode: {
89
+ type: String,
90
+ default: 'chart'
91
+ },
92
+ // 视图模式选项
93
+ viewModeOptions: {
94
+ type: Array,
95
+ default: () => []
96
+ },
97
+ // 是否交叉统计模式
98
+ isCrossMode: {
99
+ type: Boolean,
100
+ default: false
101
+ },
102
+ // 右侧边栏是否折叠
103
+ isRightSidebarCollapsed: {
104
+ type: Boolean,
105
+ default: false
106
+ }
107
+ },
108
+ data() {
109
+ return {
110
+ showMoreMenu: false
111
+ }
112
+ },
113
+ methods: {
114
+ // 切换更多菜单显示
115
+ toggleMoreMenu() {
116
+ this.showMoreMenu = !this.showMoreMenu
117
+ },
118
+
119
+ // 处理视图模式切换
120
+ handleViewModeChange(val) {
121
+ this.$emit('view-mode-change', val)
122
+ },
123
+
124
+ // 刷新数据
125
+ handleRefresh() {
126
+ this.showMoreMenu = false
127
+ this.$emit('refresh')
128
+ },
129
+
130
+ // 配置
131
+ handleConfig() {
132
+ this.showMoreMenu = false
133
+ this.$emit('config')
134
+ },
135
+
136
+ // 导出数据
137
+ handleExport() {
138
+ this.showMoreMenu = false
139
+ this.$emit('export')
140
+ },
141
+
142
+ // 添加到首页
143
+ handleAddToHome() {
144
+ this.showMoreMenu = false
145
+ this.$emit('add-to-home')
146
+ },
147
+
148
+ // 删除报表
149
+ handleDeleteReport() {
150
+ this.showMoreMenu = false
151
+ this.$emit('delete-report')
152
+ },
153
+
154
+ // 关闭菜单(供外部调用)
155
+ closeMenu() {
156
+ this.showMoreMenu = false
157
+ }
158
+ }
159
+ }
160
+ </script>