2026-03-27 17:47:09 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="ring-chart" ref="chartRef"></div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-04-21 15:34:43 +08:00
|
|
|
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' },
|
2026-04-21 15:34:43 +08:00
|
|
|
{ name: '红色', value: 8, color: '#ff4d4f' },
|
|
|
|
|
],
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
centerText: {
|
|
|
|
|
type: String,
|
2026-04-21 15:34:43 +08:00
|
|
|
default: '风险\n状况',
|
|
|
|
|
},
|
|
|
|
|
});
|
2026-03-27 17:47:09 +08:00
|
|
|
|
2026-04-21 15:34:43 +08:00
|
|
|
const chartRef = ref(null);
|
|
|
|
|
let chartInstance = null;
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
const initChart = () => {
|
2026-04-21 15:34:43 +08:00
|
|
|
if (!chartRef.value) return;
|
2026-03-27 17:47:09 +08:00
|
|
|
|
2026-04-21 15:34:43 +08:00
|
|
|
chartInstance = echarts.init(chartRef.value);
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
tooltip: {
|
|
|
|
|
trigger: 'item',
|
2026-04-21 15:34:43 +08:00
|
|
|
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',
|
2026-04-21 15:34:43 +08:00
|
|
|
fontSize: 12,
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
data: props.chartData.map(item => ({
|
|
|
|
|
name: item.name,
|
2026-04-21 15:34:43 +08:00
|
|
|
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',
|
2026-04-21 15:34:43 +08:00
|
|
|
fontSize: 12,
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
labelLine: {
|
|
|
|
|
show: true,
|
|
|
|
|
length: 15,
|
|
|
|
|
length2: 10,
|
|
|
|
|
lineStyle: {
|
2026-04-21 15:34:43 +08:00
|
|
|
color: 'rgba(255, 255, 255, 0.3)',
|
|
|
|
|
},
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
emphasis: {
|
|
|
|
|
label: {
|
|
|
|
|
show: true,
|
|
|
|
|
fontSize: 14,
|
2026-04-21 15:34:43 +08:00
|
|
|
fontWeight: 'bold',
|
|
|
|
|
},
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
data: props.chartData.map(item => ({
|
|
|
|
|
value: item.value,
|
|
|
|
|
name: item.name,
|
|
|
|
|
itemStyle: {
|
2026-04-21 15:34:43 +08:00
|
|
|
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',
|
2026-04-21 15:34:43 +08:00
|
|
|
lineHeight: 24,
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
2026-04-21 15:34:43 +08:00
|
|
|
data: [{ value: 1, name: '', itemStyle: { color: 'transparent' } }],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
2026-03-27 17:47:09 +08:00
|
|
|
|
2026-04-21 15:34:43 +08:00
|
|
|
chartInstance.setOption(option);
|
|
|
|
|
};
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
const updateChart = () => {
|
2026-04-21 15:34:43 +08:00
|
|
|
if (!chartInstance) return;
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
legend: {
|
|
|
|
|
data: props.chartData.map(item => ({
|
|
|
|
|
name: item.name,
|
2026-04-21 15:34:43 +08:00
|
|
|
icon: 'circle',
|
|
|
|
|
})),
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
data: props.chartData.map(item => ({
|
|
|
|
|
value: item.value,
|
|
|
|
|
name: item.name,
|
|
|
|
|
itemStyle: {
|
2026-04-21 15:34:43 +08:00
|
|
|
color: item.color,
|
|
|
|
|
},
|
|
|
|
|
})),
|
2026-03-27 17:47:09 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: {
|
2026-04-21 15:34:43 +08:00
|
|
|
formatter: props.centerText,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
2026-03-27 17:47:09 +08:00
|
|
|
|
2026-04-21 15:34:43 +08:00
|
|
|
chartInstance.setOption(option);
|
|
|
|
|
};
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
const handleResize = () => {
|
2026-04-21 15:34:43 +08:00
|
|
|
chartInstance?.resize();
|
|
|
|
|
};
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
onMounted(() => {
|
2026-04-21 15:34:43 +08:00
|
|
|
initChart();
|
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
|
});
|
2026-03-27 17:47:09 +08:00
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
2026-04-21 15:34:43 +08:00
|
|
|
window.removeEventListener('resize', handleResize);
|
|
|
|
|
chartInstance?.dispose();
|
|
|
|
|
});
|
2026-03-27 17:47:09 +08:00
|
|
|
|
2026-04-21 15:34:43 +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>
|