@vela-studio/ui 1.0.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.
Files changed (68) hide show
  1. package/README.md +152 -0
  2. package/dist/index.d.ts +696 -0
  3. package/dist/index.js +10 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +11786 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/index.umd.js +10 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/dist/style.css +1 -0
  10. package/index.ts +150 -0
  11. package/package.json +73 -0
  12. package/src/components/advanced/scripting/Scripting.vue +189 -0
  13. package/src/components/advanced/state/State.vue +231 -0
  14. package/src/components/advanced/trigger/Trigger.vue +256 -0
  15. package/src/components/basic/button/Button.vue +120 -0
  16. package/src/components/basic/container/Container.vue +22 -0
  17. package/src/components/chart/barChart/barChart.vue +176 -0
  18. package/src/components/chart/doughnutChart/doughnutChart.vue +128 -0
  19. package/src/components/chart/funnelChart/funnelChart.vue +128 -0
  20. package/src/components/chart/gaugeChart/gaugeChart.vue +144 -0
  21. package/src/components/chart/lineChart/lineChart.vue +188 -0
  22. package/src/components/chart/pieChart/pieChart.vue +114 -0
  23. package/src/components/chart/radarChart/radarChart.vue +115 -0
  24. package/src/components/chart/sankeyChart/sankeyChart.vue +144 -0
  25. package/src/components/chart/scatterChart/scatterChart.vue +162 -0
  26. package/src/components/chart/stackedBarChart/stackedBarChart.vue +184 -0
  27. package/src/components/content/html/Html.vue +104 -0
  28. package/src/components/content/iframe/Iframe.vue +111 -0
  29. package/src/components/content/markdown/Markdown.vue +174 -0
  30. package/src/components/controls/breadcrumb/Breadcrumb.vue +79 -0
  31. package/src/components/controls/buttonGroup/ButtonGroup.vue +93 -0
  32. package/src/components/controls/checkboxGroup/CheckboxGroup.vue +147 -0
  33. package/src/components/controls/dateRange/DateRange.vue +174 -0
  34. package/src/components/controls/multiSelect/MultiSelect.vue +155 -0
  35. package/src/components/controls/navButton/NavButton.vue +97 -0
  36. package/src/components/controls/pagination/Pagination.vue +94 -0
  37. package/src/components/controls/searchBox/SearchBox.vue +170 -0
  38. package/src/components/controls/select/Select.vue +134 -0
  39. package/src/components/controls/slider/Slider.vue +167 -0
  40. package/src/components/controls/switch/Switch.vue +107 -0
  41. package/src/components/data/cardGrid/CardGrid.vue +318 -0
  42. package/src/components/data/list/List.vue +282 -0
  43. package/src/components/data/pivot/Pivot.vue +270 -0
  44. package/src/components/data/table/Table.vue +150 -0
  45. package/src/components/data/timeline/Timeline.vue +315 -0
  46. package/src/components/group/Group.vue +75 -0
  47. package/src/components/kpi/box/Box.vue +98 -0
  48. package/src/components/kpi/countUp/CountUp.vue +193 -0
  49. package/src/components/kpi/progress/Progress.vue +159 -0
  50. package/src/components/kpi/stat/Stat.vue +205 -0
  51. package/src/components/kpi/text/Text.vue +74 -0
  52. package/src/components/layout/badge/Badge.vue +105 -0
  53. package/src/components/layout/col/Col.vue +114 -0
  54. package/src/components/layout/flex/Flex.vue +105 -0
  55. package/src/components/layout/grid/Grid.vue +89 -0
  56. package/src/components/layout/modal/Modal.vue +118 -0
  57. package/src/components/layout/panel/Panel.vue +162 -0
  58. package/src/components/layout/row/Row.vue +99 -0
  59. package/src/components/layout/tabs/Tabs.vue +117 -0
  60. package/src/components/media/image/Image.vue +132 -0
  61. package/src/components/media/video/Video.vue +115 -0
  62. package/src/components/v2/basic/BaseButton.vue +179 -0
  63. package/src/components/v2/kpi/KpiCard.vue +215 -0
  64. package/src/components/v2/layout/GridBox.vue +55 -0
  65. package/src/hooks/useDataSource.ts +123 -0
  66. package/src/types/gis.ts +251 -0
  67. package/src/utils/chartUtils.ts +349 -0
  68. package/src/utils/dataUtils.ts +403 -0
