mirror of
https://github.com/pure-admin/pure-admin-thin.git
synced 2025-04-24 23:47:17 +08:00
feat: 增加管理页面
This commit is contained in:
parent
adc385edca
commit
697c1463ca
@ -69,6 +69,7 @@
|
|||||||
"responsive-storage": "^2.2.0",
|
"responsive-storage": "^2.2.0",
|
||||||
"sortablejs": "^1.15.2",
|
"sortablejs": "^1.15.2",
|
||||||
"vue": "^3.4.31",
|
"vue": "^3.4.31",
|
||||||
|
"vue-chartjs": "^5.3.1",
|
||||||
"vue-router": "^4.4.0",
|
"vue-router": "^4.4.0",
|
||||||
"vue-tippy": "^6.4.4",
|
"vue-tippy": "^6.4.4",
|
||||||
"vue-types": "^5.1.2"
|
"vue-types": "^5.1.2"
|
||||||
|
27
pnpm-lock.yaml
generated
27
pnpm-lock.yaml
generated
@ -71,6 +71,9 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.4.31
|
specifier: ^3.4.31
|
||||||
version: 3.4.31(typescript@5.5.3)
|
version: 3.4.31(typescript@5.5.3)
|
||||||
|
vue-chartjs:
|
||||||
|
specifier: ^5.3.1
|
||||||
|
version: 5.3.1(chart.js@4.4.3)(vue@3.4.31(typescript@5.5.3))
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: ^4.4.0
|
specifier: ^4.4.0
|
||||||
version: 4.4.0(vue@3.4.31(typescript@5.5.3))
|
version: 4.4.0(vue@3.4.31(typescript@5.5.3))
|
||||||
@ -894,6 +897,9 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.25':
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
|
'@kurkle/color@0.3.2':
|
||||||
|
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -1450,6 +1456,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
|
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
|
||||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||||
|
|
||||||
|
chart.js@4.4.3:
|
||||||
|
resolution: {integrity: sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==}
|
||||||
|
engines: {pnpm: '>=8'}
|
||||||
|
|
||||||
chokidar@3.6.0:
|
chokidar@3.6.0:
|
||||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
@ -3772,6 +3782,12 @@ packages:
|
|||||||
vscode-uri@3.0.8:
|
vscode-uri@3.0.8:
|
||||||
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
|
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
|
||||||
|
|
||||||
|
vue-chartjs@5.3.1:
|
||||||
|
resolution: {integrity: sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==}
|
||||||
|
peerDependencies:
|
||||||
|
chart.js: ^4.1.1
|
||||||
|
vue: ^3.0.0-0 || ^2.7.0
|
||||||
|
|
||||||
vue-demi@0.14.8:
|
vue-demi@0.14.8:
|
||||||
resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
|
resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@ -4511,6 +4527,8 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
|
'@kurkle/color@0.3.2': {}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@ -5176,6 +5194,10 @@ snapshots:
|
|||||||
|
|
||||||
chalk@5.3.0: {}
|
chalk@5.3.0: {}
|
||||||
|
|
||||||
|
chart.js@4.4.3:
|
||||||
|
dependencies:
|
||||||
|
'@kurkle/color': 0.3.2
|
||||||
|
|
||||||
chokidar@3.6.0:
|
chokidar@3.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
anymatch: 3.1.3
|
anymatch: 3.1.3
|
||||||
@ -7602,6 +7624,11 @@ snapshots:
|
|||||||
|
|
||||||
vscode-uri@3.0.8: {}
|
vscode-uri@3.0.8: {}
|
||||||
|
|
||||||
|
vue-chartjs@5.3.1(chart.js@4.4.3)(vue@3.4.31(typescript@5.5.3)):
|
||||||
|
dependencies:
|
||||||
|
chart.js: 4.4.3
|
||||||
|
vue: 3.4.31(typescript@5.5.3)
|
||||||
|
|
||||||
vue-demi@0.14.8(vue@3.4.31(typescript@5.5.3)):
|
vue-demi@0.14.8(vue@3.4.31(typescript@5.5.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.4.31(typescript@5.5.3)
|
vue: 3.4.31(typescript@5.5.3)
|
||||||
|
47
src/components/Card/Card.vue
Normal file
47
src/components/Card/Card.vue
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<!-- src/components/Card.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">{{ title }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { defineProps } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.card {
|
||||||
|
margin-bottom: 10px; /* Reduce the margin to make cards closer */
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
padding: 10px 15px; /* Reduce padding for a tighter look */
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
padding: 15px; /* Reduce padding for a tighter look */
|
||||||
|
}
|
||||||
|
</style>
|
22
src/router/modules/project.ts
Normal file
22
src/router/modules/project.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export default {
|
||||||
|
path: "/project",
|
||||||
|
name: "Project",
|
||||||
|
redirect: "/project/index",
|
||||||
|
meta: {
|
||||||
|
title: "项目管理",
|
||||||
|
icon: "ri:projector-line",
|
||||||
|
rank: 1
|
||||||
|
},
|
||||||
|
component: () => import("@/layout/index.vue"),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/project/index",
|
||||||
|
name: "ProjectIndex",
|
||||||
|
component: () => import("@/views/project/ProjectManagement.vue"),
|
||||||
|
meta: {
|
||||||
|
title: "项目管理",
|
||||||
|
showLink: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -1,11 +1,171 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { Bar } from "vue-chartjs";
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
Tooltip,
|
||||||
|
Legend
|
||||||
|
} from "chart.js";
|
||||||
|
import Card from "@/components/Card/Card.vue";
|
||||||
|
ChartJS.register(BarElement, CategoryScale, LinearScale, Tooltip, Legend);
|
||||||
|
|
||||||
|
const projectInfo = ref({
|
||||||
|
projects: 32,
|
||||||
|
repositories: 60,
|
||||||
|
scanTimes: 10,
|
||||||
|
scanFiles: 62655
|
||||||
|
});
|
||||||
|
|
||||||
|
const vulnerabilities = ref([
|
||||||
|
{ id: "CVE-2024-9999", description: "发生堆缓冲区溢出攻击" },
|
||||||
|
{ id: "CVE-123456", description: "发布在一天之前 2024-7-23 11:44" }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const recentScansData = ref({
|
||||||
|
labels: ["一月", "二月", "三月", "四月", "五月"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "软件成分分析",
|
||||||
|
backgroundColor: "#72a4d2",
|
||||||
|
data: [613, 448, 540, 652, 977]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "静态代码扫描(SAST)",
|
||||||
|
backgroundColor: "#8cd17d",
|
||||||
|
data: [138, 936, 777, 590, 54]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const issuesRankingData = ref({
|
||||||
|
labels: ["TypeError", "IndexError", "ValueError"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "违规问题",
|
||||||
|
backgroundColor: ["#ff6384", "#36a2eb", "#ffcd56"],
|
||||||
|
data: [582, 421, 747]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const appRankingData = ref({
|
||||||
|
labels: ["TestGood", "Remix", "App2", "阿坡坡", "A泡泡"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "致命",
|
||||||
|
backgroundColor: "#ff6384",
|
||||||
|
data: [61, 54, 77, 65, 54]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "严重",
|
||||||
|
backgroundColor: "#36a2eb",
|
||||||
|
data: [44, 44, 31, 59, 12]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "重要",
|
||||||
|
backgroundColor: "#ffcd56",
|
||||||
|
data: [13, 13, 65, 43, 97]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<!--<template>-->
|
||||||
|
<!-- <div class="dashboard">-->
|
||||||
|
<!-- <h1>软件安全赋能平台</h1>-->
|
||||||
|
<!-- <div class="status-overview">-->
|
||||||
|
<!-- <div class="project-info">-->
|
||||||
|
<!-- <h2>项目信息</h2>-->
|
||||||
|
<!-- <div class="info-box">-->
|
||||||
|
<!-- <p>项目数量(个): {{ projectInfo.projects }}</p>-->
|
||||||
|
<!-- <p>仓库数量(个): {{ projectInfo.repositories }}</p>-->
|
||||||
|
<!-- <p>扫描次数: {{ projectInfo.scanTimes }}</p>-->
|
||||||
|
<!-- <p>扫描文件数量: {{ projectInfo.scanFiles }}</p>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="vulnerabilities">-->
|
||||||
|
<!-- <h2>最新漏洞与补丁提示</h2>-->
|
||||||
|
<!-- <ul>-->
|
||||||
|
<!-- <li v-for="vulnerability in vulnerabilities" :key="vulnerability.id">-->
|
||||||
|
<!-- {{ vulnerability.id }}: {{ vulnerability.description }}-->
|
||||||
|
<!-- </li>-->
|
||||||
|
<!-- </ul>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="recent-scans">-->
|
||||||
|
<!-- <h2>近期扫描趋势</h2>-->
|
||||||
|
<!-- <Bar :data="recentScansData" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="details">-->
|
||||||
|
<!-- <div class="issues-ranking">-->
|
||||||
|
<!-- <h2>违规问题排行</h2>-->
|
||||||
|
<!-- <Bar :data="issuesRankingData" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="app-ranking">-->
|
||||||
|
<!-- <h2>违规应用排行</h2>-->
|
||||||
|
<!-- <Bar :data="appRankingData" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!--</template>-->
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="dashboard">
|
||||||
<h1>软件安全赋能平台</h1>
|
<div class="grid-container">
|
||||||
|
<Card title="项目信息">
|
||||||
|
<div class="info-box">
|
||||||
|
<p>项目数量(个): {{ projectInfo.projects }}</p>
|
||||||
|
<p>仓库数量(个): {{ projectInfo.repositories }}</p>
|
||||||
|
<p>扫描次数: {{ projectInfo.scanTimes }}</p>
|
||||||
|
<p>扫描文件数量: {{ projectInfo.scanFiles }}</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card title="最新漏洞与补丁提示">
|
||||||
|
<ul>
|
||||||
|
<li v-for="vulnerability in vulnerabilities" :key="vulnerability.id">
|
||||||
|
{{ vulnerability.id }}: {{ vulnerability.description }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Card>
|
||||||
|
<Card title="近期扫描趋势">
|
||||||
|
<Bar :data="recentScansData" />
|
||||||
|
</Card>
|
||||||
|
<Card title="违规问题排行">
|
||||||
|
<Bar :data="issuesRankingData" />
|
||||||
|
</Card>
|
||||||
|
<Card title="违规应用排行">
|
||||||
|
<Bar :data="appRankingData" />
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
/* Add your styles here */
|
.dashboard {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f4f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 10px; /* Reduce the gap to make cards closer */
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-box p {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
padding: 10px;
|
||||||
|
margin-bottom: 5px; /* Reduce margin for a tighter look */
|
||||||
|
background: #f2f2f2;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
70
src/views/project/ProjectDetail.vue
Normal file
70
src/views/project/ProjectDetail.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<!-- src/components/ProjectDetails.vue -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const projectName = ref("");
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
projectName.value = route.params.name as string;
|
||||||
|
});
|
||||||
|
|
||||||
|
const projectDetails = ref({
|
||||||
|
creator: "Asiv",
|
||||||
|
createTime: "2024-7-11 15:30:46",
|
||||||
|
team: "Asiv's Team",
|
||||||
|
scanDetails: {
|
||||||
|
softwareComposition: {
|
||||||
|
scanTimes: "0x111",
|
||||||
|
avgScanTime: "20s",
|
||||||
|
sourceBranch: "main"
|
||||||
|
},
|
||||||
|
componentCount: 23,
|
||||||
|
vulnerabilities: 0,
|
||||||
|
licenses: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="project-details">
|
||||||
|
<h1>项目详情: {{ projectName }}</h1>
|
||||||
|
<p>创建人: {{ projectDetails.creator }}</p>
|
||||||
|
<p>创建时间: {{ projectDetails.createTime }}</p>
|
||||||
|
<p>团队: {{ projectDetails.team }}</p>
|
||||||
|
|
||||||
|
<h2>扫描详情</h2>
|
||||||
|
<div class="scan-info">
|
||||||
|
<p>
|
||||||
|
软件成分分析扫描次数:
|
||||||
|
{{ projectDetails.scanDetails.softwareComposition.scanTimes }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
平均扫描时间:
|
||||||
|
{{ projectDetails.scanDetails.softwareComposition.avgScanTime }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
源代码分支:
|
||||||
|
{{ projectDetails.scanDetails.softwareComposition.sourceBranch }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>组件信息</h2>
|
||||||
|
<p>组件数量: {{ projectDetails.scanDetails.componentCount }}</p>
|
||||||
|
<p>漏洞数: {{ projectDetails.scanDetails.vulnerabilities }}</p>
|
||||||
|
<p>许可证数量: {{ projectDetails.scanDetails.licenses }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.project-details {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-info {
|
||||||
|
padding: 10px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
182
src/views/project/ProjectManagement.vue
Normal file
182
src/views/project/ProjectManagement.vue
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const getStatLabel = (key: string): string => {
|
||||||
|
const labels: { [key: string]: string } = {
|
||||||
|
totalProjects: "项目总数",
|
||||||
|
scanTimes: "扫描次数",
|
||||||
|
unscanned: "未扫描",
|
||||||
|
outdatedScans: "未更新扫描",
|
||||||
|
scanned: "已扫描"
|
||||||
|
};
|
||||||
|
return labels[key] || key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const projectStats = ref({
|
||||||
|
totalProjects: 32,
|
||||||
|
scanTimes: 9,
|
||||||
|
unscanned: 2,
|
||||||
|
outdatedScans: 4,
|
||||||
|
scanned: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
const projects = ref([
|
||||||
|
{
|
||||||
|
name: "TestProject",
|
||||||
|
status: "已更新",
|
||||||
|
riskLevel: "严重",
|
||||||
|
lastScan: "2024-7-12",
|
||||||
|
riskDistribution: "高-2-中-1-低-3",
|
||||||
|
scanType: "软件成分分析",
|
||||||
|
scanTime: "20s",
|
||||||
|
projectLink: "github.com/a/b",
|
||||||
|
projectSource: "Github"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="project-management">
|
||||||
|
<div class="stats-container">
|
||||||
|
<div v-for="(value, key) in projectStats" :key="key" class="stat-card">
|
||||||
|
<p>{{ getStatLabel(key) }}</p>
|
||||||
|
<h2>{{ value }}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button class="btn">+ 新建项目</button>
|
||||||
|
</div>
|
||||||
|
<div class="filter-container">
|
||||||
|
<el-input type="text" placeholder="选择搜索类型(ID或name或者tags)" />
|
||||||
|
<el-input type="text" placeholder="根据搜索类型搜索" />
|
||||||
|
</div>
|
||||||
|
<table class="project-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>项目名称</th>
|
||||||
|
<th>更新状态</th>
|
||||||
|
<th>风险等级</th>
|
||||||
|
<th>最近一次扫描时间</th>
|
||||||
|
<th>风险分布</th>
|
||||||
|
<th>扫描类别</th>
|
||||||
|
<th>扫描耗费时间</th>
|
||||||
|
<th>项目地址</th>
|
||||||
|
<th>项目来源</th>
|
||||||
|
<th>扫描</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="project in projects" :key="project.name">
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
:href="'https://' + project.projectLink"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{{ project.name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ project.status }}</td>
|
||||||
|
<td>{{ project.riskLevel }}</td>
|
||||||
|
<td>{{ project.lastScan }}</td>
|
||||||
|
<td>{{ project.riskDistribution }}</td>
|
||||||
|
<td>{{ project.scanType }}</td>
|
||||||
|
<td>{{ project.scanTime }}</td>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
:href="'https://' + project.projectLink"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{{ project.projectLink }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ project.projectSource }}</td>
|
||||||
|
<td><button class="scan-btn">扫描</button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.project-management {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f4f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 0 10px;
|
||||||
|
text-align: center;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #4caf50;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-container input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-table th,
|
||||||
|
.project-table td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-table td a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-btn {
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #3498db;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
x
Reference in New Issue
Block a user