303 lines
9.0 KiB
Vue
303 lines
9.0 KiB
Vue
<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> |