This commit is contained in:
2025-07-15 18:02:29 +08:00
parent 2038ddc617
commit d636050aac
65 changed files with 17885 additions and 103 deletions
+109
View File
@@ -0,0 +1,109 @@
<template>
<BaseEChart :options="chartOptions" v-bind="$attrs" />
</template>
<script setup>
import { computed } from 'vue'
import BaseEChart from './BaseEChart.vue'
defineOptions({
name: 'BarChart'
})
const props = defineProps({
// 数据项
data: {
type: Array,
required: true
},
// x轴数据
xAxis: {
type: Array,
required: true
},
// 是否显示背景
showBackground: {
type: Boolean,
default: true
},
// 系列配置
series: {
type: Array,
default: () => []
},
// 图表标题
title: {
type: String,
default: ''
},
// 柱子宽度
barWidth: {
type: Number,
default: 30
}
})
const chartOptions = computed(() => {
const series = props.series.length > 0 ? props.series : [{
name: '数值',
data: props.data,
type: 'bar',
barWidth: props.barWidth,
showBackground: props.showBackground,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.1)'
},
itemStyle: {
borderRadius: [4, 4, 0, 0]
}
}]
return {
title: props.title ? {
text: props.title,
left: 'center',
top: 10
} : null,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
top: props.title ? '60px' : '40px',
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: props.xAxis,
axisLine: {
lineStyle: {
color: '#E5E7EB'
}
},
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
color: '#E5E7EB'
}
},
axisLine: {
show: false
},
axisTick: {
show: false
}
},
series
}
})
</script>
+88
View File
@@ -0,0 +1,88 @@
<template>
<div ref="chartRef" :style="{ width: width, height: height }" class="chart-container"></div>
</template>
<script setup name="BaseEChart">
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as echarts from 'echarts'
import { useElementSize, useResizeObserver } from '@vueuse/core'
defineOptions({
name: 'BaseEChart'
})
const props = defineProps({
options: {
type: Object,
required: true
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
theme: {
type: String,
default: ''
}
})
const chartRef = ref(null)
let chartInstance = null
// 初始化图表
const initChart = () => {
if (chartInstance) {
chartInstance.dispose()
}
if (!chartRef.value) return
chartInstance = echarts.init(chartRef.value, props.theme)
chartInstance.setOption(props.options)
}
// 监听容器大小变化
useResizeObserver(chartRef, () => {
if (chartInstance) {
chartInstance.resize()
}
})
// 监听配置变化
watch(
() => props.options,
(newOptions) => {
if (chartInstance) {
chartInstance.setOption(newOptions)
}
},
{ deep: true }
)
onMounted(() => {
initChart()
})
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.dispose()
chartInstance = null
}
})
// 暴露更新方法
defineExpose({
getChart: () => chartInstance,
resize: () => chartInstance?.resize()
})
</script>
<style scoped>
.chart-container {
position: relative;
}
</style>
+109
View File
@@ -0,0 +1,109 @@
<template>
<BaseEChart :options="chartOptions" v-bind="$attrs" />
</template>
<script setup>
import { computed } from 'vue'
import BaseEChart from './BaseEChart.vue'
defineOptions({
name: 'LineChart'
})
const props = defineProps({
// 数据项
data: {
type: Array,
required: true
},
// x轴数据
xAxis: {
type: Array,
required: true
},
// 是否平滑曲线
smooth: {
type: Boolean,
default: true
},
// 是否显示面积
area: {
type: Boolean,
default: false
},
// 系列配置
series: {
type: Array,
default: () => []
},
// 图表标题
title: {
type: String,
default: ''
}
})
const chartOptions = computed(() => {
const series = props.series.length > 0 ? props.series : [{
name: '数值',
data: props.data,
type: 'line',
smooth: props.smooth,
areaStyle: props.area ? {} : null,
showSymbol: true,
symbolSize: 6,
lineStyle: {
width: 2
}
}]
return {
title: props.title ? {
text: props.title,
left: 'center',
top: 10
} : null,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
grid: {
top: props.title ? '60px' : '40px',
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: props.xAxis,
axisLine: {
lineStyle: {
color: '#E5E7EB'
}
},
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
color: '#E5E7EB'
}
},
axisLine: {
show: false
},
axisTick: {
show: false
}
},
series
}
})
</script>
+88
View File
@@ -0,0 +1,88 @@
<template>
<BaseEChart :options="chartOptions" v-bind="$attrs" />
</template>
<script setup>
import { computed } from 'vue'
import BaseEChart from './BaseEChart.vue'
defineOptions({
name: 'PieChart'
})
const props = defineProps({
// 数据项 [{name: '名称', value: 100}]
data: {
type: Array,
required: true
},
// 是否显示为环形图
ring: {
type: Boolean,
default: false
},
// 图表标题
title: {
type: String,
default: ''
},
// 半径设置
radius: {
type: [String, Array],
default: '70%'
},
// 是否显示图例
showLegend: {
type: Boolean,
default: true
},
// 图例位置
legendPosition: {
type: String,
default: 'right' // 'right', 'bottom'
}
})
const chartOptions = computed(() => {
return {
title: props.title ? {
text: props.title,
left: 'center',
top: 10
} : null,
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: props.showLegend ? {
orient: props.legendPosition === 'right' ? 'vertical' : 'horizontal',
[props.legendPosition]: '5%',
top: props.legendPosition === 'right' ? 'middle' : 'bottom',
itemWidth: 10,
itemHeight: 10,
icon: 'circle'
} : undefined,
series: [
{
name: props.title || '数据占比',
type: 'pie',
radius: props.ring ? ['50%', '70%'] : props.radius,
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 4,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: '{b}: {d}%'
},
labelLine: {
show: true
},
data: props.data
}
]
}
})
</script>