可信代码库-深度检测分析列表开发暂时不展示

This commit is contained in:
付民康
2025-05-09 10:31:10 +08:00
parent 3fa94693b2
commit 95bac2fe24
3 changed files with 553 additions and 0 deletions

View File

@@ -0,0 +1,286 @@
<template>
<d-drawer v-model="detailDrawerCtrl" class="w-[800px] p-[20px]">
<div class="flex flex-col h-full">
<div class="flex justify-between items-center mb-[12px]">
<p class="text-[18px]/[26px] ">恶意代码详情</p>
<d-icon @click="detailDrawerCtrl = false" name="icon-close" size="18px" class="cursor-pointer text-[#71757F]" />
</div>
<div class="flex flex-col mb-[12px] flex-1 h-0">
<div class="malware-detail-card mb-[16px]">
<p class="title">文件基本信息</p>
<div class="content">
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">文件名称</div>
<div class="single-line-ellipsis">{{ props.detailRow?.packageFullName || '--' }}</div>
<d-icon name="icon-copy" class="ml-[8px] cursor-pointer" @click="handleCopy(props.detailRow?.packageFullName)" />
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">文件路径</div>
<div class="single-line-ellipsis">{{ props.detailRow?.packagePath || '--' }}</div>
<d-icon name="icon-copy" class="ml-[8px] cursor-pointer" @click="handleCopy(props.detailRow?.packagePath)" />
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">文件版本号</div>
<div class="single-line-ellipsis">{{ props.detailRow?.packageVersion || '--' }}</div>
<d-icon name="icon-copy" class="ml-[8px] cursor-pointer" @click="handleCopy(props.detailRow?.packageVersion)" />
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">LLM名称</div>
<div class="single-line-ellipsis">{{ props.detailRow?.llmName || '--' }}</div>
<d-icon name="icon-copy" class="ml-[8px] cursor-pointer" @click="handleCopy(props.detailRow?.llmName)" />
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">敏感API总数</div>
<div class="single-line-ellipsis">{{ props.detailRow?.totalApisCalledCount }}</div>
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">可疑文件总数</div>
<div class="single-line-ellipsis">{{ props.detailRow?.suspiciousFilesCount }}</div>
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">是否恶意代码</div>
<div class="single-line-ellipsis">
<span class="card-val" v-if="props.detailRow?.isMalicious===0">
<d-tag color="#5e7ce0" size="sm"></d-tag>
</span>
<span class="card-val" v-else>
<d-tag color="#c7000b" size="sm"></d-tag>
</span>
</div>
</div>
<div class="flex items-center">
<div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">大模型是否正常回复</div>
<div class="single-line-ellipsis">
<span class="card-val" v-if="props.detailRow?.isModelResponded===0">
<d-tag color="#5e7ce0" size="sm"></d-tag>
</span>
<span class="card-val" v-else>
<d-tag color="#c7000b" size="sm"></d-tag>
</span>
</div>
</div>
<!-- <div class="flex items-center">-->
<!-- <div class="w-[160px] pr-[20px] flex-shrink-0 text-[#595959]">文件sha256</div>-->
<!-- <div :title="malwareDetails?.code" class="single-line-ellipsis">{{ malwareDetails?.code }}</div>-->
<!-- <d-icon name="icon-copy" class="ml-[8px] cursor-pointer" @click="handleCopy(malwareDetails?.code)" />-->
<!-- </div>-->
</div>
</div>
<div class="malware-detail-card mb-[16px]">
<p class="title">调用的敏感API列表</p>
<div class="content">
<d-table
:data="malwareDetails?.apisCalled"
class="w-full bg-white malware-list-table"
:fix-header="malwareDetails?.apisCalled.length > 0"
max-height="300px"
>
<d-column field="isMalicious" header="是否恶意代码">
<template #default="scope">
<span class="card-val" v-if="scope.row.isMalicious===0">
<d-tag color="#5e7ce0" size="sm">否</d-tag>
</span>
<span class="card-val" v-else>
<d-tag color="#c7000b" size="sm">是</d-tag>
</span>
</template>
</d-column>
<d-column
field="maliciousCodeCategory"
header="恶意代码分类"
/>
<template #empty>
<NoData style="padding: 0; margin: -30px 0;" :width="80" />
</template>
</d-table>
<!-- <d-pagination-->
<!-- class="flex justify-end mt-[20px]"-->
<!-- :total="pager.total"-->
<!-- v-model:pageSize="pager.pageSize"-->
<!-- v-model:pageIndex="pager.pageIndex"-->
<!-- :can-view-total="true"-->
<!-- :can-change-page-size="true"-->
<!-- :max-items="5"-->
<!-- @page-index-change="pageIndexChange"-->
<!-- @page-size-change="pageSizeChange"-->
<!-- />-->
</div>
</div>
<div class="malware-detail-card mb-[16px]">
<p class="title">包含恶意代码的文件列表</p>
<div class="content">
<d-table
:data="malwareDetails?.source"
class="w-full bg-white malware-list-table"
:fix-header="malwareDetails?.source.length > 0"
max-height="300px"
>
<d-column
field="sink"
header="恶意汇"
/>
<d-column
field="flow"
header="传播流向"
/>
<d-column
field="purpose"
header="代码目的"
/>
<d-column
field="analysis"
header="LLM对于这个代码片段的分析"
/>
<d-column
field="createTime"
header="创建时间"
/>
<template #empty>
<NoData style="padding: 0; margin: -30px 0;" :width="80" />
</template>
</d-table>
<!-- <d-pagination-->
<!-- class="flex justify-end mt-[20px]"-->
<!-- :total="pager.total"-->
<!-- v-model:pageSize="pager.pageSize"-->
<!-- v-model:pageIndex="pager.pageIndex"-->
<!-- :can-view-total="true"-->
<!-- :can-change-page-size="true"-->
<!-- :max-items="5"-->
<!-- @page-index-change="pageIndexChange"-->
<!-- @page-size-change="pageSizeChange"-->
<!-- />-->
</div>
</div>
<!-- <div class="malware-detail-card flex-1 h-0">-->
<!-- <p class="title">关键日志</p>-->
<!-- <div class="content flex flex-col flex-1 h-0">-->
<!-- <div class="log-box flex-1 overflow-y-scroll">-->
<!-- {{ malwareDetails?.analysis }}-->
<!-- {{ malwareDetails?.code }}-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</d-drawer>
</template>
<script setup lang="ts">
import { reactive, shallowRef, defineProps, ref, defineExpose } from 'vue';
import NoData from "@/components/NoData/NoData.vue";
import { getMalwareDetailApi, getMalwareDetailApi2 } from '@/api/inboundTask/inboundTaskApi';
import {Message} from "vue-devui/message";
import { type MalwareDetailType } from "@/api/inboundTask/inboundTaskType";
const props = defineProps({
detailRow: {
type: Object,
required: true,
},
});
const detailDrawerCtrl = ref(false);
const malwareDetails = shallowRef<MalwareDetailType | null>(null);
const threatContentList = shallowRef([]);
const pager = reactive({
pageIndex: 1,
pageSize: 10,
total: 0,
});
async function getMalwareDetails(id) {
try {
const res = await getMalwareDetailApi2({
current: 1,
size: 10,
maliciousId: id
});
if(res.data.records&&res.data.records.length>0) {
malwareDetails.value = res.data.records[0];
}
} catch (e) {
Message.error('接口错误,查询详情失败');
}
getCurrentPageData();
}
function getCurrentPageData() {
// pager.total = malwareDetails.value.contentInfo.total;
// const endIndex = pager.pageIndex * pager.pageSize;
// threatContentList.value = malwareDetails.value.contentInfo.list.slice(endIndex - pager.pageSize, endIndex);
}
function pageIndexChange() {
getCurrentPageData();
}
function pageSizeChange() {
pager.pageIndex = 1;
getCurrentPageData();
}
function handleCopy(text: string) {
inputCopy(text);
}
const openDetail = (id) => {
detailDrawerCtrl.value = true;
getMalwareDetails(id)
}
function inputCopy(text: string) {
const aux = document.createElement('input');
aux.setAttribute('value', text);
document.body.appendChild(aux);
aux.select();
document.execCommand('copy');
document.body.removeChild(aux);
Message({ type: 'success', message: '复制成功' });
}
// 暴露方法,供父组件调用
defineExpose({
openDetail,
});
</script>
<style scoped lang="scss">
.malware-detail-card {
border-radius: 8px;
border: 1px solid #EEF0F5;
display: flex;
flex-direction: column;
.title {
color: #191919;
padding: 10px 16px;
font-size: 14px;
line-height: 22px;
background-color: #F3F3F3;
}
.content {
padding: 20px 16px;
:deep(.devui-table__thead .header-container) {
background-color: #F3F3F3;
}
}
}
.log-box {
border-radius: 8px;
background: #F7F8FA;
border: 1px solid #EEF0F5;
padding: 8px 16px;
}
.single-line-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@@ -0,0 +1,264 @@
<template>
<div>
<div>
<d-search
v-model="searchText"
icon-position="left"
class="w-[400px] mb-[12px]"
placeholder="请输入搜索内容"
@search="getMalwareList"
/>
</div>
<d-table
:data="tableData"
:show-loading="searchLoading"
class="jyh-table"
:fix-header="tableData.length > 0"
max-height="600px"
@sort-change="sortChange"
>
<d-column type="index" width="48px" />
<!-- <d-column field="packageFullName" width="220px">-->
<!-- <template #header>-->
<!-- 文件名称-->
<!-- <TableFilter field="packageFullName" :condition="filterData.packageFullName" @filter-change="filterChange" />-->
<!-- </template>-->
<!-- <template #default="{ row }">-->
<!-- <a class="devui-link" @click="openMalwareDetail(row)">{{ row.packageFullName }}</a>-->
<!-- </template>-->
<!-- </d-column>-->
<!-- <d-column field="category">-->
<!-- <template #header>-->
<!-- 恶意类别-->
<!-- <TableFilter-->
<!-- type="radio"-->
<!-- field="category"-->
<!-- :condition="filterData.category"-->
<!-- :filter-list="categoryFilterOptions"-->
<!-- @filter-change="filterChange"-->
<!-- />-->
<!-- </template>-->
<!-- </d-column>-->
<d-column field="packageName" header="文件名称" width="180">
<template #default="{ row }">
<a class="devui-link" @click="openMalwareDetail(row)">{{ row.packageFullName }}</a>
</template>
</d-column>
<d-column field="packagePath" header="文件路径" width="180" show-overflow-tooltip/>
<d-column field="packageVersion" header="文件版本号" show-overflow-tooltip/>
<d-column field="llmName" header="LLM名称" show-overflow-tooltip/>
<d-column field="totalApisCalledCount" header="敏感API总数" show-overflow-tooltip/>
<d-column field="suspiciousFilesCount" header="可疑文件总数" show-overflow-tooltip/>
<d-column field="isMalicious" header="是否恶意代码">
<template #default="scope">
<span class="card-val" v-if="scope.row.isMalicious===0">
<d-tag color="#5e7ce0" size="sm">否</d-tag>
</span>
<span class="card-val" v-else>
<d-tag color="#c7000b" size="sm">是</d-tag>
</span>
</template>
</d-column>
<d-column field="isModelResponded" header="大模型是否正常回复" width="180">
<template #default="scope">
<span class="card-val" v-if="scope.row.isModelResponded===0">
<d-tag color="#5e7ce0" size="sm">否</d-tag>
</span>
<span class="card-val" v-else>
<d-tag color="#c7000b" size="sm">是</d-tag>
</span>
</template>
</d-column>
<d-column field="createTime" header="检测时间" width="180" show-overflow-tooltip/>
<!-- <d-column field="threatLevel">-->
<!-- <template #header>-->
<!-- 威胁级别-->
<!-- <TableFilter-->
<!-- type="radio"-->
<!-- field="threatLevel"-->
<!-- :condition="filterData.threatLevel"-->
<!-- :filter-list="threatLevelFilterList"-->
<!-- @filter-change="filterChange"-->
<!-- />-->
<!-- </template>-->
<!-- <template #default="{ row }">-->
<!-- <d-status :type="ThreatLevelMap[row.threatLevel].statusType">-->
<!-- {{ ThreatLevelMap[row.threatLevel].label }}-->
<!-- </d-status>-->
<!-- </template>-->
<!-- </d-column>-->
<!-- <d-column field="confidenceCoefficient">-->
<!-- <template #header>-->
<!-- 置信度-->
<!-- <TableFilter-->
<!-- type="radio"-->
<!-- field="confidenceCoefficient"-->
<!-- :condition="filterData.confidenceCoefficient"-->
<!-- :filter-list="confidenceCoefficientFilterList"-->
<!-- @filter-change="filterChange"-->
<!-- />-->
<!-- </template>-->
<!-- <template #default="{ row }">-->
<!-- <d-tag size="sm" :type="ConfidenceCoefficientMap[row.confidenceCoefficient].statusType">-->
<!-- {{ ConfidenceCoefficientMap[row.confidenceCoefficient].label }}-->
<!-- </d-tag>-->
<!-- </template>-->
<!-- </d-column>-->
<!-- <d-column field="testResult" header="检测结果" />-->
<template #empty>
<NoData v-if="!searchLoading" />
</template>
</d-table>
<d-pagination
class="flex justify-end mt-[20px]"
:total="pager.total"
v-model:pageSize="pager.pageSize"
v-model:pageIndex="pager.pageIndex"
:can-view-total="true"
:can-change-page-size="true"
:max-items="5"
@page-index-change="pageIndexChange"
@page-size-change="pageSizeChange"
/>
</div>
<Detail ref="MalwareDetailRef" :detailRow="detailRow" />
</template>
<script lang="ts" setup>
import { reactive, ref, shallowRef } from 'vue';
import TableFilter from '@/components/TableFilter/TableFilter.vue';
import NoData from '@/components/NoData/NoData.vue';
import Detail from './Detail.vue';
import { getMalwareListApi } from '@/api/inboundTask/inboundTaskApi';
import { type MalwareListItemType } from '@/api/inboundTask/inboundTaskType';
import { Message } from 'vue-devui/message';
import { useRoute } from 'vue-router';
enum ThreatLevelEnum {
HIGH = 'high',
MD = 'medium',
LOW = 'low'
}
enum ConfidenceCoefficientEnum {
HIGH = 'high',
MD = 'medium',
LOW = 'low'
}
const route = useRoute();
const versionId = route.params.versionId;
const searchText = ref('');
const searchLoading = ref(false);
const MalwareDetailRef = ref<InstanceType<typeof MalwareDetail> | null>(null)
const tableData = shallowRef<MalwareListItemType[]>([]);
const pager = reactive({
pageSize: 10,
pageIndex: 1,
total: 0
});
const ThreatLevelMap = {
[ThreatLevelEnum.HIGH]: { label: '高危', statusType: 'error' },
[ThreatLevelEnum.MD]: { label: '中危', statusType: 'warning' },
[ThreatLevelEnum.LOW]: { label: '低危', statusType: 'waiting' }
};
const ConfidenceCoefficientMap = {
[ConfidenceCoefficientEnum.HIGH]: { label: '高', statusType: 'success' },
[ConfidenceCoefficientEnum.MD]: { label: '中', statusType: 'warning' },
[ConfidenceCoefficientEnum.LOW]: { label: '低', statusType: 'danger' }
};
const confidenceCoefficientFilterList = [
{ label: '高', value: ConfidenceCoefficientEnum.HIGH },
{ label: '中', value: ConfidenceCoefficientEnum.MD },
{ label: '低', value: ConfidenceCoefficientEnum.LOW }
];
const threatLevelFilterList = [
{ label: '高危', value: ThreatLevelEnum.HIGH },
{ label: '中危', value: ThreatLevelEnum.MD },
{ label: '低危', value: ThreatLevelEnum.LOW }
];
const categoryFilterOptions = [{ label: 'Python', value: 'Python' }];
const filterData = reactive({
packageFullName: '',
threatLevel: '',
confidenceCoefficient: '',
category: ''
});
const detailRow = shallowRef<MalwareListItemType | null>(null);
init();
function init() {
getMalwareList();
}
async function getMalwareList() {
const params = {
current: pager.pageIndex,
size: pager.pageSize,
taskId: '',
softwareId: versionId
};
pager.total = 0;
tableData.value = [];
searchLoading.value = true;
try {
const res = await getMalwareListApi(params);
if (res.data?.code === 200) {
tableData.value = res.data.data.records.map((item) => {
return { ...item, threatLevel: ThreatLevelEnum.HIGH, confidenceCoefficient: ConfidenceCoefficientEnum.HIGH };
});
pager.total = res.data.data.total;
} else {
Message.error(res.data.msg || '查询恶意代码列表失败');
}
} catch (e) {
Message.error('接口错误,查询恶意代码列表失败');
}
searchLoading.value = false;
}
function sortChange(sortInfo: { field: string; direction: 'ASC' | 'DESC' | '' }) {
console.log(sortInfo);
getMalwareList();
}
function filterChange(filterInfo: { field: string; value: any }) {
filterData[filterInfo.field] = filterInfo.value;
getMalwareList();
}
function pageSizeChange() {
pager.pageIndex = 1;
getMalwareList();
}
function pageIndexChange() {
getMalwareList();
}
function openMalwareDetail(row: MalwareListItemType) {
detailRow.value = row;
// 添加检查
if (MalwareDetailRef.value && typeof MalwareDetailRef.value.openDetail === 'function') {
MalwareDetailRef.value.openDetail(row.id)
} else {
console.error('MalwareDetailRef 或 openDetail 方法不可用')
}
}
</script>
<style scoped lang="scss">
.malware-list-table {
:deep(.devui-table__row td) {
padding-top: 8px;
padding-bottom: 8px;
}
:deep(.devui-status.devui-status__bg--warning:before) {
background-color: #fcc800;
}
}
</style>

