可信代码库V2版-安全智库页面原型开发、安全检测中心页面原型开发、关于我们页面原型开发

This commit is contained in:
fmk1023
2025-11-06 10:54:58 +08:00
parent 533e20b2f3
commit f5b59fadd9
29 changed files with 8077 additions and 650 deletions

View File

@@ -0,0 +1,367 @@
<template>
<div class="vuln-detail-container">
<div class="vuln-title mb-2">
<span>漏洞预警详情</span>
<div class="vuln-sub-title">
<!-- <d-button @click="openWarningDetail()" variant="solid">预警发布</d-button>-->
<!-- <span class="split-line"></span>-->
<d-icon name="icon-close" @click="$emit('close')"></d-icon>
</div>
</div>
<Card simple class="jyh-card mb-4">
<div class="card-title">漏洞信息</div>
<d-row class="mb-3">
<d-col :span="12">
<span class="card-key width-90">漏洞名称</span>
<span class="card-val">{{ valInfos.vulnId || '--' }}</span>
</d-col>
<d-col :span="12">
<span class="card-key width-90">漏洞类型</span>
<span class="card-val">{{ valInfos.vulnType || '--' }}</span>
</d-col>
</d-row>
<d-row class="mb-3">
<d-col :span="12">
<span class="card-key width-90">漏洞时间</span>
<span class="card-val">{{
valInfos.publishDate ? dayjs(valInfos.publishDate).format('YYYY-MM-DD') : '--'
}}</span>
</d-col>
<d-col :span="12">
<span class="card-key width-90">严重程度</span>
<span class="card-val" v-if="tagMap[valInfos.severity]">
<d-tag :color="tagMap[valInfos.severity].color" size="sm">{{ tagMap[valInfos.severity].text }}</d-tag>
</span>
</d-col>
</d-row>
</Card>
<Card simple class="jyh-card mb-4">
<div class="card-title">漏洞影响的软件列表</div>
<d-row class="mb-3">
<d-col :span="24">
<div v-if="componentsLists.length>0">
<d-table
class="jyh-table jyh-table-2"
:header-bg="true"
:data="componentsLists"
:span-method="spanMethod"
>
<d-column field="effectedComponentName" header="软件名称" show-overflow-tooltip></d-column>
<d-column field="effectedComponentVersion" header="软件版本及范围" show-overflow-tooltip></d-column>
<d-column field="isCriticalInfrastructureComponent" header="是否用户订阅" width="140" align="center">
<template #default="scope">
<div class="text-center" v-if="scope.row.isCriticalInfrastructureComponent==='是'">
<d-icon name="icon-right-o" style="font-size: 14px; color: rgb(80, 212, 171)"></d-icon>
</div>
<div class="text-center" v-else>
<d-icon name="icon-error-o" style="font-size: 14px; color: rgb(246, 111, 106)"></d-icon>
</div>
</template>
</d-column>
<!-- <d-column field="fixVersion" header="补丁版本"></d-column>-->
<!-- <d-column field="fixIssue" header="修复建议" show-overflow-tooltip></d-column>-->
<template #empty>
<NoData :small="false"></NoData>
</template>
</d-table>
<div class="mt-20 mb-20 flex justify-end" >
<d-pagination
style="display: inline-flex"
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:can-view-total="true"
:can-change-page-size="true"
:can-jump-page="true"
:max-items="5"
total-item-text="总计"
@page-index-change="getComponentsList"
@page-size-change="getComponentsList"
/>
</div>
</div>
<NoData v-else :small="false"></NoData>
</d-col>
</d-row>
</Card>
<!-- <Card simple class="jyh-card mb-4">-->
<!-- <div class="card-title">受影响的开源软件是否出库</div>-->
<!-- <d-row class="mb-3">-->
<!-- <d-col :span="24">-->
<!-- <d-radio-group direction="row" v-model="isOut" @change="onStorageStartTask">-->
<!-- <d-radio :value="2">出库</d-radio>-->
<!-- <d-radio :value="1">不出库</d-radio>-->
<!-- </d-radio-group>-->
<!-- </d-col>-->
<!-- </d-row>-->
<!-- </Card>-->
<!-- <Card simple class="jyh-card mb-4">-->
<!-- <div class="card-title">预警订阅人员列表</div>-->
<!-- <d-row class="mb-3">-->
<!-- <d-col :span="24">-->
<!-- <d-table class="jyh-table jyh-table-2" :header-bg="true" :data="alertsUsersLists">-->
<!-- <d-column field="username" header="订阅人"></d-column>-->
<!-- <d-column field="method" header="订阅方式"></d-column>-->
<!-- <d-column field="notifiedStatus" header="通知状态">-->
<!-- <template #default="scope, text">-->
<!-- <d-tag v-if="scope.row.notifiedStatus === 0" type="danger" size="sm">未通知</d-tag>-->
<!-- <d-tag v-if="scope.row.notifiedStatus === 1" type="success" size="sm">已通知</d-tag>-->
<!-- </template>-->
<!-- </d-column>-->
<!-- <template #empty>-->
<!-- <NoData :small="false"></NoData>-->
<!-- </template>-->
<!-- </d-table>-->
<!-- &lt;!&ndash; <div class="invitation-pagination">-->
<!-- <d-pagination-->
<!-- style="display: inline-flex"-->
<!-- :total="subscribePager.total"-->
<!-- v-model:pageSize="subscribePager.pageSize"-->
<!-- v-model:pageIndex="subscribePager.pageIndex"-->
<!-- :can-view-total="true"-->
<!-- :can-change-page-size="true"-->
<!-- :can-jump-page="true"-->
<!-- :max-items="5"-->
<!-- />-->
<!-- </div> &ndash;&gt;-->
<!-- </d-col>-->
<!-- </d-row>-->
<!-- </Card>-->
</div>
<d-modal class="warning-modal" v-model="warningModalVisable" title="">
<EarlyWarningDetail
@close="colseWarningDetail"
:softwareId="valInfos.softwareId"
:valInfos="valInfos"
:softwareIds="softwareIds"
:isStartOutTask="isOut"
type="system"
></EarlyWarningDetail>
</d-modal>
</template>
<script setup lang="ts">
import NoData from '@/components/NoData/NoData.vue';
import dayjs from 'dayjs';
import {
getVulnAffected,
getVulnDetail,
getVulnerabilitiesAlertsUsers,
getVulnerabilitiesComponents,
getVulnerabilitiesDetails,
getVulnPatch,
storageStartOutTask
} from '@/api/repo';
import { computed, onMounted, ref, shallowReactive } from 'vue';
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
import { Message } from 'vue-devui/message';
const tagMap = {
Critical: {
text: '致命',
color: '#c7000b'
},
High: {
text: '高',
color: '#f66f6a'
},
Medium: {
text: '中',
color: '#fac20a'
},
Low: {
text: '低',
color: '#5e7ce0'
},
high: {
text: '高',
color: '#f66f6a'
},
medium: {
text: '中',
color: '#fac20a'
},
low: {
text: '低',
color: '#5e7ce0'
}
};
const subscribePager = shallowReactive({
total: 1,
pageIndex: 1,
pageSize: 10,
pageSizeOptions: [10, 20, 30, 40, 50]
});
const isOut = ref(1);
const propsData = defineProps(['vulnId']);
const warningModalVisable = ref(false);
const softwareIds = computed(() => {
let arr = [];
alertsUsersLists.value?.map(i=>{
if(i.notifiedStatus==0) {
if(!arr.includes(i.softwareId)) {
arr.push(i.softwareId)
}
}
})
return arr;
});
const openWarningDetail = () => {
if(valInfos.value?.effectedComponents.length>0&&softwareIds.value.length>0) {
warningModalVisable.value = true;
} else {
Message.warning('当前暂无需要通知的用户');
}
};
const colseWarningDetail = () => {
warningModalVisable.value = false;
};
const onStorageStartTask = async (e) => {
if (!valInfos.value?.softwareId) return;
await storageStartOutTask({
softwareId: valInfos.value?.softwareId,
taskType: isOut.value
});
};
const severityMap = {
high: '高',
medium: '中',
low: '低'
};
const valInfos: any = ref({});
const componentsLists: any = ref([]);
const alertsUsersLists: any = ref([]);
const getComponentsList = async () => {
const response = await getVulnerabilitiesComponents({
id:propsData.vulnId,
current: pager.value.pageIndex,
size: pager.value.pageSize
});
debugger
if (response.data.data.code === 200) {
// 假设接口返回格式为 { code, data: { records, total } }
componentsLists.value = response.data.data.data.records || [];
pager.value.total = response.data.data.data.total || 0;
} else {
// Message.error('获取组件列表失败');
componentsLists.value = [];
pager.value.total = 0;
}
}
onMounted(async () => {
const _valInfos = await getVulnerabilitiesDetails(propsData.vulnId);
const _alertsUsersLists = await getVulnerabilitiesAlertsUsers(propsData.vulnId);
valInfos.value = _valInfos?.data?.data?.data;
alertsUsersLists.value = _alertsUsersLists?.data?.data?.data?.map((user) => {
const alertMethod = JSON.parse(user.alertTypeExt ?? '{}');
let method = '';
if (alertMethod.webSwitch) {
method = '站内通知';
} else if (alertMethod.emailSwitch) {
method = '邮件';
} else if (alertMethod.mobileSwitch) {
method = '短信';
}
return {
...user,
method
};
});
await getComponentsList()
});
const pager = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
// 分页事件处理
function onPageIndexChange(newPageIndex) {
pager.value.pageIndex = newPageIndex;
}
function onPageSizeChange(newPageSize) {
// 重置页码为1
pager.value.pageIndex = 1;
pager.value.pageSize = newPageSize;
}
</script>
<style scoped lang="scss">
.vuln-detail-container {
width: 800px;
padding: 20px;
.vuln-title {
color: #191919;
font-family: HarmonyOS Sans SC;
font-weight: 400;
font-size: 18px;
display: flex;
justify-content: space-between;
}
.vuln-sub-title {
color: #191919;
font-family: HarmonyOS Sans;
font-weight: regular;
font-size: 12px;
line-height: 20px;
letter-spacing: 0px;
text-align: left;
.split-line {
width: 1px;
display: inline-block;
line-height: 16px;
height: 16px;
vertical-align: middle;
margin: 0 8px;
background-color: #eef0f5;
}
.release-time {
color: #808080;
}
}
.card-val {
display: inline-block;
width: calc(100% - 90px);
vertical-align: top;
}
.invitation-pagination {
padding: 12px 0;
text-align: right;
}
}
</style>
<style lang="scss">
.warning-modal {
width: auto;
.devui-modal__header {
font-size: 20px;
height: auto !important;
}
.devui-modal__body {
padding: 0;
}
}
</style>

