态势感知平台-全球开源风险态势感知监控中心抽离情报流组件

This commit is contained in:
d266377
2026-01-26 17:30:14 +08:00
parent 1085a8f8c8
commit 43ca3c13a1

View File

@@ -0,0 +1,272 @@
<template>
<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>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
// 接收外部数据作为属性
const props = defineProps<{
initialData?: Array<any>;
}>();
// 情报流数据
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 个伪造开源组件,包含后门程序'
}
]);
// 如果提供了初始数据,则使用提供的数据
watch(() => props.initialData, (newData) => {
if (newData && newData.length > 0) {
feedList.value = newData;
}
}, { immediate: true });
// 1. 定义滚动容器的ref
const scrollContainer1 = 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 : null;
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. 组件挂载时启动滚动
onMounted(() => {
nextTick(() => {
autoScroll(1);
});
});
// 8. 组件卸载时清除定时器
onUnmounted(() => {
Object.keys(scrollTimers).forEach(key => {
const k = Number(key);
if (scrollTimers[k]) {
clearInterval(scrollTimers[k]!);
scrollTimers[k] = null;
}
});
});
</script>
<style scoped>
/* 使用主页面相同的CSS类定义以确保样式一致性 */
.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.list-card {
padding: 1.5rem;
}
.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;
}
/* 列表容器样式:隐藏原生滚动条(可选,视觉更美观) */
.chartCard__container.list-container {
height: auto;
max-height: 300px; /* 限制列表高度,超出滚动 */
overflow-y: auto;
padding: 0 0.5rem;
/* 隐藏滚动条 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
/* 隐藏webkit内核浏览器的滚动条 */
.chartCard__container.list-container::-webkit-scrollbar {
display: none;
}
/* 项目列表样式 */
.project-list {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
.project-item {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.8rem;
background: #f8f9fa;
border-radius: 0.5rem;
border-left: 3px solid #2951E0;
transition: all 0.2s;
}
/* 鼠标悬停项目项时的样式 */
.project-item:hover {
background: #f0f4ff;
transform: translateX(2px);
}
.project-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.project-rank {
min-width: 24px;
height: 24px;
border-radius: 4px;
background: #2951E0;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
flex-shrink: 0;
padding: 0 4px;
}
/* 特定类型的颜色定义 - 使用中文类名 */
/* .project-rank.CISA {
background: #ff0000;
}
.project-rank.投毒 {
background: #ffa500;
}
.project-rank.CNVD {
background: #ffff00;
color: #000;
}
.project-rank.GitHub {
background: #0000ff;
}
.project-rank.修复 {
background: #008000;
}
.project-rank.供应链 {
background: #800080;
} */
.project-name {
font-size: 14px;
font-weight: 600;
color: #333;
line-height: 1.4;
}
</style>