border_Inspection/web/src/components/AlgorithmStats.vue
2025-08-06 15:56:07 +08:00

190 lines
4.3 KiB
Vue

<template>
<div class="radar-chart-container">
<dv-border-box-10 class="border-box">
<div class="chart-title">算法命中率统计</div>
<div ref="radarChart" class="chart"></div>
</dv-border-box-10>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'
const props = defineProps({
algorithmTypes: {
type: Array,
default: () => []
}
})
const radarChart = ref(null)
let chartInstance = null
// 颜色数组
const colors = [
{ line: '#A020F0', area: 'rgba(160, 32, 240, 0.2)' }, // 紫色
{ line: '#1E90FF', area: 'rgba(30, 144, 255, 0.2)' }, // 蓝色
{ line: '#FF6347', area: 'rgba(255, 99, 71, 0.2)' }, // 红色
{ line: '#32CD32', area: 'rgba(50, 205, 50, 0.2)' }, // 绿色
{ line: '#FFD700', area: 'rgba(255, 215, 0, 0.2)' } // 金色
]
const initChart = () => {
if (!radarChart.value) return
chartInstance = echarts.init(radarChart.value)
// 固定雷达图维度
const indicators = [
{ name: '命中率', max: 100 },
{ name: '误报率', max: 100 },
{ name: '触发器', max: 100 },
{ name: '处理时延', max: 100 },
{ name: '稳定性', max: 100 }
]
// 根据算法类型生成系列数据
const seriesData = props.algorithmTypes.map((item, index) => {
// 计算各维度值
const values = [
item.accuracy, // 命中率 = 准确率
100 - item.accuracy, // 误报率 = 100 - 准确率
Math.min(100, item.count), // 触发器 = count * 15 (最大100)
100 - Math.round(item.accuracy / 1.5), // 处理时延 = 反比于准确率
90 + Math.round(item.accuracy / 10) // 稳定性 = 90 + 准确率/10
]
const colorIndex = index % colors.length
return {
value: values,
name: item.type,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: colors[colorIndex].line
},
itemStyle: {
color: colors[colorIndex].line,
borderWidth: 1,
borderColor: '#fff'
},
areaStyle: {
color: colors[colorIndex].area
}
}
})
const radarOption = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0,0,0,0.8)',
borderColor: 'rgba(124, 208, 255, 0.8)',
borderWidth: 1,
textStyle: {
color: '#fff',
fontSize: 12
},
formatter: params => {
return `
<div style="font-weight:bold">${params.name}</div>
<div>命中率: ${params.value[0].toFixed(1)}%</div>
<div>误报率: ${params.value[1].toFixed(1)}%</div>
<div>触发器: ${params.value[2].toFixed(0)}</div>
<div>处理时延: ${params.value[3].toFixed(0)}ms</div>
<div>稳定性: ${params.value[4].toFixed(0)}%</div>
`
}
},
legend: {
data: props.algorithmTypes.map(item => item.type),
bottom: 10,
textStyle: {
color: '#fff',
fontSize: 12
},
itemWidth: 12,
itemHeight: 8,
itemGap: 20
},
radar: {
indicator: indicators,
radius: '65%',
axisName: {
color: 'rgba(124, 208, 255, 0.8)',
fontSize: 12,
padding: [3, 5]
},
splitLine: {
lineStyle: {
color: 'rgba(124, 208, 255, 0.2)',
width: 1
}
},
axisLine: {
lineStyle: {
color: 'rgba(124, 208, 255, 0.5)',
width: 1
}
},
splitArea: {
show: false
}
},
series: [{
type: 'radar',
data: seriesData
}]
}
chartInstance.setOption(radarOption)
}
onMounted(() => {
initChart()
window.addEventListener('resize', () => {
chartInstance && chartInstance.resize()
})
})
watch(() => props.algorithmTypes, () => {
if (chartInstance) {
initChart()
}
}, { deep: true })
</script>
<style scoped>
.radar-chart-container {
width: 100%;
height: 40vh;
padding: 15px 30px;
box-sizing: border-box;
}
.border-box {
width: 100%;
height: 100%;
border-radius: 4px;
box-sizing: border-box;
}
.chart-title {
font-size: 16px;
color: #7cd0ff;
text-align: center;
padding-top: 15px;
font-weight: 500;
letter-spacing: 1px;
}
.chart {
width: 100%;
height: calc(100% - 30px);
padding: 20px;
}
</style>