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';
2026-03-27 17:47:09 +08:00
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' },
],
2026-03-27 17:47:09 +08:00
},
centerText: {
type: String,
default: '风险\n状况',
},
});
2026-03-27 17:47:09 +08:00
const chartRef = ref(null);
let chartInstance = null;
2026-03-27 17:47:09 +08:00
const initChart = () => {
if (!chartRef.value) return;
2026-03-27 17:47:09 +08:00
chartInstance = echarts.init(chartRef.value);
2026-03-27 17:47:09 +08:00
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
formatter: '{b}: {c}%',
2026-03-27 17:47:09 +08:00
},
legend: {
orient: 'vertical',
right: '5%',
top: 'center',
itemWidth: 10,
itemHeight: 10,
textStyle: {
color: '#fff',
fontSize: 12,
2026-03-27 17:47:09 +08:00
},
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle',
})),
2026-03-27 17:47:09 +08:00
},
series: [
{
name: '风险状况',
type: 'pie',
radius: ['45%', '65%'],
center: ['40%', '50%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{c}%',
color: '#fff',
fontSize: 12,
2026-03-27 17:47:09 +08:00
},
labelLine: {
show: true,
length: 15,
length2: 10,
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)',
},
2026-03-27 17:47:09 +08:00
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold',
},
2026-03-27 17:47:09 +08:00
},
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color,
},
})),
2026-03-27 17:47:09 +08:00
},
{
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,
2026-03-27 17:47:09 +08:00
},
data: [{ value: 1, name: '', itemStyle: { color: 'transparent' } }],
},
],
};
2026-03-27 17:47:09 +08:00
chartInstance.setOption(option);
};
2026-03-27 17:47:09 +08:00
const updateChart = () => {
if (!chartInstance) return;
2026-03-27 17:47:09 +08:00
const option = {
legend: {
data: props.chartData.map(item => ({
name: item.name,
icon: 'circle',
})),
2026-03-27 17:47:09 +08:00
},
series: [
{
data: props.chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: {
color: item.color,
},
})),
2026-03-27 17:47:09 +08:00
},
{
label: {
formatter: props.centerText,
},
},
],
};
2026-03-27 17:47:09 +08:00
chartInstance.setOption(option);
};
2026-03-27 17:47:09 +08:00
const handleResize = () => {
chartInstance?.resize();
};
2026-03-27 17:47:09 +08:00
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
});
2026-03-27 17:47:09 +08:00
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
2026-03-27 17:47:09 +08:00
watch(() => props.chartData, updateChart, { deep: true });
watch(() => props.centerText, updateChart);
2026-03-27 17:47:09 +08:00
</script>
<style lang="scss" scoped>
.ring-chart {
width: 100%;
height: 100%;
}
</style>