态势感知中心-全球开源风险态势感知中心编程语言安全态势组件抽离
This commit is contained in:
213
src/views/Jyh/security/components/ScatterChart.vue
Normal file
213
src/views/Jyh/security/components/ScatterChart.vue
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<template>
|
||||||
|
<div class="index-module__NV_5cW__chartCard mb-[1.5rem]">
|
||||||
|
<h3 class="chartCard__title">编程语言安全态势</h3>
|
||||||
|
<div class="chartCard__container">
|
||||||
|
<div class="num-empty" v-if="isEmpty.scatterData"></div>
|
||||||
|
<div v-else id="scatterChart" class="chart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, nextTick, onMounted, onUnmounted } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
|
||||||
|
// 空数据标识
|
||||||
|
const isEmpty = ref({
|
||||||
|
scatterData: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// 图表实例存储(用于resize时销毁重绘)
|
||||||
|
const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
||||||
|
scatterChart: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// 气泡图数据
|
||||||
|
const scatterData = {
|
||||||
|
// 基于真实数据:[代码活跃度(X), 漏洞密度(Y), 漏洞总数(Size), 语言名称(Name)]
|
||||||
|
// 活跃度基于新增项目数量,漏洞密度基于CWE分布统计
|
||||||
|
scatterData: [
|
||||||
|
[95, 75, 450, 'JavaScript'], // 最高活跃度:9,345,046个项目
|
||||||
|
[90, 70, 380, 'Python'], // 高活跃度:9,261,587个项目
|
||||||
|
[85, 65, 320, 'TypeScript'], // 高增长:78.1%增长率
|
||||||
|
[75, 80, 420, 'Java'], // 传统强势:3,520,215个项目
|
||||||
|
[45, 60, 280, 'C++'], // 中等活跃:1,701,552个项目
|
||||||
|
[40, 55, 250, 'C#'], // 中等活跃:1,478,463个项目
|
||||||
|
[35, 45, 180, 'PHP'], // 传统Web语言
|
||||||
|
[25, 25, 80, 'Go'], // 新兴语言,低漏洞密度
|
||||||
|
[15, 20, 45, 'Rust'], // 安全性较好的新语言
|
||||||
|
[60, 50, 200, 'Shell'], // 脚本语言
|
||||||
|
],
|
||||||
|
// 四象限分割点
|
||||||
|
midX: 50,
|
||||||
|
midY: 50,
|
||||||
|
|
||||||
|
// 四象限颜色定义
|
||||||
|
quadrantColors: {
|
||||||
|
// [高密度, 低活跃度] - 极高风险
|
||||||
|
Q1: '#BF232A',
|
||||||
|
// [高密度, 高活跃度] - 高风险,需密切关注
|
||||||
|
Q2: '#FF4900',
|
||||||
|
// [低密度, 低活跃度] - 低风险,但维护成本高
|
||||||
|
Q3: '#00B43E',
|
||||||
|
// [低密度, 高活跃度] - 健康生态
|
||||||
|
Q4: '#0063D0'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化气泡图
|
||||||
|
const initScatterChart = () => {
|
||||||
|
const el = document.getElementById('scatterChart');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
// 延迟执行以确保DOM已渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
const chartEl = document.getElementById('scatterChart');
|
||||||
|
if (!chartEl) return;
|
||||||
|
|
||||||
|
if (chartInstances.value.scatterChart) {
|
||||||
|
chartInstances.value.scatterChart.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
const myChart = echarts.init(chartEl);
|
||||||
|
chartInstances.value.scatterChart = myChart;
|
||||||
|
|
||||||
|
// 数据处理
|
||||||
|
const data = scatterData.scatterData.map(item => ({
|
||||||
|
value: [item[0], item[1], item[2]],
|
||||||
|
name: item[3]
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 计算四象限颜色
|
||||||
|
const getColor = (x: number, y: number) => {
|
||||||
|
if (x < scatterData.midX && y >= scatterData.midY) return scatterData.quadrantColors.Q1; // 高密度, 低活跃度 - 极高风险
|
||||||
|
if (x >= scatterData.midX && y >= scatterData.midY) return scatterData.quadrantColors.Q2; // 高密度, 高活跃度 - 高风险
|
||||||
|
if (x < scatterData.midX && y < scatterData.midY) return scatterData.quadrantColors.Q3; // 低密度, 低活跃度 - 低风险
|
||||||
|
return scatterData.quadrantColors.Q4; // 低密度, 高活跃度 - 健康生态
|
||||||
|
};
|
||||||
|
|
||||||
|
myChart.setOption({
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: (params: any) => {
|
||||||
|
return `
|
||||||
|
<div>${params.data.name}</div>
|
||||||
|
<div>代码活跃度: ${params.data.value[0]}</div>
|
||||||
|
<div>漏洞密度: ${params.data.value[1]}</div>
|
||||||
|
<div>漏洞总数: ${params.data.value[2]}</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
|
||||||
|
xAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '代码活跃度',
|
||||||
|
nameTextStyle: { fontSize: 12 },
|
||||||
|
axisLabel: { fontSize: 12 },
|
||||||
|
splitLine: { show: true }
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
name: '漏洞密度',
|
||||||
|
nameTextStyle: { fontSize: 12 },
|
||||||
|
axisLabel: { fontSize: 12 },
|
||||||
|
splitLine: { show: true }
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'scatter',
|
||||||
|
data: data,
|
||||||
|
symbolSize: (val: any) => val[2] / 2, // 根据漏洞总数调整气泡大小
|
||||||
|
itemStyle: {
|
||||||
|
color: (params: any) => getColor(params.value[0], params.value[1])
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
formatter: (params: any) => params.data.name,
|
||||||
|
position: 'inside',
|
||||||
|
fontSize: 10,
|
||||||
|
color: '#fff'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听窗口大小变化,重新调整图表大小
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
if (chartInstances.value.scatterChart) {
|
||||||
|
chartInstances.value.scatterChart.resize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 在组件挂载后初始化图表
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
initScatterChart();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 在组件卸载前清理资源
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (chartInstances.value.scatterChart) {
|
||||||
|
chartInstances.value.scatterChart.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initScatterChart
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.index-module__NV_5cW__chartCard {
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background: #ffffffe6;
|
||||||
|
border: 1px solid #ffffff4d;
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
box-shadow: 0 4px 16px #00000014;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-module__NV_5cW__chartCard:hover {
|
||||||
|
border-color: #3b82f64d;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 24px #0000001f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chartCard__title {
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 1rem 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chartCard__container {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px; /* 图表高度 */
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-\[1\.5rem\] {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 与示例一致的空数据样式 */
|
||||||
|
.num-empty {
|
||||||
|
height: 10px;
|
||||||
|
border-top: 2px solid #2951E0;
|
||||||
|
width: 100%;
|
||||||
|
background: linear-gradient(180deg, rgba(41, 81, 224, 0.12) 0%, rgba(41, 81, 224, 0.04) 100%);
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -55,22 +55,10 @@
|
|||||||
<VulnerabilityLanguageChart />
|
<VulnerabilityLanguageChart />
|
||||||
|
|
||||||
<!-- 高危漏洞占比图表 -->
|
<!-- 高危漏洞占比图表 -->
|
||||||
<div class="index-module__NV_5cW__chartCard mb-[1.5rem]">
|
<VulnerabilitySeverityChart />
|
||||||
<h3 class="chartCard__title">漏洞等级分布</h3>
|
|
||||||
<div class="chartCard__container">
|
|
||||||
<div class="num-empty" v-if="isEmpty.vulnerabilitySeverity"></div>
|
|
||||||
<div v-else id="vulnerabilitySeverityChart" class="chart"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 气泡图 -->
|
<!-- 编程语言安全态势 -->
|
||||||
<div class="index-module__NV_5cW__chartCard mb-[1.5rem]">
|
<ScatterChart />
|
||||||
<h3 class="chartCard__title">编程语言安全态势</h3>
|
|
||||||
<div class="chartCard__container">
|
|
||||||
<div class="num-empty" v-if="isEmpty.scatterData"></div>
|
|
||||||
<div v-else id="scatterChart" class="chart"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -85,6 +73,8 @@ import HighRiskComponentRank from './components/HighRiskComponentRank.vue';
|
|||||||
import IntelligenceFeed from './components/IntelligenceFeed.vue';
|
import IntelligenceFeed from './components/IntelligenceFeed.vue';
|
||||||
import CveTrendChart from './components/CveTrendChart.vue';
|
import CveTrendChart from './components/CveTrendChart.vue';
|
||||||
import VulnerabilityLanguageChart from './components/VulnerabilityLanguageChart.vue';
|
import VulnerabilityLanguageChart from './components/VulnerabilityLanguageChart.vue';
|
||||||
|
import VulnerabilitySeverityChart from './components/VulnerabilitySeverityChart.vue';
|
||||||
|
import ScatterChart from './components/ScatterChart.vue';
|
||||||
import StatsGlass from '@/views/Jyh/security/StatsGlass.vue';
|
import StatsGlass from '@/views/Jyh/security/StatsGlass.vue';
|
||||||
|
|
||||||
// 页面尺寸响应式
|
// 页面尺寸响应式
|
||||||
@@ -181,73 +171,9 @@ const chartData = ref({
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
// 漏洞占比数据
|
|
||||||
vulnerabilitySeverity: {
|
|
||||||
categories: ['2024Q1', '2024Q2', '2024Q3', '2024Q4', '2025Q1', '2025Q2', '2025Q3', '2025Q4'],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: '高危漏洞',
|
|
||||||
type: 'bar',
|
|
||||||
stack: 'total',
|
|
||||||
itemStyle: { color: '#FF4D4F' },
|
|
||||||
barWidth: 16,
|
|
||||||
data: [35, 42, 58, 45, 67, 78, 62, 85, 92]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '中危漏洞',
|
|
||||||
type: 'bar',
|
|
||||||
stack: 'total',
|
|
||||||
itemStyle: { color: '#FAAD14' },
|
|
||||||
barWidth: 16,
|
|
||||||
data: [65, 72, 88, 95, 112, 105, 120, 135, 128]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '低危漏洞',
|
|
||||||
type: 'bar',
|
|
||||||
stack: 'total',
|
|
||||||
itemStyle: { color: '#36CFC9' },
|
|
||||||
barWidth: 16,
|
|
||||||
data: [120, 135, 150, 142, 165, 180, 175, 190, 210]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 气泡图数据
|
|
||||||
// 基于真实数据:[代码活跃度(X), 漏洞密度(Y), 漏洞总数(Size), 语言名称(Name)]
|
|
||||||
// 活跃度基于新增项目数量,漏洞密度基于CWE分布统计
|
|
||||||
scatterData: [
|
|
||||||
[95, 75, 450, 'JavaScript'], // 最高活跃度:9,345,046个项目
|
|
||||||
[90, 70, 380, 'Python'], // 高活跃度:9,261,587个项目
|
|
||||||
[85, 65, 320, 'TypeScript'], // 高增长:78.1%增长率
|
|
||||||
[75, 80, 420, 'Java'], // 传统强势:3,520,215个项目
|
|
||||||
[45, 60, 280, 'C++'], // 中等活跃:1,701,552个项目
|
|
||||||
[40, 55, 250, 'C#'], // 中等活跃:1,478,463个项目
|
|
||||||
[35, 45, 180, 'PHP'], // 传统Web语言
|
|
||||||
[25, 25, 80, 'Go'], // 新兴语言,低漏洞密度
|
|
||||||
[15, 20, 45, 'Rust'], // 安全性较好的新语言
|
|
||||||
[60, 50, 200, 'Shell'], // 脚本语言
|
|
||||||
],
|
|
||||||
// 四象限分割点
|
|
||||||
midX: 50,
|
|
||||||
midY: 50,
|
|
||||||
|
|
||||||
// 四象限颜色定义
|
|
||||||
quadrantColors: {
|
|
||||||
// [高密度, 低活跃度] - 极高风险
|
|
||||||
Q1: '#BF232A',
|
|
||||||
// [高密度, 高活跃度] - 高风险,需密切关注
|
|
||||||
Q2: '#FF4900',
|
|
||||||
// [低密度, 低活跃度] - 低风险,但维护成本高
|
|
||||||
Q3: '#00B43E',
|
|
||||||
// [低密度, 高活跃度] - 健康生态
|
|
||||||
Q4: '#0063D0'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 空数据标识
|
// 空数据标识
|
||||||
const isEmpty = ref({
|
const isEmpty = ref({
|
||||||
university: false,
|
university: false,
|
||||||
@@ -480,132 +406,9 @@ const initDeveloperChart = () => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 初始化高危漏洞占比图表
|
|
||||||
const initVulnerabilitySeverityChart = () => {
|
|
||||||
const el = document.getElementById('vulnerabilitySeverityChart');
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
if (chartInstances.value.vulnerabilitySeverityChart) {
|
|
||||||
chartInstances.value.vulnerabilitySeverityChart.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
const myChart = echarts.init(el);
|
|
||||||
chartInstances.value.vulnerabilitySeverityChart = myChart;
|
|
||||||
|
|
||||||
myChart.setOption({
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: {
|
|
||||||
type: 'shadow'
|
|
||||||
},
|
|
||||||
formatter: (params: any) => {
|
|
||||||
let res = `<div>${params[0].name}</div>`;
|
|
||||||
let total = 0;
|
|
||||||
params.forEach((p: any) => {
|
|
||||||
total += p.value;
|
|
||||||
});
|
|
||||||
params.forEach((p: any) => {
|
|
||||||
const percentage = ((p.value / total) * 100).toFixed(1);
|
|
||||||
res += `<div style="display:flex;align-items:center;"><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${p.color};"></span>${p.seriesName}: ${p.value} (${percentage}%)</div>`;
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
top: 0,
|
|
||||||
textStyle: { fontSize: 12 },
|
|
||||||
data: chartData.value.vulnerabilitySeverity.series.map(item => item.name)
|
|
||||||
},
|
|
||||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
|
|
||||||
xAxis: [
|
|
||||||
{
|
|
||||||
type: 'category',
|
|
||||||
data: chartData.value.vulnerabilitySeverity.categories,
|
|
||||||
axisLabel: { fontSize: 12 }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
yAxis: [
|
|
||||||
{
|
|
||||||
type: 'value',
|
|
||||||
name: '漏洞数量',
|
|
||||||
nameTextStyle: { fontSize: 12 },
|
|
||||||
axisLabel: { fontSize: 12 }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: chartData.value.vulnerabilitySeverity.series
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化气泡图
|
|
||||||
const initScatterChart = () => {
|
|
||||||
const el = document.getElementById('scatterChart');
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
if (chartInstances.value.scatterChart) {
|
|
||||||
chartInstances.value.scatterChart.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
const myChart = echarts.init(el);
|
|
||||||
chartInstances.value.scatterChart = myChart;
|
|
||||||
|
|
||||||
// 数据处理
|
|
||||||
const data = chartData.value.scatterData.map(item => ({
|
|
||||||
value: [item[0], item[1], item[2]],
|
|
||||||
name: item[3]
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 计算四象限颜色
|
|
||||||
const getColor = (x: number, y: number) => {
|
|
||||||
if (x < chartData.value.midX && y >= chartData.value.midY) return chartData.value.quadrantColors.Q1; // 高密度, 低活跃度 - 极高风险
|
|
||||||
if (x >= chartData.value.midX && y >= chartData.value.midY) return chartData.value.quadrantColors.Q2; // 高密度, 高活跃度 - 高风险
|
|
||||||
if (x < chartData.value.midX && y < chartData.value.midY) return chartData.value.quadrantColors.Q3; // 低密度, 低活跃度 - 低风险
|
|
||||||
return chartData.value.quadrantColors.Q4; // 低密度, 高活跃度 - 健康生态
|
|
||||||
};
|
|
||||||
|
|
||||||
myChart.setOption({
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item',
|
|
||||||
formatter: (params: any) => {
|
|
||||||
return `
|
|
||||||
<div>${params.data.name}</div>
|
|
||||||
<div>代码活跃度: ${params.data.value[0]}</div>
|
|
||||||
<div>漏洞密度: ${params.data.value[1]}</div>
|
|
||||||
<div>漏洞总数: ${params.data.value[2]}</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
grid: { left: '3%', right: '4%', bottom: '3%', top: '15%', containLabel: true },
|
|
||||||
xAxis: {
|
|
||||||
type: 'value',
|
|
||||||
name: '代码活跃度',
|
|
||||||
nameTextStyle: { fontSize: 12 },
|
|
||||||
axisLabel: { fontSize: 12 },
|
|
||||||
splitLine: { show: true }
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value',
|
|
||||||
name: '漏洞密度',
|
|
||||||
nameTextStyle: { fontSize: 12 },
|
|
||||||
axisLabel: { fontSize: 12 },
|
|
||||||
splitLine: { show: true }
|
|
||||||
},
|
|
||||||
series: [{
|
|
||||||
type: 'scatter',
|
|
||||||
data: data,
|
|
||||||
symbolSize: (val: any) => val[2] / 2, // 根据漏洞总数调整气泡大小
|
|
||||||
itemStyle: {
|
|
||||||
color: (params: any) => getColor(params.value[0], params.value[1])
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
show: true,
|
|
||||||
formatter: (params: any) => params.data.name,
|
|
||||||
position: 'inside',
|
|
||||||
fontSize: 10,
|
|
||||||
color: '#fff'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化武汉市语言与技术竞争趋势(折线图)
|
// 初始化武汉市语言与技术竞争趋势(折线图)
|
||||||
const initLanguageTechChart = () => {
|
const initLanguageTechChart = () => {
|
||||||
@@ -679,10 +482,6 @@ const initCharts = () => {
|
|||||||
languageTech: chartData.value.languageTech.series.every(s => s.data.every(d => d === 0)),
|
languageTech: chartData.value.languageTech.series.every(s => s.data.every(d => d === 0)),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vulnerabilitySeverity: chartData.value.vulnerabilitySeverity.series.every(s => s.data.every(d => d === 0)),
|
|
||||||
scatterData: chartData.value.scatterData.length === 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化各图表
|
// 初始化各图表
|
||||||
@@ -692,11 +491,6 @@ const initCharts = () => {
|
|||||||
if (!isEmpty.value.developer) nextTick(() => initDeveloperChart());
|
if (!isEmpty.value.developer) nextTick(() => initDeveloperChart());
|
||||||
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
if (!isEmpty.value.languageTech) nextTick(() => initLanguageTechChart());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!isEmpty.value.vulnerabilitySeverity) nextTick(() => initVulnerabilitySeverityChart());
|
|
||||||
if (!isEmpty.value.scatterData) nextTick(() => initScatterChart());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面resize时重绘图表
|
// 页面resize时重绘图表
|
||||||
@@ -1053,21 +847,6 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 与示例一致的空数据样式 */
|
/* 与示例一致的空数据样式 */
|
||||||
.num-empty {
|
|
||||||
height: 10px;
|
|
||||||
border-top: 2px solid #2951E0;
|
|
||||||
width: 100%;
|
|
||||||
background: linear-gradient(180deg, rgba(41, 81, 224, 0.12) 0%, rgba(41, 81, 224, 0.04) 100%);
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 0;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.index-module__NV_5cW__sectionHeader {
|
.index-module__NV_5cW__sectionHeader {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user