@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.
- package/README.md +152 -0
- package/dist/index.d.ts +696 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +11786 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +10 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/style.css +1 -0
- package/index.ts +150 -0
- package/package.json +73 -0
- package/src/components/advanced/scripting/Scripting.vue +189 -0
- package/src/components/advanced/state/State.vue +231 -0
- package/src/components/advanced/trigger/Trigger.vue +256 -0
- package/src/components/basic/button/Button.vue +120 -0
- package/src/components/basic/container/Container.vue +22 -0
- package/src/components/chart/barChart/barChart.vue +176 -0
- package/src/components/chart/doughnutChart/doughnutChart.vue +128 -0
- package/src/components/chart/funnelChart/funnelChart.vue +128 -0
- package/src/components/chart/gaugeChart/gaugeChart.vue +144 -0
- package/src/components/chart/lineChart/lineChart.vue +188 -0
- package/src/components/chart/pieChart/pieChart.vue +114 -0
- package/src/components/chart/radarChart/radarChart.vue +115 -0
- package/src/components/chart/sankeyChart/sankeyChart.vue +144 -0
- package/src/components/chart/scatterChart/scatterChart.vue +162 -0
- package/src/components/chart/stackedBarChart/stackedBarChart.vue +184 -0
- package/src/components/content/html/Html.vue +104 -0
- package/src/components/content/iframe/Iframe.vue +111 -0
- package/src/components/content/markdown/Markdown.vue +174 -0
- package/src/components/controls/breadcrumb/Breadcrumb.vue +79 -0
- package/src/components/controls/buttonGroup/ButtonGroup.vue +93 -0
- package/src/components/controls/checkboxGroup/CheckboxGroup.vue +147 -0
- package/src/components/controls/dateRange/DateRange.vue +174 -0
- package/src/components/controls/multiSelect/MultiSelect.vue +155 -0
- package/src/components/controls/navButton/NavButton.vue +97 -0
- package/src/components/controls/pagination/Pagination.vue +94 -0
- package/src/components/controls/searchBox/SearchBox.vue +170 -0
- package/src/components/controls/select/Select.vue +134 -0
- package/src/components/controls/slider/Slider.vue +167 -0
- package/src/components/controls/switch/Switch.vue +107 -0
- package/src/components/data/cardGrid/CardGrid.vue +318 -0
- package/src/components/data/list/List.vue +282 -0
- package/src/components/data/pivot/Pivot.vue +270 -0
- package/src/components/data/table/Table.vue +150 -0
- package/src/components/data/timeline/Timeline.vue +315 -0
- package/src/components/group/Group.vue +75 -0
- package/src/components/kpi/box/Box.vue +98 -0
- package/src/components/kpi/countUp/CountUp.vue +193 -0
- package/src/components/kpi/progress/Progress.vue +159 -0
- package/src/components/kpi/stat/Stat.vue +205 -0
- package/src/components/kpi/text/Text.vue +74 -0
- package/src/components/layout/badge/Badge.vue +105 -0
- package/src/components/layout/col/Col.vue +114 -0
- package/src/components/layout/flex/Flex.vue +105 -0
- package/src/components/layout/grid/Grid.vue +89 -0
- package/src/components/layout/modal/Modal.vue +118 -0
- package/src/components/layout/panel/Panel.vue +162 -0
- package/src/components/layout/row/Row.vue +99 -0
- package/src/components/layout/tabs/Tabs.vue +117 -0
- package/src/components/media/image/Image.vue +132 -0
- package/src/components/media/video/Video.vue +115 -0
- package/src/components/v2/basic/BaseButton.vue +179 -0
- package/src/components/v2/kpi/KpiCard.vue +215 -0
- package/src/components/v2/layout/GridBox.vue +55 -0
- package/src/hooks/useDataSource.ts +123 -0
- package/src/types/gis.ts +251 -0
- package/src/utils/chartUtils.ts +349 -0
- package/src/utils/dataUtils.ts +403 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="v-progress-container" :style="containerStyle">
|
|
3
|
+
<el-progress
|
|
4
|
+
:percentage="percentage"
|
|
5
|
+
:type="type"
|
|
6
|
+
:status="status"
|
|
7
|
+
:stroke-width="strokeWidth"
|
|
8
|
+
:text-inside="textInside"
|
|
9
|
+
:show-text="showText"
|
|
10
|
+
:color="computedColor"
|
|
11
|
+
:format="formatText"
|
|
12
|
+
:width="circleWidth"
|
|
13
|
+
:stroke-linecap="strokeLinecap"
|
|
14
|
+
:striped="showStripe"
|
|
15
|
+
:striped-flow="animateStripe"
|
|
16
|
+
class="custom-progress"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
import { computed } from 'vue'
|
|
23
|
+
import type { CSSProperties } from 'vue'
|
|
24
|
+
import { ElProgress } from 'element-plus'
|
|
25
|
+
|
|
26
|
+
// 颜色配置类型
|
|
27
|
+
interface ColorStop {
|
|
28
|
+
color: string
|
|
29
|
+
percentage: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 定义纯 UI Props,无业务逻辑
|
|
33
|
+
const props = withDefaults(
|
|
34
|
+
defineProps<{
|
|
35
|
+
// 核心数据
|
|
36
|
+
percentage?: number
|
|
37
|
+
type?: 'line' | 'circle' | 'dashboard'
|
|
38
|
+
status?: '' | 'success' | 'exception' | 'warning'
|
|
39
|
+
|
|
40
|
+
// 进度条配置
|
|
41
|
+
strokeWidth?: number
|
|
42
|
+
textInside?: boolean
|
|
43
|
+
showText?: boolean
|
|
44
|
+
showStripe?: boolean
|
|
45
|
+
animateStripe?: boolean
|
|
46
|
+
circleWidth?: number
|
|
47
|
+
strokeLinecap?: 'butt' | 'round' | 'square'
|
|
48
|
+
textFormat?: string
|
|
49
|
+
|
|
50
|
+
// 颜色配置
|
|
51
|
+
barColor?: string
|
|
52
|
+
trackColor?: string
|
|
53
|
+
textColor?: string
|
|
54
|
+
successColor?: string
|
|
55
|
+
warningColor?: string
|
|
56
|
+
exceptionColor?: string
|
|
57
|
+
useGradient?: boolean
|
|
58
|
+
|
|
59
|
+
// 容器样式
|
|
60
|
+
opacity?: number
|
|
61
|
+
visible?: boolean
|
|
62
|
+
backgroundColor?: string
|
|
63
|
+
borderColor?: string
|
|
64
|
+
borderWidth?: number
|
|
65
|
+
borderRadius?: number
|
|
66
|
+
padding?: number
|
|
67
|
+
}>(),
|
|
68
|
+
{
|
|
69
|
+
percentage: 0,
|
|
70
|
+
type: 'line',
|
|
71
|
+
status: '',
|
|
72
|
+
strokeWidth: 6,
|
|
73
|
+
textInside: false,
|
|
74
|
+
showText: true,
|
|
75
|
+
showStripe: false,
|
|
76
|
+
animateStripe: false,
|
|
77
|
+
circleWidth: 126,
|
|
78
|
+
strokeLinecap: 'round',
|
|
79
|
+
textFormat: '{value}%',
|
|
80
|
+
opacity: 100,
|
|
81
|
+
visible: true,
|
|
82
|
+
backgroundColor: 'transparent',
|
|
83
|
+
borderColor: 'transparent',
|
|
84
|
+
borderWidth: 0,
|
|
85
|
+
borderRadius: 0,
|
|
86
|
+
padding: 10,
|
|
87
|
+
barColor: '#409eff',
|
|
88
|
+
trackColor: '#e4e7ed',
|
|
89
|
+
textColor: '#606266',
|
|
90
|
+
},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// 计算颜色
|
|
94
|
+
const computedColor = computed<string | ColorStop[]>(() => {
|
|
95
|
+
const barColor = props.barColor
|
|
96
|
+
const successColor = props.successColor ?? '#67c23a'
|
|
97
|
+
const warningColor = props.warningColor ?? '#e6a23c'
|
|
98
|
+
const exceptionColor = props.exceptionColor ?? '#f56c6c'
|
|
99
|
+
|
|
100
|
+
// 根据状态返回对应颜色
|
|
101
|
+
if (props.status) {
|
|
102
|
+
if (props.status === 'success') return successColor
|
|
103
|
+
if (props.status === 'warning') return warningColor
|
|
104
|
+
if (props.status === 'exception') return exceptionColor
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 使用渐变色
|
|
108
|
+
if (props.useGradient) {
|
|
109
|
+
return [
|
|
110
|
+
{ color: exceptionColor, percentage: 20 },
|
|
111
|
+
{ color: warningColor, percentage: 50 },
|
|
112
|
+
{ color: successColor, percentage: 100 },
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return barColor
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// 格式化文本
|
|
120
|
+
const formatText = (percentage: number) => {
|
|
121
|
+
const format = props.textFormat
|
|
122
|
+
return format.replace('{value}', percentage.toFixed(0))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 容器样式
|
|
126
|
+
const containerStyle = computed<CSSProperties>(() => {
|
|
127
|
+
return {
|
|
128
|
+
opacity: props.opacity / 100,
|
|
129
|
+
display: props.visible === false ? 'none' : 'flex',
|
|
130
|
+
backgroundColor: props.backgroundColor,
|
|
131
|
+
borderColor: props.borderColor,
|
|
132
|
+
borderWidth: `${props.borderWidth}px`,
|
|
133
|
+
borderStyle: 'solid',
|
|
134
|
+
borderRadius: `${props.borderRadius}px`,
|
|
135
|
+
padding: `${props.padding}px`,
|
|
136
|
+
width: '100%',
|
|
137
|
+
height: '100%',
|
|
138
|
+
alignItems: 'center',
|
|
139
|
+
justifyContent: 'center',
|
|
140
|
+
boxSizing: 'border-box',
|
|
141
|
+
'--el-fill-color-light': props.trackColor, // Hack: Element Plus track color
|
|
142
|
+
} as CSSProperties
|
|
143
|
+
})
|
|
144
|
+
</script>
|
|
145
|
+
|
|
146
|
+
<style scoped>
|
|
147
|
+
.v-progress-container {
|
|
148
|
+
box-sizing: border-box;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:deep(.el-progress) {
|
|
152
|
+
width: 100%;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
:deep(.el-progress__text) {
|
|
156
|
+
font-size: inherit !important;
|
|
157
|
+
color: v-bind('props.textColor');
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="v-stat-card" :style="cardStyle">
|
|
3
|
+
<div class="v-stat-header">
|
|
4
|
+
<div class="v-stat-title" :style="titleStyleComputed">{{ title }}</div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="v-stat-body">
|
|
7
|
+
<div v-if="icon" class="v-stat-icon" :style="iconStyle">
|
|
8
|
+
<i :class="icon"></i>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="v-stat-value" :style="valueStyleComputed">{{ formattedValue }}{{ suffix }}</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div v-if="showChange && (change ?? 0) !== 0" class="v-stat-footer">
|
|
13
|
+
<span class="v-stat-change" :style="changeStyleComputed">
|
|
14
|
+
{{ (change ?? 0) > 0 ? '+' : '' }}{{ (change ?? 0).toFixed(1) }}%
|
|
15
|
+
</span>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { computed } from 'vue'
|
|
22
|
+
import type { CSSProperties } from 'vue'
|
|
23
|
+
|
|
24
|
+
// 定义纯 UI Props,无业务逻辑
|
|
25
|
+
const props = withDefaults(
|
|
26
|
+
defineProps<{
|
|
27
|
+
// 数据
|
|
28
|
+
title?: string
|
|
29
|
+
value?: number
|
|
30
|
+
change?: number
|
|
31
|
+
suffix?: string
|
|
32
|
+
icon?: string
|
|
33
|
+
precision?: number
|
|
34
|
+
showChange?: boolean
|
|
35
|
+
|
|
36
|
+
// 卡片样式
|
|
37
|
+
opacity?: number
|
|
38
|
+
visible?: boolean
|
|
39
|
+
backgroundColor?: string
|
|
40
|
+
borderColor?: string
|
|
41
|
+
borderWidth?: number
|
|
42
|
+
borderRadius?: number
|
|
43
|
+
boxShadow?: string
|
|
44
|
+
padding?: number
|
|
45
|
+
|
|
46
|
+
// 标题样式
|
|
47
|
+
titleColor?: string
|
|
48
|
+
titleFontSize?: number
|
|
49
|
+
titleFontWeight?: 'normal' | 'bold' | 'lighter' | number
|
|
50
|
+
|
|
51
|
+
// 数值样式
|
|
52
|
+
valueColor?: string
|
|
53
|
+
valueFontSize?: number
|
|
54
|
+
valueFontWeight?: 'normal' | 'bold' | 'lighter' | number
|
|
55
|
+
|
|
56
|
+
// 变化率样式
|
|
57
|
+
changeFontSize?: number
|
|
58
|
+
changeFontWeight?: 'normal' | 'bold' | 'lighter' | number
|
|
59
|
+
changeColorPositive?: string
|
|
60
|
+
changeColorNegative?: string
|
|
61
|
+
|
|
62
|
+
// 图标样式
|
|
63
|
+
iconColor?: string
|
|
64
|
+
iconSize?: number
|
|
65
|
+
}>(),
|
|
66
|
+
{
|
|
67
|
+
title: 'Statistic Title',
|
|
68
|
+
value: 0,
|
|
69
|
+
change: 0,
|
|
70
|
+
suffix: '',
|
|
71
|
+
icon: '',
|
|
72
|
+
precision: 0,
|
|
73
|
+
showChange: false,
|
|
74
|
+
opacity: 100,
|
|
75
|
+
visible: true,
|
|
76
|
+
backgroundColor: '#fff',
|
|
77
|
+
borderColor: '#e0e0e0',
|
|
78
|
+
borderWidth: 1,
|
|
79
|
+
borderRadius: 8,
|
|
80
|
+
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',
|
|
81
|
+
padding: 20,
|
|
82
|
+
titleColor: '#909399',
|
|
83
|
+
titleFontSize: 14,
|
|
84
|
+
titleFontWeight: 'normal',
|
|
85
|
+
valueColor: '#303133',
|
|
86
|
+
valueFontSize: 24,
|
|
87
|
+
valueFontWeight: 'bold',
|
|
88
|
+
changeFontSize: 14,
|
|
89
|
+
changeFontWeight: 500,
|
|
90
|
+
changeColorPositive: '#28a745',
|
|
91
|
+
changeColorNegative: '#dc3545',
|
|
92
|
+
iconColor: '#409eff',
|
|
93
|
+
iconSize: 32,
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
// 格式化显示值
|
|
98
|
+
const formattedValue = computed(() => {
|
|
99
|
+
const val = props.value
|
|
100
|
+
const prec = props.precision
|
|
101
|
+
return val.toLocaleString(undefined, {
|
|
102
|
+
minimumFractionDigits: prec,
|
|
103
|
+
maximumFractionDigits: prec,
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// 卡片样式
|
|
108
|
+
const cardStyle = computed<CSSProperties>(() => {
|
|
109
|
+
return {
|
|
110
|
+
opacity: props.opacity / 100,
|
|
111
|
+
display: props.visible === false ? 'none' : 'flex',
|
|
112
|
+
backgroundColor: props.backgroundColor,
|
|
113
|
+
borderColor: props.borderColor,
|
|
114
|
+
borderWidth: `${props.borderWidth}px`,
|
|
115
|
+
borderStyle: 'solid',
|
|
116
|
+
borderRadius: `${props.borderRadius}px`,
|
|
117
|
+
boxShadow: props.boxShadow,
|
|
118
|
+
padding: `${props.padding}px`,
|
|
119
|
+
flexDirection: 'column',
|
|
120
|
+
justifyContent: 'space-between',
|
|
121
|
+
width: '100%',
|
|
122
|
+
height: '100%',
|
|
123
|
+
boxSizing: 'border-box',
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// 标题样式
|
|
128
|
+
const titleStyleComputed = computed<CSSProperties>(() => {
|
|
129
|
+
return {
|
|
130
|
+
color: props.titleColor,
|
|
131
|
+
fontSize: `${props.titleFontSize}px`,
|
|
132
|
+
fontWeight: props.titleFontWeight,
|
|
133
|
+
margin: 0,
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// 数值样式
|
|
138
|
+
const valueStyleComputed = computed<CSSProperties>(() => {
|
|
139
|
+
return {
|
|
140
|
+
color: props.valueColor,
|
|
141
|
+
fontSize: `${props.valueFontSize}px`,
|
|
142
|
+
fontWeight: props.valueFontWeight,
|
|
143
|
+
lineHeight: 1,
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
// 变化率样式
|
|
148
|
+
const changeStyleComputed = computed<CSSProperties>(() => {
|
|
149
|
+
const changeVal = props.change
|
|
150
|
+
const color = changeVal > 0 ? props.changeColorPositive : props.changeColorNegative
|
|
151
|
+
return {
|
|
152
|
+
color,
|
|
153
|
+
fontSize: `${props.changeFontSize}px`,
|
|
154
|
+
fontWeight: props.changeFontWeight,
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// 图标样式
|
|
159
|
+
const iconStyle = computed<CSSProperties>(() => {
|
|
160
|
+
return {
|
|
161
|
+
fontSize: `${props.iconSize}px`,
|
|
162
|
+
color: props.iconColor,
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<style scoped>
|
|
168
|
+
.v-stat-card {
|
|
169
|
+
box-sizing: border-box;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.v-stat-header {
|
|
173
|
+
margin-bottom: 8px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.v-stat-title {
|
|
177
|
+
font-size: 14px;
|
|
178
|
+
color: #909399;
|
|
179
|
+
margin: 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.v-stat-body {
|
|
183
|
+
display: flex;
|
|
184
|
+
align-items: center;
|
|
185
|
+
gap: 12px;
|
|
186
|
+
flex: 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.v-stat-icon {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.v-stat-value {
|
|
195
|
+
line-height: 1;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.v-stat-footer {
|
|
199
|
+
margin-top: 8px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.v-stat-change {
|
|
203
|
+
font-weight: 500;
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="v-text" :style="textStyle">
|
|
3
|
+
{{ content }}
|
|
4
|
+
</div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
import type { CSSProperties } from 'vue'
|
|
10
|
+
|
|
11
|
+
// 定义纯 UI Props,无业务逻辑
|
|
12
|
+
const props = withDefaults(
|
|
13
|
+
defineProps<{
|
|
14
|
+
// 内容
|
|
15
|
+
content?: string
|
|
16
|
+
|
|
17
|
+
// 样式配置
|
|
18
|
+
fontSize?: number | string // 标准化类型
|
|
19
|
+
color?: string // 标准化命名:原 fontColor
|
|
20
|
+
fontWeight?: 'normal' | 'bold' | 'lighter' | number | string
|
|
21
|
+
textAlign?: 'left' | 'center' | 'right' | 'justify'
|
|
22
|
+
letterSpacing?: number | string
|
|
23
|
+
lineHeight?: number | string
|
|
24
|
+
paddingX?: number
|
|
25
|
+
paddingY?: number
|
|
26
|
+
opacity?: number
|
|
27
|
+
visible?: boolean
|
|
28
|
+
locked?: boolean
|
|
29
|
+
}>(),
|
|
30
|
+
{
|
|
31
|
+
content: '文本内容',
|
|
32
|
+
fontSize: 16,
|
|
33
|
+
color: '#000000',
|
|
34
|
+
fontWeight: 'normal',
|
|
35
|
+
textAlign: 'left',
|
|
36
|
+
letterSpacing: 0,
|
|
37
|
+
lineHeight: 1.2,
|
|
38
|
+
paddingX: 0,
|
|
39
|
+
paddingY: 0,
|
|
40
|
+
opacity: 100,
|
|
41
|
+
visible: true,
|
|
42
|
+
locked: false,
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
// 计算文本样式
|
|
47
|
+
const textStyle = computed<CSSProperties>(() => {
|
|
48
|
+
return {
|
|
49
|
+
opacity: props.opacity / 100,
|
|
50
|
+
display: props.visible === false ? 'none' : 'block',
|
|
51
|
+
fontSize: typeof props.fontSize === 'number' ? `${props.fontSize}px` : props.fontSize,
|
|
52
|
+
color: props.color,
|
|
53
|
+
fontWeight: props.fontWeight,
|
|
54
|
+
textAlign: props.textAlign,
|
|
55
|
+
letterSpacing:
|
|
56
|
+
typeof props.letterSpacing === 'number' ? `${props.letterSpacing}px` : props.letterSpacing,
|
|
57
|
+
lineHeight: props.lineHeight,
|
|
58
|
+
padding: `${props.paddingY}px ${props.paddingX}px`,
|
|
59
|
+
width: '100%',
|
|
60
|
+
height: '100%',
|
|
61
|
+
userSelect: props.locked ? 'none' : 'text',
|
|
62
|
+
pointerEvents: props.locked ? 'none' : 'auto',
|
|
63
|
+
overflow: 'hidden',
|
|
64
|
+
boxSizing: 'border-box',
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<style scoped>
|
|
70
|
+
.v-text {
|
|
71
|
+
word-break: break-word;
|
|
72
|
+
white-space: pre-wrap;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="v-badge-container" :style="containerStyle">
|
|
3
|
+
<el-badge
|
|
4
|
+
:value="value"
|
|
5
|
+
:type="type"
|
|
6
|
+
:is-dot="isDot"
|
|
7
|
+
:max="max"
|
|
8
|
+
:hidden="hidden"
|
|
9
|
+
:show-zero="showZero"
|
|
10
|
+
:offset="offset"
|
|
11
|
+
>
|
|
12
|
+
<slot>
|
|
13
|
+
<span :style="slotContentStyle">{{ slotText || 'Badge Content' }}</span>
|
|
14
|
+
</slot>
|
|
15
|
+
</el-badge>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { computed } from 'vue'
|
|
21
|
+
import type { CSSProperties } from 'vue'
|
|
22
|
+
import { ElBadge } from 'element-plus'
|
|
23
|
+
|
|
24
|
+
// 定义纯 UI Props,无业务逻辑
|
|
25
|
+
const props = withDefaults(
|
|
26
|
+
defineProps<{
|
|
27
|
+
// Badge 值
|
|
28
|
+
value?: string | number
|
|
29
|
+
type?: 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
|
30
|
+
isDot?: boolean
|
|
31
|
+
max?: number
|
|
32
|
+
hidden?: boolean
|
|
33
|
+
showZero?: boolean
|
|
34
|
+
offset?: [number, number]
|
|
35
|
+
|
|
36
|
+
// 默认插槽文本(当没有子组件时显示)
|
|
37
|
+
slotText?: string
|
|
38
|
+
|
|
39
|
+
// 容器样式
|
|
40
|
+
opacity?: number
|
|
41
|
+
visible?: boolean
|
|
42
|
+
padding?: number
|
|
43
|
+
|
|
44
|
+
// 插槽内容样式
|
|
45
|
+
slotFontSize?: number
|
|
46
|
+
slotColor?: string
|
|
47
|
+
slotPadding?: number
|
|
48
|
+
}>(),
|
|
49
|
+
{
|
|
50
|
+
value: '1',
|
|
51
|
+
type: 'primary',
|
|
52
|
+
isDot: false,
|
|
53
|
+
max: 99,
|
|
54
|
+
hidden: false,
|
|
55
|
+
showZero: false,
|
|
56
|
+
slotText: '徽章内容',
|
|
57
|
+
opacity: 100,
|
|
58
|
+
visible: true,
|
|
59
|
+
padding: 4,
|
|
60
|
+
slotFontSize: 14,
|
|
61
|
+
slotColor: '#303133',
|
|
62
|
+
slotPadding: 8,
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// 容器样式
|
|
67
|
+
const containerStyle = computed<CSSProperties>(() => {
|
|
68
|
+
return {
|
|
69
|
+
opacity: props.opacity / 100,
|
|
70
|
+
display: props.visible === false ? 'none' : 'inline-flex',
|
|
71
|
+
padding: `${props.padding}px`,
|
|
72
|
+
boxSizing: 'border-box',
|
|
73
|
+
alignItems: 'center',
|
|
74
|
+
justifyContent: 'center',
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// 插槽内容样式
|
|
79
|
+
const slotContentStyle = computed<CSSProperties>(() => {
|
|
80
|
+
return {
|
|
81
|
+
fontSize: `${props.slotFontSize}px`,
|
|
82
|
+
color: props.slotColor,
|
|
83
|
+
padding: `${props.slotPadding}px`,
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<style scoped>
|
|
89
|
+
.v-badge-container {
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
box-sizing: border-box;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:deep(.el-badge) {
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
:deep(.el-badge__content) {
|
|
103
|
+
font-size: inherit !important;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<el-col
|
|
3
|
+
:span="span"
|
|
4
|
+
:offset="offset"
|
|
5
|
+
:push="push"
|
|
6
|
+
:pull="pull"
|
|
7
|
+
:xs="xs"
|
|
8
|
+
:sm="sm"
|
|
9
|
+
:md="md"
|
|
10
|
+
:lg="lg"
|
|
11
|
+
:xl="xl"
|
|
12
|
+
:tag="tag"
|
|
13
|
+
:style="containerStyle"
|
|
14
|
+
class="v-col"
|
|
15
|
+
>
|
|
16
|
+
<slot>
|
|
17
|
+
<div class="v-col-placeholder" :style="placeholderStyle">
|
|
18
|
+
{{ placeholder }}
|
|
19
|
+
</div>
|
|
20
|
+
</slot>
|
|
21
|
+
</el-col>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
import { computed } from 'vue'
|
|
26
|
+
import type { CSSProperties } from 'vue'
|
|
27
|
+
import { ElCol } from 'element-plus'
|
|
28
|
+
|
|
29
|
+
// 响应式尺寸类型
|
|
30
|
+
type ResponsiveSize = number | { span?: number; offset?: number; push?: number; pull?: number }
|
|
31
|
+
|
|
32
|
+
// 定义纯 UI Props
|
|
33
|
+
const props = withDefaults(
|
|
34
|
+
defineProps<{
|
|
35
|
+
// Col 布局属性
|
|
36
|
+
span?: number
|
|
37
|
+
offset?: number
|
|
38
|
+
push?: number
|
|
39
|
+
pull?: number
|
|
40
|
+
xs?: ResponsiveSize
|
|
41
|
+
sm?: ResponsiveSize
|
|
42
|
+
md?: ResponsiveSize
|
|
43
|
+
lg?: ResponsiveSize
|
|
44
|
+
xl?: ResponsiveSize
|
|
45
|
+
tag?: string
|
|
46
|
+
|
|
47
|
+
// 容器样式
|
|
48
|
+
padding?: number
|
|
49
|
+
backgroundColor?: string
|
|
50
|
+
borderRadius?: number
|
|
51
|
+
borderWidth?: number
|
|
52
|
+
borderColor?: string
|
|
53
|
+
minHeight?: string
|
|
54
|
+
|
|
55
|
+
// 占位文本
|
|
56
|
+
placeholder?: string
|
|
57
|
+
textColor?: string
|
|
58
|
+
fontSize?: number
|
|
59
|
+
}>(),
|
|
60
|
+
{
|
|
61
|
+
span: 24,
|
|
62
|
+
offset: 0,
|
|
63
|
+
push: 0,
|
|
64
|
+
pull: 0,
|
|
65
|
+
tag: 'div',
|
|
66
|
+
padding: 0,
|
|
67
|
+
backgroundColor: 'transparent',
|
|
68
|
+
borderRadius: 0,
|
|
69
|
+
borderWidth: 0,
|
|
70
|
+
borderColor: '#dcdfe6',
|
|
71
|
+
minHeight: 'auto',
|
|
72
|
+
placeholder: '列布局容器 - 可拖入其他组件',
|
|
73
|
+
textColor: '#909399',
|
|
74
|
+
fontSize: 14,
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
// 容器样式
|
|
79
|
+
const containerStyle = computed<CSSProperties>(() => {
|
|
80
|
+
return {
|
|
81
|
+
padding: `${props.padding}px`,
|
|
82
|
+
backgroundColor: props.backgroundColor,
|
|
83
|
+
borderRadius: `${props.borderRadius}px`,
|
|
84
|
+
borderWidth: `${props.borderWidth}px`,
|
|
85
|
+
borderStyle: props.borderWidth ? 'solid' : 'none',
|
|
86
|
+
borderColor: props.borderColor,
|
|
87
|
+
minHeight: props.minHeight,
|
|
88
|
+
boxSizing: 'border-box',
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// 占位样式
|
|
93
|
+
const placeholderStyle = computed<CSSProperties>(() => {
|
|
94
|
+
return {
|
|
95
|
+
width: '100%',
|
|
96
|
+
minHeight: '50px',
|
|
97
|
+
display: 'flex',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
justifyContent: 'center',
|
|
100
|
+
color: props.textColor,
|
|
101
|
+
fontSize: `${props.fontSize}px`,
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style scoped>
|
|
107
|
+
.v-col {
|
|
108
|
+
box-sizing: border-box;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.v-col-placeholder {
|
|
112
|
+
width: 100%;
|
|
113
|
+
}
|
|
114
|
+
</style>
|