merge junjie_dev into master

feat: ai修复页面更新 & 依赖关系页面

Created-by: user8949
Commit-by: @user8949
Merged-by: user8949
Description: feat: ai修复页面更新 & 依赖关系页面

See merge request: hk_openRepo/OpenRepo_Portal!18
This commit is contained in:
user8949
2025-03-17 16:00:15 +08:00
7 changed files with 335 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

View File

@@ -1,4 +1,17 @@
<template>
<div class="info-outside w-full">
<div class="info">
<div class="flex items-center justify-start w-full gap-1">
<img src="@/assets/imgs/jyh/aiIcon.png">
<span class="text-base font-medium">AI修复建议:</span>
</div>
<div>
<ul>
<li v-for="info in infoList">{{ info }}</li>
</ul>
</div>
</div>
</div>
<div class="ai-container">
<div class="ai-container-card" style="width: 100%;" v-for="(rowItem, index) in list" :key="index">
<Panel :expand="rowItem.expand">
@@ -43,6 +56,7 @@
<template #body>
<div style="padding: 8px 20px 20px 20px; width: 100%;">
<Table :tableConfig="tableConfig" :dataSource="rowItem.data.listData"/>
<div class="w-full flex items-center justify-end"><span>{{ rowItem.data.listData.length }}</span></div>
</div>
</template>
</Panel>
@@ -55,6 +69,11 @@ import { ref } from 'vue';
import Panel from '@/components/AIRepair/Panel.vue';
import Table from '@/components/AIRepair/Table.vue';
const infoList = ref([
'当前代码主要风险为易受常见的注入攻击包括命令注入、SQL注入、表达式注入针对每种攻击应提供相应的防范措施如数据校验、使用安全函数和限制程序权限。',
'相对上一次检查【提升点】在于代码基础编码问题少了47.8%问题总数降低29.3%'
])
const tableConfig = ref([
{
field: 'securityProblemCode',
@@ -122,6 +141,44 @@ const list = ref([
]
}
},
{
expand: true,
data: {
listData: [
{
securityProblemCode: '1',
type: '安全问题',
CWEcode: 'CWE-123',
score: 100
},
{
securityProblemCode: '2',
type: '安全问题',
CWEcode: 'CWE-123',
score: 100
}
]
}
},
{
expand: true,
data: {
listData: [
{
securityProblemCode: '1',
type: '安全问题',
CWEcode: 'CWE-123',
score: 100
},
{
securityProblemCode: '2',
type: '安全问题',
CWEcode: 'CWE-123',
score: 100
}
]
}
},
{
expand: true,
data: {
@@ -204,4 +261,26 @@ const list = ref([
width: 14px;
height: 14px;
}
.info-outside {
margin: 20px 0;
padding: 1px;
border-radius: 8px;
background-image: linear-gradient(134.79deg, #A4F7DF 0%, #A0CEFB 21%, #5F9AFE 43%, #D9B9FC 62%, #01EFBB 73%, #FBAE46 100%);
}
.info {
padding: 10px 20px;
border-radius: 8px;
background-color: #ffffff;
img {
width: 24px;
height: 24px;
}
ul {
list-style: disc;
padding-left: 18px;
line-height: 22px;
}
}
</style>

View File

@@ -0,0 +1,254 @@
<template>
<div class="info w-full">
<div class="flex items-center justify-start w-full gap-1">
<img src="@/assets/imgs/jyh/infoIcon.png">
<span class="text-base font-medium">治理标准:</span>
</div>
<div>
<ul>
<li>
1在依赖冲突或者解决依赖软件漏洞的场景下产品引入的依赖组件与社区的依赖关系不一致从而通过产品自行录入由使用方自行维护可通过产品快速补包流程维护<a class="devui-link">操作指导</a>该部分的依赖组件漏洞由产品自行解决
</li>
<li>
2点击下面组件编码跳转到组件详情页面可直接看到基于当前火车过滤的组件依赖路径
</li>
</ul>
</div>
</div>
<div class="flex items-center justify-end gap-3 mt-3">
<d-button variant="text" icon="export">导出</d-button>
<div class="vertical-line"></div>
<d-button variant="text" @click="openAll(baseTreeTableData1)">
<div v-if="!isAllExpand" class="flex items-center justify-start gap-1">
<img style="width: 14px; height: 14px;" src="@/assets/imgs/jyh/openAll.png">
全部展开
</div>
<div v-else class="flex items-center justify-start gap-1">
<img style="width: 14px; height: 14px;" src="@/assets/imgs/jyh/closeAll.png">
全部关闭
</div>
</d-button>
</div>
<Card simple class="jyh-card mt-3">
<div class="clear-padding">
<d-table ref="table" :data="baseTreeTableData1" >
<d-column width="20px" type="index">
</d-column>
<d-column field="name" header="组件版本名称" show-overflow-tooltip></d-column>
<d-column field="groupid" header="groupid"></d-column>
<d-column field="code" filterable :filter-list="filterList" @filter-change="handleFilterChange" header="组件编号">
<template #default="scope">
<a class="devui-link" @click="showDetail = true">{{ scope.row.code }}</a>
</template>
</d-column>
<d-column field="packageName" filterable :filter-list="packageFilterList" @filter-change="handleFilterChange" header="packageName"></d-column>
<d-column field="version" filterable :filter-list="versionFilterList" @filter-change="handleFilterChange" header="version"></d-column>
<d-column field="language" filterable :filter-list="languageFilterList" @filter-change="handleFilterChange" header="编程语言"></d-column>
<d-column field="number" header="组件漏洞数量">
<template #default="scope">
<a class="devui-link" @click="showDetail = true">{{ scope.row.number }}</a>
</template>
</d-column>
</d-table>
</div>
</Card>
<div class="w-full flex justify-end my-4">
<d-pagination
size="sm"
: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"
/>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
const checked = ref(false);
const showDetail = ref(false);
const table = ref(null)
const isAllExpand = ref(false);
const pager = ref({
pageIndex: 1,
pageSize: 30,
total: 10
})
const filterList = ref([{name: '001', value: '001'}, {name: '002', value: '002'}, {name: '003', value: '003'}, {name: '004', value: '004'}])
const handleFilterChange = (val) => {
if (!val.length) {
baseTreeTableData1.value = [ ...originSource.value ]
return
}
const filterList = val.map((item) => item.value);
baseTreeTableData1.value = originSource.value.filter((item) => filterList.includes(item.code));
};
const originSource = ref([
{
id: '1',
name: 'ssl',
groupid: '2000000',
code: '001',
packageName: '包名称',
version: '202306',
language: 'java',
number: '20',
children: [
{
id: '2',
name: 'ssl',
groupid: '2000000',
code: '001',
packageName: '包名称',
version: '202306',
language: 'java',
number: '20',
children: [
{
id: '3',
name: 'ssl',
groupid: '2000000',
code: '001',
packageName: '包名称',
version: '202306',
language: 'java',
number: '20',
},
{
id: '4',
name: 'ssl',
groupid: '2000000',
code: '001',
packageName: '包名称',
version: '202306',
language: 'java',
number: '20',
}
]
}
]
},
{
id: '5',
name: 'ssl',
groupid: '2000000',
code: '002',
packageName: '包名称',
version: '202306',
language: 'java',
number: '10',
children: [
{
id: '6',
name: 'ssl',
groupid: '2000000',
code: '003',
packageName: '包名称',
version: '202306',
language: 'java',
number: '20',
children: [
{
id: '7',
name: 'ssl',
groupid: '2000000',
code: '003',
packageName: '包名称',
version: '202306',
language: 'java',
number: '11',
},
{
id: '8',
name: 'ssl',
groupid: '2000000',
code: '004',
packageName: '包名称',
version: '202306',
language: 'java',
number: '30',
}
]
}
]
},
{
id: '9',
name: 'ssl',
groupid: '2000000',
code: '001',
packageName: '包名称',
version: '202306',
language: 'java',
number: '5',
}
]);
const baseTreeTableData1 = ref([...originSource.value]);
const packageFilterList = ref(originSource.value.map(item => {
return {name: item.packageName, value: item.packageName}
}))
const versionFilterList = ref(originSource.value.map(item => {
return {name: item.version, value: item.version}
}))
const languageFilterList = ref(originSource.value.map(item => {
return {name: item.language, value: item.language}
}))
const openAll = (tree) => {
if (!tree || !tree.length) {
return
}
tree.forEach(node => {
table.value.store.toggleRowExpansion(node);
if (node.children) {
openAll(node.children);
}
})
isAllExpand.value = !isAllExpand.value
}
const sortNumberMethod = (a, b) => {
return a.number > b.number
}
</script>
<style scoped lang="scss">
@import 'devui-theme/styles-var/devui-var.scss';
.clear-padding {
margin: -16px -20px;
}
:deep(.devui-table__cell) {
display: flex;
align-items: center;
.devui-table__tree-operate {
transform: translateY(-3px);
}
}
.info {
padding: 10px 20px;
border-radius: 4px;
background: #E1E8FD;
img {
width: 14px;
height: 14px;
}
ul {
padding-left: 18px;
line-height: 22px;
}
}
.vertical-line {
width: 1px;
height: 20px;
background-color: #dcdcdc; /* 设置竖线颜色 */
margin: 0 8px; /* 设置竖线与按钮的间距 */
}
</style>

View File

@@ -46,6 +46,7 @@
<version-info v-if="selectTab === 'bbxx'" @changeTabs="changeTabs"></version-info>
<vulnerabilities-list v-else-if="selectTab === 'ldxx'"></vulnerabilities-list>
<community-info v-else-if="selectTab === 'communityInfo'"></community-info>
<Dependence v-else-if="selectTab === 'ylgx'"></Dependence>
<SBOM v-else-if="selectTab === 'SBOM'" />
<AIRepair v-else-if="selectTab === 'ai'"></AIRepair>
<LicenseInfo v-else-if="selectTab === 'licenseInfo'"></LicenseInfo>
@@ -63,6 +64,7 @@ import VersionInfo from './VersionInfo.vue';
import SBOM from './SBOM.vue';
import AIRepair from '../../AIRepair/index.vue';
import LicenseInfo from '../../LicenseInfo/index.vue';
import Dependence from './Dependency.vue'
const { namespace } = getOrgInfo();
const route = useRoute(); // 获取路由对象
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';