Merge remote-tracking branch 'origin/master'
This commit is contained in:
53
src/api/organizationManage/organizationManageApi.ts
Normal file
53
src/api/organizationManage/organizationManageApi.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
// TODO 获取组织信息功能 没有相关接口,待对齐
|
||||
export function getOrganizationInfoApi(params) {
|
||||
return request({
|
||||
url: ``,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function createOrganizationApi(params) {
|
||||
return request({
|
||||
url: `/api/v1/user/group/create`,
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO 更新组织信息功能 没有相关接口,待对齐
|
||||
export function updateOrganizationInfoApi(params) {
|
||||
return request({
|
||||
url: `/api/v1/user/group/create`,
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function getOrganizationMemberListApi(params) {
|
||||
return request({
|
||||
url: `/api/v1/user/group/member/list`,
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export function inviteOrganizationMemberApi(params) {
|
||||
return request({
|
||||
url: `/api/v1/user/group/member/invite `,
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteOrganizationMemberApi(params) {
|
||||
return request({
|
||||
url: `/api/v1/user/group/member/remove`,
|
||||
method: 'delete',
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
12
src/api/organizationManage/organizationManageType.ts
Normal file
12
src/api/organizationManage/organizationManageType.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface OrganizationInfoType {
|
||||
organizationName: string;
|
||||
organizationProfile: string;
|
||||
}
|
||||
|
||||
export interface OrganizationMemberItemType {
|
||||
id: string;
|
||||
userName: string;
|
||||
role: string;
|
||||
email: string;
|
||||
joinDate: string;
|
||||
}
|
||||
@@ -1542,3 +1542,14 @@ export const getOriginalComment = (params: types.DiscussionCommentProps): Promis
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// 获取漏洞数据
|
||||
export const getVulnDetail = (params: types.VulnDetailProps): Promise<any> => {
|
||||
return reqCatch(() =>
|
||||
request({
|
||||
url: `/api/v1/repo/vulnerability/info`,
|
||||
method: 'get',
|
||||
params,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -207,3 +207,8 @@ export interface DiscussionCommentProps {
|
||||
discussionId: string | number,
|
||||
}
|
||||
|
||||
export interface VulnDetailProps {
|
||||
repoId: string,
|
||||
id: string,
|
||||
}
|
||||
|
||||
|
||||
@@ -118,12 +118,6 @@ div.devui-tooltip {
|
||||
}
|
||||
}
|
||||
}
|
||||
// modal
|
||||
.devui-modal {
|
||||
&__header {
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
// textarea 文字计数颜色
|
||||
.devui-textarea__show-count {
|
||||
color: var(--color-lighter) !important;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
249
src/assets/imgs/jyh/nodata.svg
Normal file
249
src/assets/imgs/jyh/nodata.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 78 KiB |
26
src/assets/imgs/jyh/nodata_small.svg
Normal file
26
src/assets/imgs/jyh/nodata_small.svg
Normal file
@@ -0,0 +1,26 @@
|
||||
<svg width="128.000000" height="128.000000" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<desc>
|
||||
Created with Pixso.
|
||||
</desc>
|
||||
<defs/>
|
||||
<rect id="插图/暂无数据-浅色" width="128.000000" height="128.000000" fill="#E4E4E4" fill-opacity="0"/>
|
||||
<path id="矩形备份" d="M22.75 41.78L109.88 41.78C110.69 41.78 111.34 42.43 111.34 43.23L111.34 108.48C111.34 111.06 109.24 113.15 106.66 113.15L26.9 113.15C24.61 113.15 22.75 111.3 22.75 109L22.75 41.78Z" fill="#F3F3F3" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形备份" d="M109.88 41.78C110.69 41.78 111.34 42.43 111.34 43.23L111.34 108.48C111.34 111.06 109.24 113.15 106.66 113.15L26.9 113.15C24.61 113.15 22.75 111.3 22.75 109L22.75 41.78L109.88 41.78ZM109.88 42.42C110.33 42.42 110.7 42.78 110.7 43.23L110.7 108.48C110.7 110.71 108.89 112.51 106.66 112.51L26.9 112.51C24.96 112.51 23.39 110.94 23.39 109L23.39 42.42L109.88 42.42Z" fill="#818181" fill-opacity="0" fill-rule="evenodd"/>
|
||||
<path id="矩形" d="M17.6 41.74L87.45 41.74L87.45 108.89C87.45 111.18 85.6 113.04 83.3 113.04L20.3 113.04C18.01 113.04 16.15 111.18 16.15 108.89L16.15 43.19C16.15 42.39 16.8 41.74 17.6 41.74Z" fill="#FFFFFF" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形" d="M87.45 41.74L87.45 108.89C87.45 111.18 85.6 113.04 83.3 113.04L20.3 113.04C18.01 113.04 16.15 111.18 16.15 108.89L16.15 43.19C16.15 42.39 16.8 41.74 17.6 41.74L87.45 41.74ZM86.81 42.38L86.81 108.89C86.81 110.83 85.24 112.4 83.3 112.4L20.3 112.4C18.36 112.4 16.79 110.83 16.79 108.89L16.79 43.19C16.79 42.74 17.15 42.38 17.6 42.38L86.81 42.38Z" fill="#818181" fill-opacity="0" fill-rule="evenodd"/>
|
||||
<path id="矩形" d="M87.45 41.74L16.84 41.74C16.13 41.74 15.46 42.1 15.08 42.7L4.01 60.24C3.57 60.94 4.08 61.83 4.9 61.83L71.03 61.23C72.33 61.22 73.56 60.6 74.33 59.54L87.45 41.74Z" fill="#FFFFFF" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形" d="" fill="#818181" fill-opacity="0" fill-rule="evenodd"/>
|
||||
<path id="矩形备份 4" d="M87.12 41.78L111.2 41.78C111.89 41.78 112.54 42.12 112.93 42.7L124.91 60.55C125.37 61.24 124.88 62.17 124.05 62.17L101.98 62.17C100.54 62.17 99.2 61.42 98.44 60.19L87.12 41.78Z" fill="#FFFFFF" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形备份 4" d="" fill="#818181" fill-opacity="0" fill-rule="evenodd"/>
|
||||
<path id="路径" d="M111.34 62.17L111.34 107.35C111.34 110.56 108.77 113.15 105.6 113.15L80.75 113.15L80.75 111.87L105.6 111.87C108.07 111.87 110.06 109.85 110.06 107.35L110.06 62.17L111.34 62.17Z" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="路径" d="M87.76 41.14L87.76 107.37C87.76 110.56 85.21 113.15 82.07 113.15L21.43 113.15C18.29 113.15 15.74 110.56 15.74 107.37L15.79 61.85L17.05 61.85L17 107.37C17 109.85 18.99 111.87 21.43 111.87L82.07 111.87C84.51 111.87 86.49 109.85 86.49 107.37L86.49 42.42L18.14 42.42L18.14 41.14L87.76 41.14Z" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形" d="M17.4102 41.1436C16.5332 41.1436 15.7188 41.582 15.252 42.3037L3.66797 60.2617C3.29492 60.8408 3.47656 61.6035 4.07227 61.9648C4.27539 62.0879 4.50781 62.1533 4.74805 62.1533L70.9844 62.1533C72.7109 62.1533 74.3223 61.3037 75.2598 59.8955L87.7617 41.1436L17.4102 41.1436ZM85.4219 42.3799L17.4102 42.3799C16.9727 42.3799 16.5645 42.5986 16.332 42.96L4.74805 60.918L70.9844 60.918C72.2793 60.918 73.4883 60.2803 74.1914 59.2246L85.4219 42.3799Z" clip-rule="evenodd" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="矩形备份 4" d="M111.24 41.1436C112.121 41.1436 112.941 41.5713 113.418 42.2803L125.5 60.25C125.887 60.8242 125.713 61.5889 125.111 61.958C124.902 62.0859 124.658 62.1533 124.412 62.1533L102.389 62.167C100.555 62.167 98.8574 61.2393 97.9277 59.7295L86.4863 41.1562L111.24 41.1436ZM88.9785 42.3584L111.297 42.3584C111.736 42.3584 112.146 42.5723 112.385 42.9258L124.469 60.8965L102.619 60.8965C101.244 60.8965 99.9707 60.2012 99.2734 59.0684L88.9785 42.3584Z" clip-rule="evenodd" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="路径备份" d="M65.81 15.63L65.81 24.54C65.81 24.9 65.52 25.18 65.17 25.18C64.82 25.18 64.53 24.9 64.53 24.54L64.53 15.63C64.53 15.28 64.82 15 65.17 15C65.52 15 65.81 15.28 65.81 15.63Z" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="路径备份" d="M89.07 20.27L84.62 27.99C84.44 28.3 84.05 28.4 83.75 28.22C83.44 28.05 83.34 27.66 83.51 27.35L87.97 19.64C88.15 19.33 88.53 19.23 88.84 19.4C89.14 19.58 89.25 19.97 89.07 20.27Z" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<path id="路径备份" d="M42.37 19.64L46.83 27.35C47 27.66 46.9 28.05 46.59 28.22C46.29 28.4 45.9 28.3 45.73 27.99L41.27 20.27C41.09 19.97 41.2 19.58 41.5 19.4C41.81 19.23 42.2 19.33 42.37 19.64Z" fill="#191919" fill-opacity="1.000000" fill-rule="evenodd"/>
|
||||
<rect id="矩形" x="24.667969" y="86.392578" rx="1.281281" width="24.830080" height="6.366683" fill="#7693F5" fill-opacity="1.000000"/>
|
||||
<rect id="矩形" x="24.988281" y="86.712891" rx="1.281281" width="24.189440" height="5.726042" stroke="#000000" stroke-opacity="0" stroke-width="0.640641"/>
|
||||
<rect id="矩形备份 2" x="24.667969" y="96.588867" rx="0.640000" width="18.622562" height="1.911917" fill="#191919" fill-opacity="1.000000"/>
|
||||
<rect id="矩形备份 3" x="24.667969" y="102.325195" rx="0.640000" width="9.311282" height="1.911917" fill="#191919" fill-opacity="1.000000"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -4,9 +4,8 @@
|
||||
<img
|
||||
v-if="!hideImg"
|
||||
class="block mb-[20px]"
|
||||
width="300"
|
||||
height="240"
|
||||
src="/src/assets/imgs/jyh/nodata.png"
|
||||
:width="imgWidth"
|
||||
:src="src"
|
||||
alt="NoData"
|
||||
/>
|
||||
</slot>
|
||||
@@ -17,16 +16,36 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
hideImg: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
imgSrc: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const src = computed(() => {
|
||||
if (props.imgSrc) {
|
||||
return props.imgSrc;
|
||||
}
|
||||
return props.small ? '/src/assets/imgs/jyh/nodata_small.svg' : '/src/assets/imgs/jyh/nodata.svg';
|
||||
});
|
||||
const imgWidth = computed(() => {
|
||||
if (props.width) {
|
||||
return props.width;
|
||||
}
|
||||
return props.small ? '128px' : '300px';
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.bg-white {
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,7 +15,6 @@ import { ref } from 'vue';
|
||||
import EarlyWarningPerson from './EarlyWarningPerson.vue';
|
||||
import EarlyWarningOrganization from './EarlyWarningOrganization.vue';
|
||||
const selectTab = ref('gryj');
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -23,3 +22,18 @@ const selectTab = ref('gryj');
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.warning-modal {
|
||||
width: auto;
|
||||
|
||||
.devui-modal__header {
|
||||
font-size: 20px;
|
||||
height: auto!important;
|
||||
}
|
||||
|
||||
.devui-modal__body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
106
src/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue
Normal file
106
src/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div class="warning-detail-container">
|
||||
<div class="warning-title">
|
||||
<div>{{ warningData.title }}</div>
|
||||
<div class="sub-title mt-3">
|
||||
<span>重要性</span>
|
||||
<d-tag type="danger" size="sm">{{warningData.importance}}</d-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-text">
|
||||
<div class="text-box mb-5">
|
||||
<div>一、概要</div>
|
||||
<p> {{ warningData.summary }}</p>
|
||||
</div>
|
||||
<div class="text-box">
|
||||
<div>二、修复方案</div>
|
||||
<p> {{ warningData.fixMethod }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="{'border-radius': propsData.type === 'user' ? '6px' : 0}" class="warning-from">可信开源代码库运营团队 {{ warningData.fromTime }}</div>
|
||||
<div v-if="propsData.type === 'system'" class="warning-operation">
|
||||
<d-button @click="confirm" variant="solid" class="mr-2">确定</d-button>
|
||||
<d-button @click="$emit('close')">取消</d-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
const propsData = defineProps(['type', 'warningData']);
|
||||
const warningData = ref({
|
||||
title: '【漏洞排查预警】ApacheIgnite远程代码执行漏洞排查(CVE-2024-52577)',
|
||||
importance: '高',
|
||||
summary: '近日,安全中心发现Apache lgnite远程代码执行漏洞(CVE-2024-52577)。在 2.6.0<Apache Ignite< 2.17.0版本中,由于lgnite未能正确实施类序列化过滤器,攻击者能够利用恶意序列化对象绕过安全检查,从而在服务器端反序列化时触发任意代码的执行。经可信开源代码库运营团队评审漏洞技术定级2级/3级,若不满足利用条件可举证降为6级。请你按要求在XX时间内完成修复。',
|
||||
fixMethod: '升级Apache Ignite至安全版本:2.17.0',
|
||||
fromTime: '2025-2-20'
|
||||
});
|
||||
// warningData.value = propsData.warningData;
|
||||
const confirm = () => {
|
||||
emit('close');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.warning-detail-container {
|
||||
width: 600px;
|
||||
|
||||
.warning-title {
|
||||
color: #000000;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: 600;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
padding: 4px 20px 12px;
|
||||
|
||||
.sub-title {
|
||||
>span {
|
||||
margin-right: 12px;
|
||||
color: #808080;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
padding: 20px;
|
||||
background: #F6F6F8;
|
||||
|
||||
.text-box {
|
||||
|
||||
div {
|
||||
margin-bottom: 8px;
|
||||
color: #252B3A;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #252B3A;
|
||||
font-family: 苹方-简;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.warning-from {
|
||||
background: #F6F6F8;
|
||||
color: #808080;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.warning-operation {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@
|
||||
<d-column field="code" header="时间"></d-column>
|
||||
<d-column field="name" header="标题">
|
||||
<template #default="scope">
|
||||
<a>{{scope.row.name}}</a>
|
||||
<a @click="openWarningDetail(scope.row)">{{scope.row.name}}</a>
|
||||
</template>
|
||||
</d-column>
|
||||
<d-column field="detail" header="详情"></d-column>
|
||||
@@ -25,11 +25,16 @@
|
||||
</d-table>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<d-modal class="warning-modal" v-model="warningModalVisable" title="主题:">
|
||||
<EarlyWarningDetail @close="colseWarningDetail" :warningData="currentWarning" type="user"></EarlyWarningDetail>
|
||||
</d-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import { ref } from 'vue';
|
||||
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
|
||||
|
||||
const licenseTableData = ref([
|
||||
{code: '05822156', name:'MIT License',detail: 'integer',level: 4},
|
||||
@@ -38,6 +43,15 @@ const licenseTableData = ref([
|
||||
{code: '05822156', name:'MIT License',detail: 'integer',level: 1},
|
||||
]);
|
||||
|
||||
const warningModalVisable = ref(false);
|
||||
const currentWarning = ref();
|
||||
const openWarningDetail = (row) => {
|
||||
warningModalVisable.value = true;
|
||||
currentWarning.value = row;
|
||||
};
|
||||
const colseWarningDetail = () => {
|
||||
warningModalVisable.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
74
src/views/Jyh/PersonalCenter/Detail/InvitationNoticeList.vue
Normal file
74
src/views/Jyh/PersonalCenter/Detail/InvitationNoticeList.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div class="invitation-notice-container">
|
||||
<Card simple class="jyh-card mt-3">
|
||||
<div class="card-title">邀请通知列表</div>
|
||||
<div class="mb-3">
|
||||
<d-table
|
||||
class="jyh-table jyh-table-2"
|
||||
:header-bg="true"
|
||||
:data="noticeTableData"
|
||||
>
|
||||
<d-column field="content" header="邀请内容"></d-column>
|
||||
<d-column field="time" header="邀请时间" width="200"></d-column>
|
||||
<d-column field="creator" header="邀请人" width="180"></d-column>
|
||||
<d-column header="操作" width="150">
|
||||
<template #default="scope">
|
||||
<d-button
|
||||
variant="text"
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
接收
|
||||
</d-button>
|
||||
<d-button
|
||||
variant="text"
|
||||
color="primary"
|
||||
>
|
||||
拒绝
|
||||
</d-button>
|
||||
</template>
|
||||
</d-column>
|
||||
</d-table>
|
||||
<div class="invitation-pagination">
|
||||
<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"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, shallowReactive } from 'vue';
|
||||
|
||||
const noticeTableData = ref([
|
||||
{
|
||||
content: '当您订阅的软件有漏洞预警通知时,将以应用号的方式通知。可在首页查看或取消订阅!',
|
||||
time: '2025-03-15 17:29:30',
|
||||
creator: '132456798',
|
||||
}
|
||||
]);
|
||||
const pager = shallowReactive({
|
||||
total: 1,
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [10, 20, 30, 40, 50],
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.invitation-notice-container {
|
||||
.invitation-pagination {
|
||||
padding: 12px 0;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,117 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="hasOrganization"></div>
|
||||
<div v-if="hasOrganization">
|
||||
<d-card class="mb-[16px] bg-white" shadow="never">
|
||||
<div class="text-[14px] w-full flex items-center justify-between">
|
||||
<div class="font-bold mb-[16px]">基础信息</div>
|
||||
<div>
|
||||
<d-icon
|
||||
v-if="!isEdit"
|
||||
class="font-normal"
|
||||
name="edit"
|
||||
operable
|
||||
@click="editIconClick"
|
||||
>
|
||||
<template #suffix>
|
||||
<span>编辑</span>
|
||||
</template>
|
||||
</d-icon>
|
||||
</div>
|
||||
</div>
|
||||
<d-form
|
||||
ref="baseInfoFormRef"
|
||||
:data="createFormData"
|
||||
message-type="none"
|
||||
>
|
||||
<d-form-item
|
||||
field="organizationName"
|
||||
label="组织名称"
|
||||
>
|
||||
<d-input v-if="isEdit" v-model="createFormData.organizationName" />
|
||||
<div v-else>{{ organizationInfo.organizationName }}</div>
|
||||
</d-form-item>
|
||||
<d-form-item field="organizationProfile" label="组织简介">
|
||||
<d-textarea
|
||||
v-if="isEdit"
|
||||
v-model="createFormData.organizationProfile"
|
||||
show-count
|
||||
maxlength="200"
|
||||
/>
|
||||
<div v-else>{{ organizationInfo.organizationProfile }}</div>
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
<div v-if="isEdit">
|
||||
<d-button
|
||||
variant="solid"
|
||||
class="mr-[8px]"
|
||||
@click="editOrganizationConfirm"
|
||||
>完成</d-button>
|
||||
<d-button @click="editOrganizationCancel">取消</d-button>
|
||||
</div>
|
||||
</d-card>
|
||||
|
||||
|
||||
<d-card class="mb-[16px] bg-white" shadow="never">
|
||||
<div class="font-bold text-[14px] mb-[12px]">成员管理</div>
|
||||
<div class="flex mb-[12px]">
|
||||
<d-button
|
||||
icon="add"
|
||||
variant="solid"
|
||||
class="mr-[8px]"
|
||||
@click="openInviteMemberModal"
|
||||
>邀请成员</d-button>
|
||||
<d-search
|
||||
icon-position="left"
|
||||
class="w-[296px]"
|
||||
placeholder="请输入搜索内容"
|
||||
/>
|
||||
</div>
|
||||
<d-table
|
||||
v-if="memberTableData.length"
|
||||
:data="memberTableData"
|
||||
class="w-full mb-[20px]"
|
||||
fix-header
|
||||
header-bg
|
||||
max-height="500px"
|
||||
>
|
||||
<d-column field="userName" header="成员名" />
|
||||
<d-column field="role" header="角色">
|
||||
<template #default="{ row }">
|
||||
{{ memberRoleMap[row.role] ?? '' }}
|
||||
</template>
|
||||
</d-column>
|
||||
<d-column field="email" header="邮箱" />
|
||||
<d-column field="joinDate" header="加入时间" />
|
||||
<d-column header="操作">
|
||||
<template #default="{row}">
|
||||
<d-button
|
||||
variant="text"
|
||||
color="primary"
|
||||
@click="openDeleteModal(row)"
|
||||
>删除</d-button>
|
||||
</template>
|
||||
</d-column>
|
||||
</d-table>
|
||||
<NoData v-else />
|
||||
<d-pagination
|
||||
class="flex justify-end"
|
||||
: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"
|
||||
/>
|
||||
</d-card>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<NoData>
|
||||
<NoData :small="false">
|
||||
<div class="font-bold mb-[20px]">很抱歉,当前无任何组织,赶快去</div>
|
||||
<d-button
|
||||
size="lg"
|
||||
variant="solid"
|
||||
@click="createOrganizationBtnClick"
|
||||
@click="openCreateOrganizationModal"
|
||||
>新建组织</d-button>
|
||||
</NoData>
|
||||
</div>
|
||||
@@ -46,29 +150,168 @@
|
||||
class="mr-[8px]"
|
||||
@click="confirmCreateOrganizationBtnClick"
|
||||
>确定</d-button>
|
||||
<d-button @click="createOrganizationModalClose">取消</d-button>
|
||||
<d-button @click="closeOrganizationModal">取消</d-button>
|
||||
</div>
|
||||
</d-modal>
|
||||
|
||||
<d-modal
|
||||
v-model="inviteMemberModalCtrl"
|
||||
title="邀请成员"
|
||||
class="w-[600px]"
|
||||
>
|
||||
<d-form
|
||||
ref="inviteMemberFormRef"
|
||||
layout="vertical"
|
||||
:data="inviteMemberFormData"
|
||||
message-type="none"
|
||||
>
|
||||
<d-form-item
|
||||
field="userName"
|
||||
label="成员"
|
||||
required
|
||||
>
|
||||
<d-input v-model="inviteMemberFormData.userName" placeholder="请输入" />
|
||||
</d-form-item>
|
||||
<d-form-item field="role" label="角色" required>
|
||||
<d-select v-model="inviteMemberFormData.role">
|
||||
<d-option
|
||||
v-for="item of inviteMemberSelectOptions"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:name="item.name"
|
||||
/>
|
||||
</d-select>
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<d-button
|
||||
variant="solid"
|
||||
class="mr-[8px]"
|
||||
@click="inviteMemberConfirmBtnClick"
|
||||
>确定</d-button>
|
||||
<d-button @click="closeInviteMemberModal">取消</d-button>
|
||||
</div>
|
||||
</d-modal>
|
||||
|
||||
|
||||
<d-modal
|
||||
v-model="deleteMemberModalCtrl"
|
||||
title="删除成员"
|
||||
class="w-[600px]"
|
||||
>
|
||||
<div>
|
||||
即将删除成员‘{{ deleteRow.userName }}’,请确认是否继续?
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<d-button
|
||||
variant="solid"
|
||||
class="mr-[8px]"
|
||||
@click="deleteMember"
|
||||
>确定</d-button>
|
||||
<d-button @click="closeDeleteMemberModal">取消</d-button>
|
||||
</div>
|
||||
</d-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {reactive, ref} from "vue";
|
||||
import {reactive, ref, shallowRef} from "vue";
|
||||
import NoData from "@/components/NoData/NoData.vue";
|
||||
import {
|
||||
createOrganizationApi, deleteOrganizationMemberApi,
|
||||
getOrganizationInfoApi, getOrganizationMemberListApi, inviteOrganizationMemberApi,
|
||||
updateOrganizationInfoApi
|
||||
} from "@/api/organizationManage/organizationManageApi";
|
||||
import {
|
||||
type OrganizationInfoType,
|
||||
type OrganizationMemberItemType,
|
||||
} from "@/api/organizationManage/organizationManageType";
|
||||
import table from "@/components/AIRepair/Table.vue";
|
||||
|
||||
const searchOrganizationLoading = ref(false);
|
||||
const hasOrganization = ref(false);
|
||||
const organizationInfo = shallowRef<OrganizationInfoType>({
|
||||
organizationName: '',
|
||||
organizationProfile: '',
|
||||
});
|
||||
|
||||
const createOrganizationModalCtrl = ref(false);
|
||||
const createFormData = reactive({
|
||||
organizationName: "",
|
||||
organizationProfile: "", // 组织简介
|
||||
organizationName: '',
|
||||
organizationProfile: '', // 组织简介
|
||||
});
|
||||
const createFormRef = ref();
|
||||
const createOrganizationLoading = ref(false);
|
||||
|
||||
const isEdit = ref(false);
|
||||
const editLoading = ref(false);
|
||||
|
||||
const memberListSearchLoading = ref(false);
|
||||
const memberListSearchParam = ref('');
|
||||
const memberTableData = shallowRef<OrganizationMemberItemType[]>([]);
|
||||
const pager = reactive({
|
||||
pageSize: 10,
|
||||
pageIndex: 1,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const deleteRow = shallowRef<OrganizationMemberItemType>(null);
|
||||
const deleteMemberModalCtrl = ref(false);
|
||||
const deleteMemberLoading = ref(false);
|
||||
|
||||
const inviteMemberFormRef = ref();
|
||||
const inviteMemberModalCtrl = ref(false);
|
||||
const inviteMemberLoading = ref(false);
|
||||
const inviteMemberFormData = reactive({
|
||||
userName: '',
|
||||
role: '',
|
||||
});
|
||||
const inviteMemberSelectOptions = [
|
||||
{ name: '创建者', value: 'creator' },
|
||||
{ name: '成员', value: 'member' },
|
||||
];
|
||||
const memberRoleMap = {
|
||||
creator: '创建者',
|
||||
member: '成员',
|
||||
};
|
||||
|
||||
const mockTableData = [
|
||||
{ userName: '张三', role: 'member', email: '111@gmail.com', joinDate: '2090-02-30', id: '1' },
|
||||
{ userName: '李四', role: 'creator', email: '111@gmail.com', joinDate: '2090-02-30', id: '2' },
|
||||
{ userName: '王五', role: 'member', email: '111@gmail.com', joinDate: '2090-02-30', id: '3' },
|
||||
{ userName: '赵六', role: 'member', email: '111@gmail.com', joinDate: '2090-02-30', id: '4' },
|
||||
{ userName: '秦七', role: 'member', email: '111@gmail.com', joinDate: '2090-02-30', id: '5' },
|
||||
];
|
||||
|
||||
// -------------------- 获取组织信息 --------------------
|
||||
async function getOrganizationInfo() {
|
||||
const params = {
|
||||
organizationName: createFormData.organizationName,
|
||||
organizationProfile: createFormData.organizationProfile,
|
||||
};
|
||||
searchOrganizationLoading.value = true;
|
||||
try {
|
||||
const res = await getOrganizationInfoApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
searchOrganizationLoading.value = false;
|
||||
getMemberList();
|
||||
// TODO 待接口定义好后删除下面两行固定赋值语句
|
||||
hasOrganization.value = true;
|
||||
organizationInfo.value = { organizationName: createFormData.organizationName, organizationProfile: createFormData.organizationProfile };
|
||||
}
|
||||
|
||||
// -------------------- 获取成员信息 --------------------
|
||||
async function getOrganizationMember(organizationId: string) {
|
||||
const params = {};
|
||||
}
|
||||
|
||||
// -------------------- 创建组织 --------------------
|
||||
function confirmCreateOrganizationBtnClick() {
|
||||
createFormRef.value.validate(isValid => {
|
||||
createFormRef.value.validate((isValid: boolean) => {
|
||||
if (isValid) {
|
||||
createOrganization();
|
||||
createOrganization();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -78,21 +321,146 @@ async function createOrganization() {
|
||||
organizationName: createFormData.organizationName,
|
||||
organizationProfile: createFormData.organizationProfile,
|
||||
};
|
||||
createOrganizationLoading.value = true;
|
||||
try {
|
||||
|
||||
const res = await createOrganizationApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
closeOrganizationModal();
|
||||
// TODO 待接口定义好后删除下面调用逻辑
|
||||
getOrganizationInfo();
|
||||
createOrganizationLoading.value = false;
|
||||
}
|
||||
|
||||
function createOrganizationBtnClick(): void {
|
||||
function openCreateOrganizationModal() {
|
||||
createOrganizationModalCtrl.value = true;
|
||||
}
|
||||
|
||||
function createOrganizationModalClose(): void {
|
||||
function closeOrganizationModal() {
|
||||
createOrganizationModalCtrl.value = false;
|
||||
}
|
||||
|
||||
// -------------------- 编辑组织信息 --------------------
|
||||
function editIconClick() {
|
||||
isEdit.value = true;
|
||||
}
|
||||
|
||||
async function editOrganizationConfirm() {
|
||||
editLoading.value = true;
|
||||
const params = {
|
||||
organizationName: createFormData.organizationName,
|
||||
organizationProfile: createFormData.organizationProfile,
|
||||
};
|
||||
try {
|
||||
const res = await updateOrganizationInfoApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
editLoading.value = false;
|
||||
isEdit.value = false;
|
||||
// TODO 待接口定义好后删除下面两行固定赋值语句
|
||||
hasOrganization.value = true;
|
||||
organizationInfo.value = { organizationName: createFormData.organizationName, organizationProfile: createFormData.organizationProfile };
|
||||
}
|
||||
|
||||
function editOrganizationCancel() {
|
||||
isEdit.value = false;
|
||||
createFormData.organizationName = organizationInfo.value.organizationName;
|
||||
createFormData.organizationProfile = organizationInfo.value.organizationProfile;
|
||||
}
|
||||
|
||||
// -------------------- 邀请、查询成员 --------------------
|
||||
async function getMemberList() {
|
||||
const params = {
|
||||
organizationName: createFormData.organizationName,
|
||||
pageIndex: pager.pageIndex,
|
||||
pageSize: pager.pageSize,
|
||||
searchParam: memberListSearchParam.value,
|
||||
};
|
||||
memberListSearchLoading.value = true;
|
||||
try {
|
||||
const res = await getOrganizationMemberListApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
memberTableData.value = mockTableData;
|
||||
pager.total = 6;
|
||||
memberListSearchLoading.value = false;
|
||||
}
|
||||
|
||||
function openInviteMemberModal() {
|
||||
inviteMemberModalCtrl.value = true;
|
||||
}
|
||||
|
||||
function openDeleteModal(row: any) {
|
||||
deleteRow.value = row;
|
||||
deleteMemberModalCtrl.value = true;
|
||||
}
|
||||
|
||||
function inviteMemberConfirmBtnClick() {
|
||||
inviteMemberFormRef.value.validate((isValid: boolean) => {
|
||||
if (isValid) {
|
||||
console.log('aaaaaaaa')
|
||||
inviteMember();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function inviteMember() {
|
||||
const params = {
|
||||
userName: inviteMemberFormData.userName,
|
||||
role: inviteMemberFormData.role,
|
||||
};
|
||||
inviteMemberLoading.value = true;
|
||||
try {
|
||||
const res = await inviteOrganizationMemberApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
inviteMemberLoading.value = false;
|
||||
closeInviteMemberModal();
|
||||
// TODO 待接口定义好后删除下面调用逻辑
|
||||
mockTableData.unshift({
|
||||
userName: inviteMemberFormData.userName,
|
||||
role: inviteMemberFormData.role,
|
||||
joinDate: new Date().toDateString(),
|
||||
id: String(pager.total++),
|
||||
email: `${inviteMemberFormData.userName}@gmail.com`,
|
||||
});
|
||||
memberTableData.value = [...mockTableData];
|
||||
}
|
||||
|
||||
function closeInviteMemberModal() {
|
||||
inviteMemberModalCtrl.value = false;
|
||||
}
|
||||
|
||||
async function deleteMember() {
|
||||
const params = {
|
||||
id: deleteRow.value.id,
|
||||
};
|
||||
deleteMemberLoading.value = true;
|
||||
try {
|
||||
const res = await deleteOrganizationMemberApi(params);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
deleteMemberLoading.value = false;
|
||||
closeDeleteMemberModal();
|
||||
// TODO 待接口定义好后删除下面调用逻辑
|
||||
const index = mockTableData.findIndex(item => item.id === deleteRow.value.id);
|
||||
mockTableData.splice(index, 1);
|
||||
memberTableData.value = [...mockTableData];
|
||||
pager.total--;
|
||||
}
|
||||
|
||||
function closeDeleteMemberModal() {
|
||||
deleteMemberModalCtrl.value = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.devui-table__row td) {
|
||||
padding: 10px 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<d-tab id="yjtzlb" title="预警通知列表"></d-tab>
|
||||
<d-tab id="dylb" title="订阅列表"></d-tab>
|
||||
<d-tab id="organizationManage" title="组织管理"></d-tab>
|
||||
<d-tab id="invitation" title="邀请通知"></d-tab>
|
||||
</d-tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -30,6 +31,7 @@
|
||||
<early-warning v-if="selectTab==='yjtzlb'"/>
|
||||
<subscribe-list v-if="selectTab==='dylb'"/>
|
||||
<OrganizationManage v-if="selectTab === 'organizationManage'" />
|
||||
<InvitationNoticeList v-if="selectTab === 'invitation'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -41,6 +43,7 @@ import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
|
||||
import EarlyWarning from './Detail/EarlyWarning.vue';
|
||||
import SubscribeList from './Detail/SubscribeList.vue';
|
||||
import OrganizationManage from './OrganizationManage/OrganizationManage.vue';
|
||||
import InvitationNoticeList from './Detail/InvitationNoticeList.vue';
|
||||
|
||||
const { namespace } = getOrgInfo();
|
||||
const avatarUrl = '/src/assets/imgs/avatar/male.png';
|
||||
|
||||
84
src/views/Jyh/Version/Detail/SubscriptionModal.vue
Normal file
84
src/views/Jyh/Version/Detail/SubscriptionModal.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="subscribe-container">
|
||||
<div class="subscribe-tip mb-3">当您订阅的软件有漏洞预警通知时,将以应用号的方式通知。可在首页查看或取消订阅!</div>
|
||||
<div class="subscribe-form">
|
||||
<d-form ref="formRef" :data="formData" :rules="rules">
|
||||
<d-form-item field="subscribeType" label="通知方式">
|
||||
<d-radio-group direction="row" v-model="formData.subscribeType" @change="typeChange">
|
||||
<d-radio value="0">短信</d-radio>
|
||||
<d-radio value="1">邮件</d-radio>
|
||||
<d-radio value="2">站内通知</d-radio>
|
||||
</d-radio-group>
|
||||
</d-form-item>
|
||||
<d-form-item v-if="formData.subscribeType && formData.subscribeType !== '2'" field="subscribeText" :label="textLabel">
|
||||
<d-input v-model="formData.subscribeText" />
|
||||
</d-form-item>
|
||||
</d-form>
|
||||
</div>
|
||||
<div class="subscribe-operation mt-5">
|
||||
<d-button @click="confirm" variant="solid" class="mr-2">确定</d-button>
|
||||
<d-button @click="$emit('close')">取消</d-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
const props = defineProps(['softwareData']);
|
||||
const emit = defineEmits(['close']);
|
||||
const formRef = ref(null);
|
||||
const formData = ref({
|
||||
subscribeType: '',
|
||||
subscribeText: '',
|
||||
});
|
||||
const rules = {
|
||||
subscribeType: [{ required: true, message: '请选择', trigger: 'change' }],
|
||||
subscribeText: [{ required: true, message: '不能为空', trigger: 'blur' }],
|
||||
};
|
||||
const textLabel = ref('');
|
||||
const confirm = () => {
|
||||
(formRef?.value as any)?.validate((isValid: boolean, invalidFields: any) => {
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
emit('close');
|
||||
});
|
||||
};
|
||||
const typeChange = () => {
|
||||
if (formData.value.subscribeType === '0') {
|
||||
textLabel.value = '手机号';
|
||||
} else if (formData.value.subscribeType === '1') {
|
||||
textLabel.value = '邮箱地址';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.subscribe-container {
|
||||
width: 600px;
|
||||
|
||||
.subscribe-tip {
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: regular;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.subscribe-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
background: #F2F5FC;
|
||||
padding: 20px 32px 0;
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.subscribe-operation {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,7 +11,7 @@
|
||||
@filter-change="handleFilterChange"
|
||||
>
|
||||
<template #default="scope">
|
||||
<a>{{ scope.row.versionName }}</a>
|
||||
<a @click="openVulnDetail(scope.row)">{{ scope.row.versionName }}</a>
|
||||
</template>
|
||||
</d-column>
|
||||
<d-column
|
||||
@@ -100,6 +100,11 @@
|
||||
>你确认删除此项:{{ item.cla_name }} ?</span
|
||||
>
|
||||
</GModal>
|
||||
|
||||
<!-- 漏洞详情 -->
|
||||
<d-drawer v-model="vulnDetailVisable" style="width: auto;">
|
||||
<VulnerabilityDetail :vulnId="currentVuln.id"></VulnerabilityDetail>
|
||||
</d-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -110,9 +115,10 @@ import { ref, reactive } from 'vue';
|
||||
import { getGroupClaList, setGroupClaStatus, deleteGroupCla } from '@/api/cla';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { GModal } from '@/components/Setting/index';
|
||||
import { reqCatch } from '@/utils/catch';
|
||||
import { reqCatch } from '@/utils/catch';
|
||||
import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
|
||||
import { Message } from 'vue-devui';
|
||||
import VulnerabilityDetail from '@/views/Jyh/Version/Detail/VulnerabilityDetail.vue'
|
||||
const { namespace } = getOrgInfo();
|
||||
|
||||
const tableData = ref([
|
||||
@@ -233,6 +239,13 @@ const setClaStatus = async (row: any) => {
|
||||
const signCla = (row: any) => {
|
||||
router.push('/cla/' + row.object_id);
|
||||
};
|
||||
|
||||
const vulnDetailVisable = ref(false);
|
||||
const currentVuln = ref();
|
||||
const openVulnDetail = (row) => {
|
||||
vulnDetailVisable.value = true;
|
||||
currentVuln.value = row;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
204
src/views/Jyh/Version/Detail/VulnerabilityDetail.vue
Normal file
204
src/views/Jyh/Version/Detail/VulnerabilityDetail.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div class="vuln-detail-container">
|
||||
<div class="vuln-title mb-2">{{ vulnDetail.id }}</div>
|
||||
<div class="vuln-sub-title mb-3">
|
||||
<span>{{ vulnDetail.cveId || '--' }}</span>
|
||||
<span class="split-line"></span>
|
||||
<span><span class="release-time">发布时间:</span>{{ vulnDetail.releaseTime || '--' }}</span>
|
||||
</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">{{vulnDetail.id || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">关联漏洞编号</span>
|
||||
<span class="card-val">{{vulnDetail.cnvdId || '--'}}</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row class="mb-3">
|
||||
<d-col :span="24">
|
||||
<span class="card-key width-90">简介</span>
|
||||
<span class="card-val">{{vulnDetail.description || '--'}}</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row class="mb-3">
|
||||
<d-col :span="24">
|
||||
<span class="card-key width-90">额外信息</span>
|
||||
<span class="card-val">
|
||||
<a v-for="link in vulnDetail.links" class="devui-link" :href="link" target="_blank" rel="noreferrer noopener">{{link}}</a>
|
||||
<span v-if="!vulnDetail.links || vulnDetail.links.length === 0">--</span>
|
||||
</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row>
|
||||
<d-col :span="24">
|
||||
<span class="card-key width-90">补丁链接</span>
|
||||
<span class="card-val">
|
||||
<a v-for="link in vulnDetail.links2" class="devui-link" :href="link" target="_blank" rel="noreferrer noopener">{{link}}</a>
|
||||
<span v-if="!vulnDetail.links || vulnDetail.links.length === 0">--</span>
|
||||
</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="12">
|
||||
<span class="card-key width-90">严重性</span>
|
||||
<span class="card-val">{{vulnDetail.id || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">分值</span>
|
||||
<span class="card-val">{{vulnDetail.code || '--'}}</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="12">
|
||||
<span class="card-key width-90">攻击向量</span>
|
||||
<span class="card-val">{{vulnDetail.id || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">攻击复杂度</span>
|
||||
<span class="card-val">{{vulnDetail.complexity || '--'}}</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">{{vulnDetail.compName || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">需要特殊权限</span>
|
||||
<span class="card-val">{{vulnDetail.cnvdId || '--'}}</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="12">
|
||||
<span class="card-key width-90">组件名</span>
|
||||
<span class="card-val">{{vulnDetail.compName || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">深度</span>
|
||||
<span class="card-val">{{vulnDetail.complexity || '--'}}</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">{{vulnDetail.version || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">最新版本</span>
|
||||
<span class="card-val">{{vulnDetail.cnvdId || '--'}}</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row>
|
||||
<d-col :span="24">
|
||||
<span class="card-key width-90">组件依赖关系</span>
|
||||
<span class="card-val">{{vulnDetail.version || '--'}}</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="12">
|
||||
<span class="card-key width-90">补丁版本</span>
|
||||
<span class="card-val">{{vulnDetail.id || '--'}}</span>
|
||||
</d-col>
|
||||
<d-col :span="12">
|
||||
<span class="card-key width-90">修复兼容性</span>
|
||||
<span class="card-val">{{vulnDetail.complexity || '--'}}</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
<d-row>
|
||||
<d-col :span="24">
|
||||
<span class="card-key width-90">修复建议</span>
|
||||
<span class="card-val">{{vulnDetail.description || '--'}}</span>
|
||||
</d-col>
|
||||
</d-row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getVulnDetail } from '@/api/repo';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const propsData = defineProps(['repoId', 'vulnId']);
|
||||
const vulnDetail = ref({
|
||||
id: 'HWPSIRT-2022-29348',
|
||||
cveId: 'CVE-2013-0293',
|
||||
cnvdId: 'CNVD-201105-215',
|
||||
name: '',
|
||||
code: '',
|
||||
description: '华为开发者社区致力于打造华为开发者专属的官方技术交流平台,帮助开发者探索开发实践、交流心得经验、获悉业界动态、解决开发问题。汇聚华为云社区“华为云”领域博客、问答、视频等精彩内容,形成开发者和技术爱好者交流与分享主阵地。',
|
||||
links: ['/home'],
|
||||
links2: ['/home'],
|
||||
vector: '',
|
||||
complexity: '',
|
||||
interactive: '',
|
||||
releaseTime: '2018-07-31',
|
||||
compName: 'mplayer',
|
||||
version: '1.4',
|
||||
});
|
||||
|
||||
const queryVulnDetail = async () => {
|
||||
const data = await getVulnDetail({repoId: propsData.repoId, id: propsData.vulnId});
|
||||
vulnDetail.value = data;
|
||||
};
|
||||
// queryVulnDetail();
|
||||
</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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,18 +9,27 @@
|
||||
<div class="header-top">
|
||||
<GAvatar style="margin-right: 12px" :src="avatarUrl" name="Vue" :width="40" :height="40"></GAvatar>
|
||||
<div>
|
||||
<div class="header-title1">vue</div>
|
||||
<div class="header-title1">{{ softwareData.name }}</div>
|
||||
<div class="header-div">
|
||||
<span class="span1">版本:</span><span class="span2">3.5.13</span>
|
||||
<span class="span1">版本:</span><span class="span2">{{ softwareData.version }}</span>
|
||||
<span class="split"></span>
|
||||
<span class="span1">生命周期状态:</span><span class="span2">选型中</span>
|
||||
<span class="span1">生命周期状态:</span><span class="span2">{{ softwareData.lifecycle }}</span>
|
||||
<span class="split"></span>
|
||||
<span class="span1">集成风险:</span>
|
||||
<d-tag color="#F6933B">低风险</d-tag>
|
||||
<d-tag color="#F6933B">{{ softwareData.risk }}</d-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fr">
|
||||
<d-button class="mr-2" variant="solid">订阅</d-button>
|
||||
<d-button class="mr-2" variant="solid" @click="openSubscription">订阅</d-button>
|
||||
<d-modal class="subscribe-modal" style="width: auto;" v-model="subscribeModalVisable" title="订阅漏洞预警通知">
|
||||
<template #header>
|
||||
<div class="subscribe-header">
|
||||
<d-icon name="icon-info-o" color="var(--devui-info)" size="18px"></d-icon>
|
||||
<span>订阅漏洞预警通知</span>
|
||||
</div>
|
||||
</template>
|
||||
<SubscriptionModal @close="colseSubscription" :softwareData="softwareData"></SubscriptionModal>
|
||||
</d-modal>
|
||||
</div>
|
||||
</div>
|
||||
<d-tabs class="jyh-tabs jyh-tabs-2" type="wrapped" v-model="selectTab">
|
||||
@@ -57,6 +66,7 @@ import LicenseInfo from '../../LicenseInfo/index.vue';
|
||||
const { namespace } = getOrgInfo();
|
||||
const route = useRoute(); // 获取路由对象
|
||||
const avatarUrl = '/src/assets/imgs/jyh/工程首字母图标.png';
|
||||
import SubscriptionModal from '@/views/Jyh/Version/Detail/SubscriptionModal.vue';
|
||||
|
||||
const selectTab = ref('bbxx');
|
||||
|
||||
@@ -157,6 +167,21 @@ const setClaStatus = async (row: any) => {
|
||||
const signCla = (row: any) => {
|
||||
router.push('/cla/' + row.object_id);
|
||||
};
|
||||
|
||||
const softwareData = ref({
|
||||
name: 'vue',
|
||||
version: '3.5.13',
|
||||
lifecycle: '选中型',
|
||||
risk: '低风险',
|
||||
});
|
||||
|
||||
const subscribeModalVisable = ref(false);
|
||||
const openSubscription = () => {
|
||||
subscribeModalVisable.value = true;
|
||||
};
|
||||
const colseSubscription = () => {
|
||||
subscribeModalVisable.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -303,4 +328,25 @@ const signCla = (row: any) => {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.subscribe-modal {
|
||||
width: auto;
|
||||
|
||||
.subscribe-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px 20px 0;
|
||||
>span {
|
||||
margin-left: 8px;
|
||||
color: #191919;
|
||||
font-family: HarmonyOS Sans SC;
|
||||
font-weight: medium;
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
Reference in New Issue
Block a user