View File

@@ -0,0 +1,329 @@
<template>
<d-modal style="width: 1200px" v-model="visible" @close="close" class="software-modal">
<template #header>
<gc-modal-header>
<span class="text-G900 text-base font-bold leading-[24px]">受影响软件清单</span>
</gc-modal-header>
<div class="line bg-G200"></div>
</template>
<d-row class="mb-3">
<d-col :span="24">
<!-- 批量预警按钮保留 -->
<div class="mb-4 flex justify-start">
<d-button
variant="solid"
color="primary"
@click="batchPublishWarning"
:disabled="selectedRows.length === 0"
>
批量预警
</d-button>
<span class="ml-3 text-G600" v-if="selectedRows.length > 0">
已选中 {{ selectedRows.length }} 条数据
</span>
</div>
<div v-if="componentsLists.length > 0">
<d-table
ref="tableRef"
class="jyh-table jyh-table-2"
:header-bg="true"
:data="componentsLists"
:span-method="spanMethod"
row-key="effectedComponentVersion"
@check-change="handleCheckChange"
@check-all-change="handleCheckAllChange"
>
<!-- 1. 新增复选框列DevUI标准选中入口 -->
<d-column
type="checkable"
width="40"
reserve-check
></d-column>
<!-- 原有列保持不变 -->
<d-column field="effectedSoftwareName" header="应用名称" show-overflow-tooltip width="200"></d-column>
<d-column field="effectedComponentName" header="组件名称" show-overflow-tooltip width="200"></d-column>
<d-column field="effectedComponentVersion" header="版本及范围" show-overflow-tooltip width="200"></d-column>
<d-column field="develop" header="组件开发者" show-overflow-tooltip width="180"></d-column>
<d-column field="responsibleTeam" header="责任单位" show-overflow-tooltip width="180"></d-column>
<d-column header="操作" fixed-right="0px" width="160">
<template #default="scope">
<a class="devui-link mr-[8px]" @click="openWarningDetail(scope.row)">发布预警</a>
</template>
</d-column>
</d-table>
<!-- 分页组件保留新增选中状态重置逻辑 -->
<div class="mt-20 mb-20 flex justify-end">
<d-pagination
size="md"
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:can-view-total="true"
:can-change-page-size="true"
:can-jump-page="true"
:max-items="5"
total-item-text="总计"
@page-index-change="handlePageChange"
@page-size-change="handlePageChange"
/>
</div>
</div>
<NoData v-else :small="false"></NoData>
</d-col>
</d-row>
<template #footer>
<div class="flex justify-end px-[24px] pb-[24px] gap-2">
<d-button @click="handleCancel">取消</d-button>
<d-button variant="solid" :disabled="disabled" @click="handleConfirm">确定</d-button>
</div>
</template>
<!-- <EarlyWarningDetail :warningData="currentWarning" type="system" @refresh="getAlertSubscribesPage"></EarlyWarningDetail>-->
</d-modal>
</template>
<script setup>
import { ref } from 'vue';
import NoData from '@/components/NoData/NoData.vue';
import { getVulnerabilitiesComponents } from '@/api/repo';
import { Message } from 'vue-devui/message';
import { useGlobalInfoStore } from '@/stores/Global';
import { getNoticeAdd } from '@/api/jyh';
const globalStore = useGlobalInfoStore();
// -------------------------- 1. 核心状态调整 --------------------------
const tableRef = ref(null); // 新增表格Ref用于主动操作如清空选中
const vulnId = ref('');
const vulnRow = ref({});
const visible = ref(false);
const componentsLists = ref([]);
const disabled = ref(false);
const pager = ref({ total: 0, pageIndex: 1, pageSize: 10 });
const warningData = ref({});
const currentWarning = ref();
const selectedRows = ref([]); // 存储选中的行数据(核心)
// 暴露给父组件的方法
defineExpose({ open, close, setDisabled });
// -------------------------- 2. 选中功能核心逻辑适配DevUI标准 --------------------------
/**
* 可选:控制行是否允许选中(如过滤特定责任单位的行)
* @param row 当前行数据
* @param rowIndex 行索引
* @returns 是否允许选中
*/
const isRowCheckable = (row, rowIndex) => {
// 示例:所有行都允许选中(可自定义条件,如 row.responsibleUnit === '信支工程大学'
return true;
};
/**
* 单选事件DevUI标准事件@check-change
* @param checked 当前行是否选中boolean
* @param row 当前行数据object
* @param selection 所有选中的行数据array
*/
// 复选框选中状态变化
const handleCheckChange = (checked, row, selection) => {
if (checked) {
if (!selectedRows.value.some(r => r.effectedComponentVersion === row.effectedComponentVersion)) {
selectedRows.value.push(row);
}
} else {
selectedRows.value = selectedRows.value.filter(r => r.effectedComponentVersion !== row.effectedComponentVersion);
}
};
// 全选状态变化
const handleCheckAllChange = (checked, selection) => {
if (checked) {
selectedRows.value = [...selection];
} else {
selectedRows.value = [];
}
};
// -------------------------- 3. 分页事件调整(重置选中状态) --------------------------
/**
* 分页切换事件(统一处理页码/页大小变化)
*/
const handlePageChange = async () => {
// 分页切换时,清空上一页的选中状态(避免跨页残留)
selectedRows.value = [];
// 若需要保留跨页选中,可通过 tableRef 操作tableRef.value.store.clearSelection()
await getComponentsList();
};
// -------------------------- 4. 原有业务逻辑(保持不变,仅适配选中数据) --------------------------
/**
* 单条发布预警
*/
const openWarningDetail = async (row) => {
currentWarning.value = row;
// Message.success(`已为【${row.softName}】发布预警`);
const { data } = await getNoticeAdd({
"softwareId": [row?.effectedSoftwareId],
"username": globalStore.currentRoleKey,
"vulId": row?.vulnId,
}).catch((err) => {
Message({
type: 'error',
message: '预警发送失败,请重试'
});
});
if(data.ok) {
Message({
type: 'success',
message: '预警发送成功'
});
}
};
/**
* 批量发布预警
*/
const batchPublishWarning = async () => {
if (selectedRows.value.length === 0) {
Message.warning('请先选择需要发布预警的数据');
return;
}
const { data } = await getNoticeAdd({
"softwareId": selectedRows.value.map(i=>i.effectedSoftwareId),
"username": globalStore.currentRoleKey,
"vulId": selectedRows.value[0]?.vulnId,
}).catch((err) => {
Message({
type: 'error',
message: '预警发送失败,请重试'
});
});
if(data.ok) {
Message({
type: 'success',
message: '预警发送成功'
});
// // 批量预警后主动清空表格选中状态联动UI
// if (tableRef.value) {
// tableRef.value.store.clearSelection();
// }
// selectedRows.value = [];
}
};
/**
* 获取组件列表(模拟数据+真实接口)
*/
const getComponentsList = async () => {
if (vulnRow.value.vulnId === 'CVE-2025-27507') {
// 模拟数据(保持不变)
componentsLists.value = [
{
id: '1',
softName: '军工供应链管理系统 V2.0',
effectedComponentName: 'Apache Commons Text',
effectedComponentVersion: '1.9 - 1.11.0(含)',
coder: 'Apache软件基金会',
responsibleUnit: '信支工程大学'
},
{
id: '2',
softName: '高校科研项目管理平台',
effectedComponentName: 'Log4j',
effectedComponentVersion: '2.0 - 2.14.1(含)',
coder: 'Apache软件基金会',
responsibleUnit: '华中科技大学'
},
{
id: '3',
softName: '军工代码审计系统 V3.5',
effectedComponentName: 'Jackson Databind',
effectedComponentVersion: '2.9.0 - 2.15.2(含)',
coder: 'FasterXML',
responsibleUnit: '信支工程大学'
},
{
id: '4',
softName: '高校教学管理系统 V5.0',
effectedComponentName: 'Spring Framework',
effectedComponentVersion: '5.3.0 - 5.3.23(含)',
coder: 'Pivotal Software',
responsibleUnit: '武汉大学'
}
];
pager.value.total = componentsLists.value.length;
} else {
// 真实接口逻辑(保持不变)
const response = await getVulnerabilitiesComponents({
id: vulnId.value,
current: pager.value.pageIndex,
size: pager.value.pageSize
});
if (response.data.data.code === 200) {
componentsLists.value = response.data.data.data.records?.map(item => ({
...item,
coder: item.coder || '未知',
responsibleUnit: item.responsibleUnit || '未知单位'
})) || [];
pager.value.total = response.data.data.data.total || 0;
} else {
componentsLists.value = [];
pager.value.total = 0;
}
}
};
/**
* 打开/关闭模态框(重置选中状态)
*/
async function open(row) {
if (row.id || row.vulnId) {
vulnId.value = row.id;
vulnRow.value = row;
selectedRows.value = []; // 重置选中
await getComponentsList();
visible.value = true;
}
}
function close() {
componentsLists.value = [];
pager.value = { total: 0, pageIndex: 1, pageSize: 10 };
vulnId.value = '';
vulnRow.value = {};
selectedRows.value = []; // 清空选中
// if (tableRef.value) {
// tableRef.value.store.clearSelection(); // 联动表格UI清空
// }
visible.value = false;
}
// 其他原有方法(保持不变)
function setComponentsList(list) { componentsLists.value = list; }
function setDisabled(isDisabled) { disabled.value = isDisabled; }
function handleConfirm() { close(); }
function handleCancel() { close(); }
</script>
<style lang="scss" scoped>
.software-modal {
width: 1200px !important;
}
:deep(.devui-btn) {
margin-bottom: 8px;
}
:deep(.devui-table-cell) {
white-space: nowrap;
}
// 可选:调整复选框列样式(与表格对齐)
:deep(.devui-table-checkable-column) {
text-align: center;
}
</style>

