168 lines
3.4 KiB
Vue
Raw Normal View History

2026-03-27 17:47:09 +08:00
<template>
<div class="ring-chart" ref="chartRef"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
chartData: {
type: Array,
default: () => [
{ name: '蓝色', value: 13, color: '#40a9ff' },
{ name: '橙色', value: 40.2, color: '#ff7a45' },
{ name: '黄色', value: 22, color: '#ffc53d' },
{ name: '红色', value: 8, color: '#ff4d4f' }
]
},
centerText: {
type: String,
default: '风险\n状况'
}
})
const chartRef = ref(null)
let chartInstance = null
const initChart = () => {
if (!chartRef.value) return
chartInstance = echarts.init(chartRef.value)
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%'
},
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
itemWidth: 10,
itemHeight: 10,
textStyle: {
color: '#fff',
fontSize: 12
},
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle'
}))
},
series: [
{
name: '风险状况',
type: 'pie',
radius: ['45%', '65%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{c}%',
color: '#fff',
fontSize: 12
},
labelLine: {
show: true,
length: 15,
length2: 10,
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color
}
}))
},
{
type: 'pie',
radius: ['0%', '35%'],
center: ['40%', '50%'],
silent: true,
label: {
show: true,
position: 'center',
formatter: props.centerText,
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
lineHeight: 24
},
data: [{ value: 1, name: '', itemStyle: { color: 'transparent' } }]
}
]
}
chartInstance.setOption(option)
}
const updateChart = () => {
if (!chartInstance) return
const option = {
legend: {
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle'
}))
},
series: [
{
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color
}
}))
},
{
label: {
formatter: props.centerText
}
}
]
}
chartInstance.setOption(option)
}
const handleResize = () => {
chartInstance?.resize()
}
onMounted(() => {
initChart()
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
chartInstance?.dispose()
})
watch(() => props.chartData, updateChart, { deep: true })
watch(() => props.centerText, updateChart)
</script>
<style lang="scss" scoped>
.ring-chart {
width: 100%;
height: 100%;
}
</style>