View File

@@ -52,6 +52,7 @@
<d-tab id="ai" title="AI修复建议"></d-tab>
<d-tab id="licenseInfo" title="许可证信息"></d-tab>
<d-tab id="communityInfo" title="开发者社区信息"></d-tab>
<!-- <d-tab id="DeepDetectionAnalysis" title="深度检测分析" />-->
</d-tabs>
</div>
<div class="version-detail-content">
@@ -63,6 +64,7 @@
<AIRepair :versionId="versionId" v-else-if="selectTab === 'ai'"></AIRepair>
<LicenseInfo :versionId="versionId" v-else-if="selectTab === 'licenseInfo'"></LicenseInfo>
<Malware :versionId="versionId" v-else-if="selectTab === 'Malware'" />
<!-- <DeepDetectionAnalysis :versionId="versionId" v-else-if="selectTab === 'DeepDetectionAnalysis'" />-->
</div>
</div>
</template>
@@ -79,6 +81,7 @@ import AIRepair from '../../AIRepair/index.vue';
import LicenseInfo from '../../LicenseInfo/index.vue';
import Dependence from './Dependency.vue'
import Malware from "@/views/Jyh/Version/Detail/Malware/Malware.vue";
import DeepDetectionAnalysis from "@/views/Jyh/Version/Detail/DeepDetectionAnalysis/index.vue";
const { namespace } = getOrgInfo();
const route = useRoute(); // 获取路由对象
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';