f
This commit is contained in:
303
src/components/GaugeChart.vue
Normal file
303
src/components/GaugeChart.vue
Normal file
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="px-4 text-sm text-gray-500">
|
||||
分析指数是根据网络行为大数据出具的分析评估参考分数,分数越高越好。该指数仅对本报告有效,不代表对报告查询人的综合定性评价。
|
||||
</div>
|
||||
<div ref="chartRef" :style="{ width: '100%', height: '200px' }"></div>
|
||||
<div class="risk-description">
|
||||
{{ riskDescription }}
|
||||
</div>
|
||||
<div class="risk-legend mt-6">
|
||||
<div v-for="item in legendItems" :key="item.level" class="risk-legend__item">
|
||||
<span class="risk-legend__pill" :style="{ backgroundColor: item.color, color: item.textColor }">
|
||||
{{ item.range }}
|
||||
</span>
|
||||
<span class="risk-legend__text">{{ item.level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { ref, onMounted, onUnmounted, watch, computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
score: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 根据分数计算风险等级和颜色(分数越高越安全)
|
||||
const riskLevel = computed(() => {
|
||||
const score = props.score;
|
||||
if (score >= 75 && score <= 100) {
|
||||
return {
|
||||
level: "无任何风险",
|
||||
color: "#52c41a",
|
||||
gradient: [
|
||||
{ offset: 0, color: "#52c41a" },
|
||||
{ offset: 1, color: "#7fdb42" }
|
||||
]
|
||||
};
|
||||
} else if (score >= 50 && score < 75) {
|
||||
return {
|
||||
level: "风险指数较低",
|
||||
color: "#faad14",
|
||||
gradient: [
|
||||
{ offset: 0, color: "#faad14" },
|
||||
{ offset: 1, color: "#ffc53d" }
|
||||
]
|
||||
};
|
||||
} else if (score >= 25 && score < 50) {
|
||||
return {
|
||||
level: "风险指数较高",
|
||||
color: "#fa8c16",
|
||||
gradient: [
|
||||
{ offset: 0, color: "#fa8c16" },
|
||||
{ offset: 1, color: "#ffa940" }
|
||||
]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
level: "高风险警告",
|
||||
color: "#f5222d",
|
||||
gradient: [
|
||||
{ offset: 0, color: "#f5222d" },
|
||||
{ offset: 1, color: "#ff4d4f" }
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 评分解释文本(分数越高越安全)
|
||||
const riskDescription = computed(() => {
|
||||
const score = props.score;
|
||||
if (score >= 75 && score <= 100) {
|
||||
return "根据综合分析,当前报告未检测到明显风险因素,各项指标表现正常,总体状况良好。";
|
||||
} else if (score >= 50 && score < 75) {
|
||||
return "根据综合分析,当前报告存在少量风险信号,建议关注相关指标变化,保持警惕。";
|
||||
} else if (score >= 25 && score < 50) {
|
||||
return "根据综合分析,当前报告风险指数较高,多项指标显示异常,建议进一步核实相关情况。";
|
||||
} else {
|
||||
return "根据综合分析,当前报告显示高度风险状态,多项重要指标严重异常,请立即采取相应措施。";
|
||||
}
|
||||
});
|
||||
|
||||
const chartRef = ref(null);
|
||||
let chartInstance = null;
|
||||
|
||||
const legendItems = [
|
||||
{ level: "高风险", color: "#f5222d", range: "0-24", textColor: "#ffffff" },
|
||||
{ level: "一般", color: "#fa8c16", range: "25-49", textColor: "#ffffff" },
|
||||
{ level: "良好", color: "#faad14", range: "50-74", textColor: "#ffffff" },
|
||||
{ level: "优秀", color: "#52c41a", range: "75-100", textColor: "#ffffff" }
|
||||
];
|
||||
|
||||
const initChart = () => {
|
||||
if (!chartRef.value) return;
|
||||
|
||||
// 初始化ECharts实例
|
||||
chartInstance = echarts.init(chartRef.value);
|
||||
updateChart();
|
||||
};
|
||||
|
||||
const updateChart = () => {
|
||||
if (!chartInstance) return;
|
||||
|
||||
// 获取当前风险等级信息
|
||||
const risk = riskLevel.value;
|
||||
|
||||
// 配置项
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: "gauge",
|
||||
startAngle: 180,
|
||||
endAngle: 0,
|
||||
min: 0,
|
||||
max: 100,
|
||||
radius: "100%",
|
||||
center: ["50%", "80%"],
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, risk.gradient),
|
||||
shadowBlur: 6,
|
||||
shadowColor: risk.color,
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
width: 20,
|
||||
roundCap: true,
|
||||
clip: false
|
||||
},
|
||||
axisLine: {
|
||||
roundCap: true,
|
||||
lineStyle: {
|
||||
width: 20,
|
||||
color: [
|
||||
[1, new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{
|
||||
offset: 0,
|
||||
color: risk.color + "30" // 使用风险颜色,透明度20%
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: risk.color + "25" // 使用风险颜色,透明度10%
|
||||
}
|
||||
])]
|
||||
]
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: true,
|
||||
distance: -30,
|
||||
length: 6,
|
||||
splitNumber: 10, // 每1分一个小刻度
|
||||
lineStyle: {
|
||||
color: risk.color,
|
||||
width: 1,
|
||||
opacity: 0.5
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
distance: -36,
|
||||
length: 12,
|
||||
splitNumber: 9, // 9个大刻度,100分分成9个区间
|
||||
lineStyle: {
|
||||
color: risk.color,
|
||||
width: 2,
|
||||
opacity: 0.5
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
anchor: {
|
||||
show: false
|
||||
},
|
||||
pointer: {
|
||||
icon: "triangle",
|
||||
iconStyle: {
|
||||
color: risk.color,
|
||||
borderColor: risk.color,
|
||||
borderWidth: 1
|
||||
},
|
||||
offsetCenter: ["7%", "-67%"],
|
||||
length: "10%",
|
||||
width: 15
|
||||
},
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
fontSize: 30,
|
||||
fontWeight: "bold",
|
||||
color: risk.color,
|
||||
offsetCenter: [0, "-25%"],
|
||||
formatter: function (value) {
|
||||
return `{value|${value}分}\n{level|${risk.level}}`;
|
||||
},
|
||||
rich: {
|
||||
value: {
|
||||
fontSize: 30,
|
||||
fontWeight: 'bold',
|
||||
color: risk.color,
|
||||
padding: [0, 0, 5, 0]
|
||||
},
|
||||
level: {
|
||||
fontSize: 14,
|
||||
fontWeight: 'normal',
|
||||
color: risk.color,
|
||||
padding: [5, 0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: props.score
|
||||
}
|
||||
],
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: risk.color,
|
||||
offsetCenter: [0, "10%"],
|
||||
formatter: risk.level
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// 使用配置项设置图表
|
||||
chartInstance.setOption(option);
|
||||
};
|
||||
|
||||
// 监听分数变化
|
||||
watch(
|
||||
() => props.score,
|
||||
() => {
|
||||
updateChart();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
|
||||
// 处理窗口大小变化
|
||||
window.addEventListener("resize", () => {
|
||||
if (chartInstance) {
|
||||
chartInstance.resize();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 在组件销毁前清理
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
chartInstance = null;
|
||||
}
|
||||
window.removeEventListener("resize", chartInstance?.resize);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.risk-description {
|
||||
margin-bottom: 4px;
|
||||
padding: 0 12px;
|
||||
color: #666666;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
.risk-legend {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 0 16px 12px;
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.risk-legend__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.risk-legend__pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 12px;
|
||||
border-radius: 9999px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
min-width: 64px;
|
||||
}
|
||||
|
||||
.risk-legend__text {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user