@@ -0,0 +1,256 @@
1
+ <template>
2
+ <div :style="containerStyle">
3
+ <div class="trigger-container">
4
+ <div class="header">
5
+ <span class="title">
6
+ <el-icon><Timer /></el-icon>
7
+ {{ title }}
8
+ </span>
9
+ <div class="controls">
10
+ <el-tag :type="enabled ? 'success' : 'info'" size="small">
11
+ {{ enabled ? '已启用' : '已禁用' }}
12
+ </el-tag>
13
+ <el-button
14
+ v-if="triggerType === 'manual'"
15
+ type="primary"
16
+ size="small"
17
+ @click="$emit('trigger')"
18
+ :disabled="!enabled"
19
+ >
20
+ 触发
21
+ </el-button>
22
+ <el-button v-if="showClearButton" size="small" @click="$emit('clear')"> 清除 </el-button>
23
+ </div>
24
+ </div>
25
+
26
+ <div class="info-section">
27
+ <div class="info-item">
28
+ <span class="label">类型:</span>
29
+ <el-tag size="small">{{ triggerType === 'manual' ? '手动' : '定时' }}</el-tag>
30
+ </div>
31
+ <div v-if="triggerType === 'interval'" class="info-item">
32
+ <span class="label">间隔:</span>
33
+ <span>{{ interval }}ms</span>
34
+ </div>
35
+ <div class="info-item">
36
+ <span class="label">动作:</span>
37
+ <span>{{ action }}</span>
38
+ </div>
39
+ </div>
40
+
41
+ <div class="logs-section">
42
+ <div class="section-title">执行日志 ({{ logs.length }})</div>
43
+ <div class="logs-container">
44
+ <div
45
+ v-for="(log, index) in logs"
46
+ :key="index"
47
+ class="log-item"
48
+ :class="`log-${log.type}`"
49
+ >
50
+ <span class="log-time">{{ log.time }}</span>
51
+ <span class="log-message">{{ log.message }}</span>
52
+ </div>
53
+ <div v-if="logs.length === 0" class="placeholder">
54
+ <el-icon><DocumentCopy /></el-icon>
55
+ <span>{{ placeholder }}</span>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </template>
62
+
63
+ <script setup lang="ts">
64
+ import { computed, type CSSProperties } from 'vue'
65
+ import { Timer, DocumentCopy } from '@element-plus/icons-vue'
66
+
67
+ export interface TriggerLog {
68
+ time: string
69
+ message: string
70
+ type: 'info' | 'success' | 'warning' | 'error'
71
+ }
72
+
73
+ export interface TriggerProps {
74
+ title?: string
75
+ enabled?: boolean
76
+ triggerType?: 'manual' | 'interval'
77
+ interval?: number
78
+ action?: string
79
+ logs?: TriggerLog[]
80
+ showClearButton?: boolean
81
+ placeholder?: string
82
+ // 样式
83
+ padding?: number
84
+ backgroundColor?: string
85
+ textColor?: string
86
+ fontSize?: number
87
+ lineHeight?: number
88
+ borderRadius?: number
89
+ border?: string
90
+ fontFamily?: string
91
+ }
92
+
93
+ const props = withDefaults(defineProps<TriggerProps>(), {
94
+ title: '触发器',
95
+ enabled: true,
96
+ triggerType: 'manual',
97
+ interval: 5000,
98
+ action: 'log',
99
+ logs: () => [],
100
+ showClearButton: true,
101
+ placeholder: '暂无执行记录',
102
+ padding: 16,
103
+ backgroundColor: '#1a1a1a',
104
+ textColor: '#e0e0e0',
105
+ fontSize: 13,
106
+ lineHeight: 1.5,
107
+ borderRadius: 4,
108
+ border: '1px solid #3c3c3c',
109
+ fontFamily: 'Consolas, Monaco, "Courier New", monospace',
110
+ })
111
+
112
+ defineEmits<{
113
+ trigger: []
114
+ clear: []
115
+ }>()
116
+
117
+ const containerStyle = computed<CSSProperties>(() => ({
118
+ width: '100%',
119
+ height: '100%',
120
+ padding: `${props.padding}px`,
121
+ backgroundColor: props.backgroundColor,
122
+ color: props.textColor,
123
+ fontSize: `${props.fontSize}px`,
124
+ lineHeight: props.lineHeight,
125
+ borderRadius: `${props.borderRadius}px`,
126
+ border: props.border,
127
+ overflow: 'hidden',
128
+ fontFamily: props.fontFamily,
129
+ }))
130
+ </script>
131
+
132
+ <style scoped>
133
+ .trigger-container {
134
+ display: flex;
135
+ flex-direction: column;
136
+ gap: 12px;
137
+ height: 100%;
138
+ }
139
+
140
+ .header {
141
+ display: flex;
142
+ justify-content: space-between;
143
+ align-items: center;
144
+ padding-bottom: 8px;
145
+ border-bottom: 1px solid #3c3c3c;
146
+ }
147
+
148
+ .title {
149
+ display: flex;
150
+ align-items: center;
151
+ gap: 6px;
152
+ font-weight: 600;
153
+ font-size: 16px;
154
+ }
155
+
156
+ .controls {
157
+ display: flex;
158
+ gap: 8px;
159
+ align-items: center;
160
+ }
161
+
162
+ .info-section {
163
+ display: flex;
164
+ gap: 16px;
165
+ flex-wrap: wrap;
166
+ padding: 8px 0;
167
+ }
168
+
169
+ .info-item {
170
+ display: flex;
171
+ align-items: center;
172
+ gap: 6px;
173
+ }
174
+
175
+ .label {
176
+ opacity: 0.7;
177
+ font-size: 12px;
178
+ }
179
+
180
+ .section-title {
181
+ font-size: 12px;
182
+ opacity: 0.7;
183
+ margin-bottom: 8px;
184
+ text-transform: uppercase;
185
+ }
186
+
187
+ .logs-section {
188
+ flex: 1;
189
+ min-height: 0;
190
+ display: flex;
191
+ flex-direction: column;
192
+ }
193
+
194
+ .logs-container {
195
+ flex: 1;
196
+ overflow-y: auto;
197
+ background: rgba(0, 0, 0, 0.3);
198
+ border-radius: 4px;
199
+ padding: 8px;
200
+ }
201
+
202
+ .log-item {
203
+ display: flex;
204
+ gap: 12px;
205
+ padding: 6px 8px;
206
+ margin-bottom: 4px;
207
+ border-radius: 3px;
208
+ font-size: 12px;
209
+ border-left: 3px solid transparent;
210
+ }
211
+
212
+ .log-info {
213
+ background: rgba(59, 130, 246, 0.1);
214
+ border-left-color: #3b82f6;
215
+ }
216
+
217
+ .log-success {
218
+ background: rgba(34, 197, 94, 0.1);
219
+ border-left-color: #22c55e;
220
+ }
221
+
222
+ .log-warning {
223
+ background: rgba(251, 191, 36, 0.1);
224
+ border-left-color: #fbbf24;
225
+ }
226
+
227
+ .log-error {
228
+ background: rgba(239, 68, 68, 0.1);
229
+ border-left-color: #ef4444;
230
+ }
231
+
232
+ .log-time {
233
+ opacity: 0.6;
234
+ flex-shrink: 0;
235
+ width: 80px;
236
+ }
237
+
238
+ .log-message {
239
+ flex: 1;
240
+ word-break: break-all;
241
+ }
242
+
243
+ .placeholder {
244
+ display: flex;
245
+ flex-direction: column;
246
+ justify-content: center;
247
+ align-items: center;
248
+ height: 100%;
249
+ gap: 8px;
250
+ opacity: 0.5;
251
+ }
252
+
253
+ .placeholder .el-icon {
254
+ font-size: 32px;
255
+ }
256
+ </style>
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <el-button
3
+ :type="type"
4
+ :size="size"
5
+ :plain="plain"
6
+ :round="round"
7
+ :circle="circle"
8
+ :disabled="disabled"
9
+ :icon="icon"
10
+ :loading="loading"
11
+ :style="buttonStyle"
12
+ @click="handleClick"
13
+ >
14
+ {{ text }}
15
+ </el-button>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { computed } from 'vue'
20
+ import type { CSSProperties } from 'vue'
21
+ import { ElButton } from 'element-plus'
22
+
23
+ // 定义纯 UI Props
24
+ const props = withDefaults(
25
+ defineProps<{
26
+ // 内容
27
+ text?: string
28
+
29
+ // 类型
30
+ type?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text' | 'default'
31
+ size?: 'large' | 'default' | 'small'
32
+
33
+ // 状态
34
+ plain?: boolean
35
+ round?: boolean
36
+ circle?: boolean
37
+ disabled?: boolean
38
+ loading?: boolean
39
+
40
+ // 图标
41
+ icon?: string
42
+
43
+ // 样式
44
+ width?: string | number
45
+ height?: string | number
46
+ backgroundColor?: string
47
+ color?: string // 标准化命名:原 textColor
48
+ fontSize?: number | string // 标准化类型:支持 string | number
49
+ fontWeight?: number | string
50
+ borderRadius?: number | string // 标准化类型
51
+ padding?: string
52
+ }>(),
53
+ {
54
+ text: '按钮',
55
+ type: 'primary',
56
+ size: 'default',
57
+ plain: false,
58
+ round: false,
59
+ circle: false,
60
+ disabled: false,
61
+ loading: false,
62
+ // 样式默认值保持 undefined 由 CSS 控制,或显式指定
63
+ },
64
+ )
65
+
66
+ const emit = defineEmits<{
67
+ (e: 'click', event: MouseEvent): void
68
+ }>()
69
+
70
+ // 按钮样式
71
+ const buttonStyle = computed<CSSProperties>(() => {
72
+ const style: CSSProperties = {}
73
+
74
+ if (props.width !== undefined) {
75
+ style.width = typeof props.width === 'number' ? `${props.width}px` : props.width
76
+ }
77
+
78
+ if (props.height !== undefined) {
79
+ style.height = typeof props.height === 'number' ? `${props.height}px` : props.height
80
+ }
81
+
82
+ if (props.backgroundColor) {
83
+ style.backgroundColor = props.backgroundColor
84
+ style.borderColor = props.backgroundColor
85
+ }
86
+
87
+ if (props.color) {
88
+ style.color = props.color
89
+ }
90
+
91
+ if (props.fontSize !== undefined) {
92
+ style.fontSize = typeof props.fontSize === 'number' ? `${props.fontSize}px` : props.fontSize
93
+ }
94
+
95
+ if (props.fontWeight !== undefined) {
96
+ style.fontWeight = props.fontWeight
97
+ }
98
+
99
+ if (props.borderRadius !== undefined) {
100
+ style.borderRadius =
101
+ typeof props.borderRadius === 'number' ? `${props.borderRadius}px` : props.borderRadius
102
+ }
103
+
104
+ if (props.padding) {
105
+ style.padding = props.padding
106
+ }
107
+
108
+ return style
109
+ })
110
+
111
+ const handleClick = (event: MouseEvent) => {
112
+ if (!props.disabled && !props.loading) {
113
+ emit('click', event)
114
+ }
115
+ }
116
+ </script>
117
+
118
+ <style scoped>
119
+ /* 样式由 Element Plus 和 props 控制 */
120
+ </style>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <div class="v-container">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ // Container 组件是一个纯粹的容器,样式通过 style 透传 (继承自 $attrs)
9
+ // 不需要定义任何 CSS 相关的 Props
10
+ defineOptions({
11
+ inheritAttrs: true, // 允许 attrs (style, class, id) 自动绑定到根元素
12
+ })
13
+ </script>
14
+
15
+ <style scoped>
16
+ .v-container {
17
+ box-sizing: border-box;
18
+ /* 默认样式 */
19
+ position: relative;
20
+ min-height: 50px; /* 给一个最小高度方便拖拽 */
21
+ }
22
+ </style>
@@ -0,0 +1,176 @@
1
+ <template>
2
+ <div class="v-bar-chart" :style="{ width: '100%', height: '100%' }">
3
+ <v-chart :option="finalOption" autoresize class="echart" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { computed } from 'vue'
9
+ import { use } from 'echarts/core'
10
+ import { CanvasRenderer } from 'echarts/renderers'
11
+ import { BarChart } from 'echarts/charts'
12
+ import {
13
+ TitleComponent,
14
+ TooltipComponent,
15
+ GridComponent,
16
+ LegendComponent,
17
+ } from 'echarts/components'
18
+ import VChart from 'vue-echarts'
19
+ import type { EChartsOption } from 'echarts'
20
+
21
+ // 注册 ECharts 组件
22
+ use([TitleComponent, TooltipComponent, GridComponent, LegendComponent, BarChart, CanvasRenderer])
23
+
24
+ // 定义标准的 Props,不含任何业务逻辑 ID
25
+ const props = defineProps<{
26
+ // 基础数据 Props
27
+ data?: number[]
28
+ xAxisData?: string[]
29
+ seriesName?: string
30
+
31
+ // 样式配置 Props
32
+ title?: string
33
+ barColor?: string
34
+ barWidth?: string
35
+ borderRadius?: number | number[]
36
+ showTooltip?: boolean
37
+ showLegend?: boolean
38
+ legendPosition?: 'top' | 'bottom' | 'left' | 'right'
39
+ showGrid?: boolean
40
+ xAxisName?: string
41
+ yAxisName?: string
42
+ showXAxisLine?: boolean
43
+ showXAxisLabel?: boolean
44
+ showYAxisLine?: boolean
45
+ showYAxisLabel?: boolean
46
+ showLabel?: boolean
47
+
48
+ // 高级覆盖
49
+ option?: EChartsOption
50
+ }>()
51
+
52
+ // 默认值配置
53
+ const defaultData = [120, 200, 150, 180, 270, 210, 220]
54
+ const defaultXAxis = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
55
+
56
+ // 计算最终 Option
57
+ const finalOption = computed<EChartsOption>(() => {
58
+ // 如果有高级配置 option,优先使用
59
+ if (props.option && Object.keys(props.option).length > 0) return props.option
60
+
61
+ const data = props.data && props.data.length ? props.data : defaultData
62
+ const xAxisData = props.xAxisData && props.xAxisData.length ? props.xAxisData : defaultXAxis
63
+ const seriesName = props.seriesName || 'Series'
64
+
65
+ return {
66
+ // 标题
67
+ title: props.title
68
+ ? {
69
+ text: props.title,
70
+ left: 'center',
71
+ textStyle: {
72
+ fontSize: 16,
73
+ },
74
+ }
75
+ : undefined,
76
+
77
+ // 提示框
78
+ tooltip:
79
+ props.showTooltip !== false
80
+ ? {
81
+ trigger: 'axis',
82
+ axisPointer: {
83
+ type: 'shadow',
84
+ },
85
+ }
86
+ : undefined,
87
+
88
+ // 图例
89
+ legend:
90
+ props.showLegend !== false
91
+ ? {
92
+ [(props.legendPosition as string) || 'top']: 10,
93
+ data: [seriesName],
94
+ }
95
+ : undefined,
96
+
97
+ // 网格
98
+ grid: {
99
+ left: '6%',
100
+ right: '6%',
101
+ bottom: '8%',
102
+ top: props.title ? '15%' : '10%',
103
+ containLabel: true,
104
+ show: props.showGrid !== false,
105
+ },
106
+
107
+ // X 轴
108
+ xAxis: {
109
+ type: 'category',
110
+ data: xAxisData,
111
+ name: props.xAxisName || '',
112
+ nameLocation: 'middle',
113
+ nameGap: 30,
114
+ axisLine: {
115
+ show: props.showXAxisLine !== false,
116
+ },
117
+ axisLabel: {
118
+ show: props.showXAxisLabel !== false,
119
+ },
120
+ splitLine: {
121
+ show: false,
122
+ },
123
+ },
124
+
125
+ // Y 轴
126
+ yAxis: {
127
+ type: 'value',
128
+ name: props.yAxisName || '',
129
+ nameLocation: 'middle',
130
+ nameGap: 50,
131
+ axisLine: {
132
+ show: props.showYAxisLine !== false,
133
+ },
134
+ axisLabel: {
135
+ show: props.showYAxisLabel !== false,
136
+ },
137
+ splitLine: {
138
+ show: props.showGrid !== false,
139
+ },
140
+ },
141
+
142
+ // 系列
143
+ series: [
144
+ {
145
+ name: seriesName,
146
+ type: 'bar',
147
+ data: data,
148
+ barWidth: props.barWidth || '60%',
149
+ itemStyle: {
150
+ color: props.barColor || '#5470c6',
151
+ borderRadius: props.borderRadius || 0,
152
+ },
153
+ label: props.showLabel
154
+ ? {
155
+ show: true,
156
+ position: 'top',
157
+ fontSize: 12,
158
+ }
159
+ : undefined,
160
+ },
161
+ ],
162
+ }
163
+ })
164
+ </script>
165
+
166
+ <style scoped>
167
+ .v-bar-chart {
168
+ width: 100%;
169
+ height: 100%;
170
+ }
171
+
172
+ .echart {
173
+ width: 100%;
174
+ height: 100%;
175
+ }
176
+ </style>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div class="v-doughnut-chart" :style="{ width: '100%', height: '100%' }">
3
+ <v-chart :option="finalOption" autoresize class="echart" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { computed } from 'vue'
9
+ import { use } from 'echarts/core'
10
+ import { CanvasRenderer } from 'echarts/renderers'
11
+ import { PieChart } from 'echarts/charts'
12
+ import { TitleComponent, TooltipComponent, LegendComponent } from 'echarts/components'
13
+ import VChart from 'vue-echarts'
14
+ import type { EChartsOption } from 'echarts'
15
+
16
+ // 注册 ECharts 组件
17
+ use([TitleComponent, TooltipComponent, LegendComponent, PieChart, CanvasRenderer])
18
+
19
+ // 定义标准的 Props,不含任何业务逻辑 ID
20
+ const props = defineProps<{
21
+ // 基础数据 Props
22
+ data?: Array<{ name: string; value: number }>
23
+
24
+ // 样式配置 Props
25
+ title?: string
26
+ titleAlign?: 'left' | 'center' | 'right'
27
+ titleSize?: number
28
+ titleColor?: string
29
+ seriesName?: string
30
+ innerRadius?: string
31
+ outerRadius?: string
32
+ centerX?: string
33
+ centerY?: string
34
+ borderRadius?: number
35
+ borderColor?: string
36
+ borderWidth?: number
37
+ showLegend?: boolean
38
+ legendOrient?: 'horizontal' | 'vertical'
39
+ legendLeft?: string
40
+ legendTop?: string
41
+ showLabel?: boolean
42
+ labelFormatter?: string
43
+ showLabelLine?: boolean
44
+
45
+ // 高级覆盖
46
+ option?: EChartsOption
47
+ }>()
48
+
49
+ // 默认值配置
50
+ const defaultData = [
51
+ { name: 'Direct', value: 335 },
52
+ { name: 'Email', value: 310 },
53
+ { name: 'Union Ads', value: 234 },
54
+ { name: 'Video Ads', value: 135 },
55
+ { name: 'Search Engine', value: 1548 },
56
+ ]
57
+
58
+ // 计算最终 Option
59
+ const finalOption = computed<EChartsOption>(() => {
60
+ // 如果有高级配置 option,优先使用
61
+ if (props.option && Object.keys(props.option).length > 0) return props.option
62
+
63
+ const data = props.data && props.data.length ? props.data : defaultData
64
+ const seriesName = props.seriesName || 'Access From'
65
+
66
+ return {
67
+ title: {
68
+ text: props.title || '',
69
+ left: props.titleAlign || 'center',
70
+ textStyle: {
71
+ fontSize: props.titleSize || 16,
72
+ color: props.titleColor || '#333',
73
+ },
74
+ },
75
+ tooltip: {
76
+ trigger: 'item',
77
+ formatter: '{a} <br/>{b}: {c} ({d}%)',
78
+ },
79
+ legend: {
80
+ show: props.showLegend !== false,
81
+ orient: props.legendOrient || 'horizontal',
82
+ left: props.legendLeft || 'center',
83
+ top: props.legendTop || 'bottom',
84
+ },
85
+ series: [
86
+ {
87
+ name: seriesName,
88
+ type: 'pie',
89
+ radius: [props.innerRadius || '40%', props.outerRadius || '70%'],
90
+ center: [props.centerX || '50%', props.centerY || '50%'],
91
+ avoidLabelOverlap: false,
92
+ itemStyle: {
93
+ borderRadius: props.borderRadius || 10,
94
+ borderColor: props.borderColor || '#fff',
95
+ borderWidth: props.borderWidth || 2,
96
+ },
97
+ label: {
98
+ show: props.showLabel !== false,
99
+ formatter: props.labelFormatter || '{b}: {c}',
100
+ },
101
+ emphasis: {
102
+ label: {
103
+ show: true,
104
+ fontSize: 20,
105
+ fontWeight: 'bold',
106
+ },
107
+ },
108
+ labelLine: {
109
+ show: props.showLabelLine !== false,
110
+ },
111
+ data: data,
112
+ },
113
+ ],
114
+ }
115
+ })
116
+ </script>
117
+
118
+ <style scoped>
119
+ .v-doughnut-chart {
120
+ width: 100%;
121
+ height: 100%;
122
+ }
123
+
124
+ .echart {
125
+ width: 100%;
126
+ height: 100%;
127
+ }
128
+ </style>