态势感知平台-全球开源风险态势感知监控中心情报流组件补充
This commit is contained in:
@@ -43,23 +43,7 @@
|
||||
<!-- 高危组件Top 10 -->
|
||||
<HighRiskComponentRank />
|
||||
|
||||
<div class="index-module__NV_5cW__chartCard list-card">
|
||||
<h3 class="chartCard__title">情报流</h3>
|
||||
<!-- 新增:ref + 鼠标事件 -->
|
||||
<div class="chartCard__container list-container"
|
||||
ref="scrollContainer1"
|
||||
@mouseenter="pauseScroll(1)"
|
||||
@mouseleave="resumeScroll(1)">
|
||||
<div class="project-list">
|
||||
<div class="project-item" v-for="(item, index) in feedList" :key="index">
|
||||
<span class="project-rank" :class="item.type">{{ item.type }}</span>
|
||||
<div class="project-info">
|
||||
<span class="project-name">{{ item.content }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<IntelligenceFeed />
|
||||
|
||||
<div class="index-module__NV_5cW__chartCard chartCard__wide">
|
||||
<div class="chartCard__header">
|
||||
@@ -127,6 +111,7 @@ import { usePageResize } from '@/utils/hooks/usePageResize';
|
||||
import ThreatIntelMap from './components/ThreatIntelMap.vue';
|
||||
import IndustryDistribution from './components/IndustryDistribution.vue';
|
||||
import HighRiskComponentRank from './components/HighRiskComponentRank.vue';
|
||||
import IntelligenceFeed from './components/IntelligenceFeed.vue';
|
||||
import StatsGlass from '@/views/Jyh/security/StatsGlass.vue';
|
||||
|
||||
// 页面尺寸响应式
|
||||
@@ -146,33 +131,7 @@ const excellentProjects = ref([
|
||||
{ name: 'NextDenovo', desc: '高效且精确的长读长纠错与组装工具', org: '武汉希望组生物科技有限公司' }
|
||||
]);
|
||||
|
||||
// 情报流数据
|
||||
const feedList = ref([
|
||||
{
|
||||
type: 'CISA',
|
||||
content: 'CISA KEV新增: WordPress 的 OneClick Chat to Order 插件,存在不安全的直接对象引用漏洞 (CVE-2025-13526) '
|
||||
},
|
||||
{
|
||||
type: '投毒',
|
||||
content: '投毒监控: npm 基建级包大规模投毒事件,影响chalk, debug, ansi-styles 等 18 个包'
|
||||
},
|
||||
{
|
||||
type: 'CNVD',
|
||||
content: 'CNVD预警: Google Chrome信息泄露漏洞(CNVD-2025-3038304)'
|
||||
},
|
||||
{
|
||||
type: 'GitHub',
|
||||
content: 'GitHub安全通告: MovableType 软件的 ContentType 页面 "编辑分类集" 功能存在存储型跨站脚本漏洞'
|
||||
},
|
||||
{
|
||||
type: '修复',
|
||||
content: '漏洞修复: Node.js 发布 v20.11.0 版本,修复 3 个高危漏洞'
|
||||
},
|
||||
{
|
||||
type: '供应链',
|
||||
content: '供应链预警: Maven 中央仓库发现 12 个伪造开源组件,包含后门程序'
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
// 2. 2025武汉市优秀开源软件项目
|
||||
const excellentProjects2025 = ref([
|
||||
@@ -428,82 +387,7 @@ const chartInstances = ref<{ [key: string]: echarts.ECharts | null }>({
|
||||
CVEChart: null
|
||||
});
|
||||
|
||||
// ===================== 新增:列表自动滚动逻辑 =====================
|
||||
// 1. 定义滚动容器的ref
|
||||
const scrollContainer1 = ref<HTMLDivElement | null>(null); // 第一个列表容器
|
||||
const scrollContainer2 = ref<HTMLDivElement | null>(null); // 第二个列表容器
|
||||
|
||||
// 2. 存储定时器(键:1/2,值:定时器ID)
|
||||
const scrollTimers: { [key: number]: NodeJS.Timeout | null } = {
|
||||
1: null,
|
||||
2: null
|
||||
};
|
||||
|
||||
// 3. 滚动配置
|
||||
const scrollStep = 1; // 每次滚动的步长(像素,越小越流畅)
|
||||
const scrollInterval = 20; // 滚动间隔(毫秒,越小越流畅)
|
||||
|
||||
// 4. 通用自动滚动函数
|
||||
const autoScroll = (containerKey: number) => {
|
||||
// 获取对应容器
|
||||
const container = containerKey === 1 ? scrollContainer1.value : scrollContainer2.value;
|
||||
if (!container) return;
|
||||
|
||||
// 获取列表内容元素(project-list)
|
||||
const projectList = container.querySelector('.project-list') as HTMLDivElement;
|
||||
if (!projectList) return;
|
||||
|
||||
// 若内容高度 ≤ 容器高度,不执行滚动
|
||||
if (projectList.scrollHeight <= container.clientHeight) {
|
||||
// 清除现有定时器
|
||||
if (scrollTimers[containerKey]) {
|
||||
clearInterval(scrollTimers[containerKey]!);
|
||||
scrollTimers[containerKey] = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除现有定时器(避免重复)
|
||||
if (scrollTimers[containerKey]) {
|
||||
clearInterval(scrollTimers[containerKey]!);
|
||||
}
|
||||
|
||||
// 启动定时器滚动
|
||||
scrollTimers[containerKey] = setInterval(() => {
|
||||
// 向下滚动步长
|
||||
container.scrollTop += scrollStep;
|
||||
|
||||
// 滚动到底部时,重置为0(循环滚动)
|
||||
// 加1是为了兼容像素精度问题
|
||||
if (projectList.scrollHeight - container.scrollTop <= container.clientHeight + 1) {
|
||||
container.scrollTop = 0; // 直接重置(也可以用平滑滚动:container.scrollTo({ top: 0, behavior: 'smooth' }))
|
||||
}
|
||||
}, scrollInterval);
|
||||
};
|
||||
|
||||
// 5. 暂停滚动
|
||||
const pauseScroll = (containerKey: number) => {
|
||||
if (scrollTimers[containerKey]) {
|
||||
clearInterval(scrollTimers[containerKey]!);
|
||||
scrollTimers[containerKey] = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 6. 恢复滚动
|
||||
const resumeScroll = (containerKey: number) => {
|
||||
autoScroll(containerKey);
|
||||
};
|
||||
|
||||
// 7. 组件卸载时清除所有定时器
|
||||
onUnmounted(() => {
|
||||
Object.keys(scrollTimers).forEach(key => {
|
||||
const k = Number(key);
|
||||
if (scrollTimers[k]) {
|
||||
clearInterval(scrollTimers[k]!);
|
||||
scrollTimers[k] = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// CVE视图切换方法
|
||||
const switchCveView = (view: 'global' | 'regional') => {
|
||||
@@ -1148,18 +1032,12 @@ const initCharts = () => {
|
||||
// 页面resize时重绘图表
|
||||
watch(widthType, () => {
|
||||
initCharts();
|
||||
// 重新启动滚动(防止resize后滚动失效)
|
||||
autoScroll(1);
|
||||
autoScroll(2);
|
||||
});
|
||||
|
||||
// 挂载时初始化
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
initCharts();
|
||||
// 启动列表自动滚动
|
||||
autoScroll(1);
|
||||
autoScroll(2);
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user