View File

@@ -0,0 +1,376 @@
<template>
<div class="page-wrap">
<!-- <h1 class="page-title">{{ title }}</h1> -->
<div class="search-form">
<!-- <d-search-->
<!-- icon-position="left"-->
<!-- @search="search"-->
<!-- v-model="vulnId"-->
<!-- style="width: 400px"-->
<!-- placeholder="请输入漏洞编号"-->
<!-- ></d-search>-->
<d-form layout="horizontal" :label-align="'end'">
<d-row :gutter="16">
<d-col :span="6">
<d-form-item field="vulnId" label="漏洞编号">
<d-input placeholder="请输入漏洞编号" v-model="newFormData.vulnId" />
</d-form-item>
</d-col>
<d-col :span="6">
<d-form-item field="severity" label="严重程度">
<d-select
:key="newFormData.severity"
:options="tagArray"
:allow-clear="true"
v-model="newFormData.severity"
placeholder="请选择严重程度"
></d-select>
</d-form-item>
</d-col>
<d-col :span="6">
<d-form-item field="affectedComponentCount" label="受影响软件数">
<d-input-number style="width: 100%;background: #ffffff" :min="0" :max="100" placeholder="请输入受影响软件数" :allowEmpty="true" v-model="newFormData.affectedComponentCount" />
</d-form-item>
</d-col>
</d-row>
</d-form>
<div class="jyh-form-operation">
<d-button @click="getList(1)" class="mr-2" variant="solid">搜索</d-button>
<d-button variant="solid" color="secondary" @click="clear">清空</d-button>
</div>
</div>
<Card class="mt-3">
<d-table :show-loading="loading" class="jyh-table" :data="dataLists" v-if="dataLists.length > 0" table-layout="auto">
<d-column type="index" width="40"></d-column>
<d-column field="vulnId" header="漏洞编号"></d-column>
<d-column field="vulnType" header="漏洞类型"></d-column>
<d-column field="publishDate" header="漏洞发布时间">
<template #default="scope">
{{ scope.row.publishDate
? dayjs(scope.row.publishDate).add(5, 'month').format('YYYY-MM-DD HH:mm:ss')
: '--'
}}
</template>
</d-column>
<d-column field="severity" header="严重程度">
<template #default="scope">
<span class="card-val" v-if="tagMap[scope.row.severity]">
<d-tag :color="tagMap[scope.row.severity].color" size="sm">{{ tagMap[scope.row.severity].text }}</d-tag>
</span></template
>
</d-column>
<d-column field="effectedComponentCount" header="受影响软件清单">
<template #default="scope">
<!--TODO:将受影响软件清单数量改为十个以下-->
<a v-if="scope.row.vulnId==='CVE-2025-27507'" class="devui-link" @click="showModal(scope.row)">4个</a>
<a v-else class="devui-link" @click="showModal(scope.row)">{{scope.row.effectedComponentCount? String(scope.row.effectedComponentCount)[0]:'0'}}</a>
</template>
</d-column>
<d-column header="操作" fixed-right="0px" width="130">
<template #default="scope">
<a class="devui-link" style="margin-right: 8px" @click="openVulnDetail(scope.row)">详情</a>
<d-button @click="handleViewAIModal(scope.row)" variant="text" color="primary"> AI问答 </d-button>
</template>
</d-column>
</d-table>
<NoData v-else :small="false"></NoData>
<div class="mt-20 mb-20 flex justify-end" v-if="dataLists.length > 0">
<d-pagination
size="md"
:page-size-options="[10, 20, 50]"
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:max-items="5"
:can-change-page-size="true"
:can-view-total="true"
total-item-text="总计"
@page-index-change="getList()"
@page-size-change="getList()"
/>
</div>
</Card>
</div>
<!-- 漏洞详情 -->
<d-drawer v-model="vulnDetailVisable" style="width: auto">
<VulnerabilityDetail :vulnId="currentVuln.id" @close="colseVulnDetail"></VulnerabilityDetail>
</d-drawer>
<AIModal ref="AIModalRef" />
<EffectedComponents ref="modalRef" />
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import VulnerabilityDetail from './VulnerabilityDetail.vue';
import EffectedComponents from './effectedComponents.vue';
import { alertsPage } from '@/api/jyh/home';
import dayjs from 'dayjs';
import NoData from '@/components/NoData/NoData.vue';
import AIModal from '../AIModal.vue';
import { getVulnerabilitiespage } from '@/api/repo';
const route = useRoute();
const title = computed(() => route.meta?.reportTitle || '漏洞感知列表');
const pager = ref({
total: 10,
pageIndex: 1,
pageSize: 10
});
const newFormData = ref({
vulnId: '',
affectedComponentCount: '',
severity: '',
});
const loading = ref(false);
const AIModalRef = ref(null);
// 清空高级搜索
const clear = () => {
newFormData.value = {
vulnId: '',
affectedComponentCount: '',
severity: '',
};
getList();
};
const tagMap = {
Critical: {
text: '致命',
color: '#c7000b'
},
High: {
text: '高',
color: '#f66f6a'
},
Medium: {
text: '中',
color: '#fac20a'
},
Low: {
text: '低',
color: '#5e7ce0'
},
critical: {
text: '致命',
color: '#c7000b'
},
high: {
text: '高',
color: '#f66f6a'
},
medium: {
text: '中',
color: '#fac20a'
},
low: {
text: '低',
color: '#5e7ce0'
}
};
const tagArray = [
{ value: 'critical', name: '致命' },
{ value: 'high', name: '高' },
{ value: 'medium', name: '中' },
{ value: 'low', name: '低' }
]
const vulnDetailVisable = ref(false);
const currentVuln = ref();
const openVulnDetail = (row) => {
vulnDetailVisable.value = true;
currentVuln.value = row;
};
const modalRef = ref(null);
function showModal(row) {
if (modalRef.value) {
modalRef.value.setDisabled(false);
modalRef.value.open(row);
}
}
// 打开弹框方法
const handleViewAIModal = (resultId) => {
AIModalRef.value.open(resultId); // 传递result_id参数
};
const colseVulnDetail = () => {
vulnDetailVisable.value = false;
};
const vulnId = ref('');
const dataLists = ref([]);
const getList = async (current) => {
loading.value = true
if(current) pager.value.pageIndex=current;
const { data } = await getVulnerabilitiespage({
vulnId: newFormData.value.vulnId,
current: current || pager.value.pageIndex,
affectedComponentCount: newFormData.value.affectedComponentCount,
severity: newFormData.value.severity,
size: pager.value.pageSize
}).finally(()=>{
loading.value = false
});
dataLists.value = data?.data?.data?.records || [
{
"id": 184783,
"taskId": null,
"softwareId": null,
"componentId": null,
"vulnId": "CVE-2024-31585",
"cweId": "CWE-193",
"severity": "medium",
"vulnType": "CVE",
"cvssScore": 5.3,
"attackVector": null,
"attackComplexity": null,
"userInteraction": null,
"privilegesRequired": null,
"exploitabilityScore": null,
"impactScore": null,
"description": "FFmpeg version n5.1 to n6.1 was discovered to contain an Off-by-one Error vulnerability in libavfilter/avf_showspectrum.c. This vulnerability allows attackers to cause a Denial of Service (DoS) via a crafted input.",
"extraInfo": "{\"refs\": [\"https://gist.github.com/1047524396/dc2c64ffe0c3934a6176bcd2c5cf5656\", \"https://github.com/FFmpeg/FFmpeg/commit/81df787b53eb5c6433731f6eaaf7f2a94d8a8c80\", \"https://github.com/ffmpeg/ffmpeg/commit/ab0fdaedd1e7224f7e84ea22fcbfaa4ca75a6c06\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6G7EYH2JAK5OJPVNC6AXYQ5K7YGYNCDN/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IPETICRXUOGRIM4U3BCRTIKE3IZWCSBT/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LE3ASLH6QF2E5OVJI5VA3JSEPJFFFMNY/\"]}",
"fixIssue": null,
"patchLink": null,
"source": "HUST",
"publishDate": "2024-04-17T19:15:08.000+00:00",
"fixVersion": null,
"exploitability": null,
"createTime": "2025-10-14T21:00:03.000+00:00",
"updateTime": "2025-10-14T21:00:03.000+00:00",
"componentName": null,
"componentVersion": null,
"effectedComponentCount": null,
"effectedComponents": null
},
{
"id": 184780,
"taskId": null,
"softwareId": null,
"componentId": null,
"vulnId": "CVE-2024-31578",
"cweId": null,
"severity": "high",
"vulnType": "CVE",
"cvssScore": 7.5,
"attackVector": null,
"attackComplexity": null,
"userInteraction": null,
"privilegesRequired": null,
"exploitabilityScore": null,
"impactScore": null,
"description": "FFmpeg version n6.1.1 was discovered to contain a heap use-after-free via the av_hwframe_ctx_init function.",
"extraInfo": "{\"refs\": [\"https://github.com/ffmpeg/ffmpeg/commit/3bb00c0a420c3ce83c6fafee30270d69622ccad7\", \"https://gist.github.com/1047524396/45400cce5859d78dcd3a62010df8d179\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LE3ASLH6QF2E5OVJI5VA3JSEPJFFFMNY/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IPETICRXUOGRIM4U3BCRTIKE3IZWCSBT/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6G7EYH2JAK5OJPVNC6AXYQ5K7YGYNCDN/\"]}",
"fixIssue": null,
"patchLink": null,
"source": "HUST",
"publishDate": "2024-04-17T14:15:08.000+00:00",
"fixVersion": null,
"exploitability": null,
"createTime": "2025-10-14T21:00:03.000+00:00",
"updateTime": "2025-10-14T21:00:03.000+00:00",
"componentName": null,
"componentVersion": null,
"effectedComponentCount": 1,
"effectedComponents": null
},
{
"id": 184781,
"taskId": null,
"softwareId": null,
"componentId": null,
"vulnId": "CVE-2024-31578",
"cweId": null,
"severity": "high",
"vulnType": "CVE",
"cvssScore": 7.5,
"attackVector": null,
"attackComplexity": null,
"userInteraction": null,
"privilegesRequired": null,
"exploitabilityScore": null,
"impactScore": null,
"description": "FFmpeg version n6.1.1 was discovered to contain a heap use-after-free via the av_hwframe_ctx_init function.",
"extraInfo": "{\"refs\": [\"https://github.com/ffmpeg/ffmpeg/commit/3bb00c0a420c3ce83c6fafee30270d69622ccad7\", \"https://gist.github.com/1047524396/45400cce5859d78dcd3a62010df8d179\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/LE3ASLH6QF2E5OVJI5VA3JSEPJFFFMNY/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/IPETICRXUOGRIM4U3BCRTIKE3IZWCSBT/\", \"https://lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/6G7EYH2JAK5OJPVNC6AXYQ5K7YGYNCDN/\"]}",
"fixIssue": null,
"patchLink": null,
"source": "HUST",
"publishDate": "2024-04-17T14:15:08.000+00:00",
"fixVersion": null,
"exploitability": null,
"createTime": "2025-10-14T21:00:03.000+00:00",
"updateTime": "2025-10-14T21:00:03.000+00:00",
"componentName": null,
"componentVersion": null,
"effectedComponentCount": null,
"effectedComponents": null
}
];
pager.value.total = data.data.data?.total;
};
onMounted(() => {
getList();
});
const search = () => {
pager.value.pageIndex = 1;
getList();
};
</script>
<style scoped lang="scss">
@import 'devui-theme/styles-var/devui-var.scss';
.page-wrap {
margin: 16px;
.page-title {
color: #191919;
font-family: HarmonyOS Sans SC;
font-weight: medium;
font-size: 18px;
line-height: 26px;
letter-spacing: 0px;
text-align: left;
}
.g-content-card {
overflow: hidden;
padding: 0;
}
}
.search-form {
position: relative;
border-radius: 8px 0px 8px 8px;
margin-right: 20px;
//background: #F2F5FC;
.left-btn {
position: absolute;
right: 28px;
bottom: 4px;
}
.output-btn {
color: #191919;
font-family: HarmonyOS Sans SC;
font-weight: regular;
font-size: 14px;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
.jyh-form-operation {
margin-left: 20px !important;
}
}
</style>