Merge branch 'junjie_dev' into 'master'

# Conflicts:
#   conflict src/views/Jyh/Home/index.vue
This commit is contained in:
user8949
2025-03-19 13:24:01 +08:00
24 changed files with 545 additions and 238 deletions

View File

@@ -2,7 +2,7 @@
<html lang="zh"> <html lang="zh">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<!-- <link rel="icon" href="https://cdn-static.gitcode.com/favicon.ico">--> <link rel="icon" href="/logo.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="//homepage-app.gitcode.com" crossorigin /> <link rel="preconnect" href="//homepage-app.gitcode.com" crossorigin />
<link rel="dns-prefetch" href="//homepage-app.gitcode.com"> <link rel="dns-prefetch" href="//homepage-app.gitcode.com">

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -142,10 +142,48 @@ export const getVulnList = (data): Promise<any> => {
request({ request({
url: `/api/v1/repo/vulnerability/page`, url: `/api/v1/repo/vulnerability/page`,
method: 'post', method: 'post',
data, data
}) })
); );
} };
// 获取SBOM依赖树
export const dependencyTree = (softwareId: any): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/repo/dependency/tree`,
method: 'POST',
data: {
softwareId,
current: 1,
size: 99999
}
})
);
};
// 获取开发者社区信息
export const communityInfo = (softwareId: any): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/repo/community/info`,
method: 'POST',
data: {
softwareId
}
})
);
};
// 编辑用户信息(包含订阅默认预警方式)
export const userEdit = (data: any): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/user/edit`,
method: 'POST',
data
})
);
};
// 获取漏洞数据 // 获取漏洞数据
export const getVulnDetail = (data): Promise<any> => { export const getVulnDetail = (data): Promise<any> => {
@@ -153,21 +191,65 @@ export const getVulnDetail = (data): Promise<any> => {
request({ request({
url: `/api/v1/repo/vulnerability/info`, url: `/api/v1/repo/vulnerability/info`,
method: 'POST', method: 'POST',
data, data
}) })
); );
} };
// 迁移批量导入 // 迁移批量导入
export function repoImport(data: types.commonRepoReqType){ export function repoImport(data: types.commonRepoReqType) {
return reqCatchV2(() => return reqCatchV2(() =>
request({ request({
url: `/api/v1/home/software/valid`, url: `/api/v1/home/software/valid`,
method: 'post', method: 'post',
data, data,
headers: { headers: {
'Content-Type': 'multipart/form-data', // 设置请求头 'Content-Type': 'multipart/form-data' // 设置请求头
}, }
})
);
}
// 个人中心-获取预警列表
export const getNoticeList = (data): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/alert/notice/list`,
method: 'POST',
data
})
);
};
// 个人中心-获取组织级预警列表
export const getgroupNoticeList = (data): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/alert/group/notice/list`,
method: 'POST',
data
})
);
};
// 个人中心-获取订阅列表
export const getSubscribeList = (data): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/alert/subscribe/list`,
method: 'POST',
data,
})
);
}
// 个人中心-获取组织级订阅列表
export const getGroupSubscribeList = (data): Promise<any> => {
return reqCatchV2(() =>
request({
url: `/api/v1/alert/group/subscribe/list`,
method: 'POST',
data,
}) })
); );
} }

View File

@@ -40,7 +40,7 @@ export function inviteOrganizationMemberApi(params: { groupId: number, username:
export function deleteOrganizationMemberApi(params: { groupId: number, username: string }): Promise<UnitRes<boolean>> { export function deleteOrganizationMemberApi(params: { groupId: number, username: string }): Promise<UnitRes<boolean>> {
return request({ return request({
url: `/api/v1/group/member/remove`, url: `/api/v1/group/member/remove`,
method: 'delete', method: 'post',
data: params, data: params,
}); });
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
src/assets/imgs/logo2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,5 +1,5 @@
<template> <template>
<d-row class="mt-3"> <d-row class="mt-3" v-if="inited">
<d-col :span="12"> <d-col :span="12">
<d-chart :option="optionConChart" style="width: 100%; height: 400px"></d-chart> <d-chart :option="optionConChart" style="width: 100%; height: 400px"></d-chart>
<p class="text-center mt-translate-y">国家/地球分布</p> <p class="text-center mt-translate-y">国家/地球分布</p>
@@ -11,80 +11,83 @@
</d-row> </d-row>
</template> </template>
<script setup> <script setup lang="ts">
import { ref, reactive } from 'vue'; import { ref, reactive, computed } from 'vue';
import { DChart } from 'vue-devui/echarts'; import { DChart } from 'vue-devui/echarts';
const optionConChart = reactive({
tooltip: { const inited = ref(false);
show: true,
trigger: 'item' const props = withDefaults(
}, defineProps<{
xAxis: { companyGraph: Array<any>;
type: 'category', countryGraph: Array<any>;
data: ['美国', '中国', '德国', '瑞士', '法国', '英国', '印度', '日本', '荷兰', '俄罗斯'] }>(),
}, {
yAxis: { companyGraph: () => [],
// 给y轴添加单位后缀 countryGraph: () => []
axisLabel: { }
formatter: '{value}%' );
const options = (x: any, y: any, color = '#2070F3') => {
return {
tooltip: {
show: true,
trigger: 'item'
}, },
name: '单位', xAxis: {
type: 'value' type: 'category',
}, data: x
series: [ },
{ yAxis: {
data: [12, 14.8, 23.6, 18.6, 17.3, 13.1, 16, 11.8, 13.9, 16.4], // 给y轴添加单位后缀
type: 'bar', axisLabel: {
barWidth: '40%', formatter: '{value}%'
// 给label添加单位后缀
label: {
show: true,
position: 'top',
formatter: '{c}%'
}, },
itemStyle: { name: '单位',
color: '#2070F3', type: 'value'
borderRadius: [5, 5, 0, 0] },
series: [
{
data: y,
type: 'bar',
barWidth: '40%',
// 给label添加单位后缀
label: {
show: true,
position: 'top',
formatter: '{c}%'
},
itemStyle: {
color,
borderRadius: [5, 5, 0, 0]
}
} }
} ]
] };
};
const optionConChart = computed(() => {
return options(
props.countryGraph.map((d) => d.name),
props.countryGraph.map((d) => d.value),
'#2070F3'
);
});
const optionOrgChart = computed(() => {
return options(
props.companyGraph.map((d) => d.name),
props.companyGraph.map((d) => d.value),
'#2CB8C9'
);
}); });
const optionOrgChart = reactive({ const onInited = () => {
tooltip: { setTimeout(() => {
show: true, inited.value = true;
trigger: 'item' }, 100);
}, };
xAxis: { // 向外暴露onInited方法
type: 'category', defineExpose({ onInited });
data: ['公司1', '公司2', '公司3', '公司4', '公司5', '公司6', '公司7', '公司8', '公司9', '公司10']
},
yAxis: {
// 给y轴添加单位后缀
axisLabel: {
formatter: '{value}%'
},
name: '单位',
type: 'value'
},
series: [
{
data: [12, 14.8, 23.6, 18.6, 17.3, 13.1, 16, 11.8, 13.9, 16.4],
type: 'bar',
barWidth: '40%',
// 给label添加单位后缀
label: {
show: true,
position: 'top',
formatter: '{c}%'
},
itemStyle: {
color: '#2CB8C9',
borderRadius: [5, 5, 0, 0]
}
}
]
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -57,7 +57,7 @@ const search = () => {
document.querySelector('#golbalSearch').blur(); document.querySelector('#golbalSearch').blur();
return; return;
} }
router.push({ name: 'Search', query: { val: searchStr.value || '', type: route?.query?.type || 'License' }}); router.push({ name: 'Search', query: { searchWord: searchStr.value || '', type: route?.query?.type || 'software' }});
}; };
const handleClear = () => { const handleClear = () => {
router.push({ name: 'home' }); router.push({ name: 'home' });

View File

@@ -1,18 +1,18 @@
<template> <template>
<div class="full-w" :style="{ height: `${height}px` }"> <div class="full-w" :style="{ height: `${height}px` }">
<div class="g-header fixed z-20" ref="headerRef" :class="{'home-background': isHome}"> <div class="g-header fixed z-20" ref="headerRef" :class="{ 'home-background': isHome }">
<div class="g-toolbar w-full overflow-hidden" :class="[searchClass, route?.meta?.headerClassName]"> <div class="g-toolbar w-full overflow-hidden" :class="[searchClass, route?.meta?.headerClassName]">
<div class="g-toolbar-left flex-shrink items-center"> <div class="g-toolbar-left flex-shrink items-center">
<div class="flex-center gap-[16px]" v-if="!isHome"> <div class="flex-center gap-[16px]" v-if="!isHome">
<!-- <g-icon v-if="!asideSetShow" @click="$emit('clickMenu')" name="gt-hamburger" size="20px" class="cursor-pointer hover:!text-black" color="#1D1F3A"></g-icon>--> <!-- <g-icon v-if="!asideSetShow" @click="$emit('clickMenu')" name="gt-hamburger" size="20px" class="cursor-pointer hover:!text-black" color="#1D1F3A"></g-icon>-->
<GLink class="g-toolbar-left-logo" :href="baseUrl" /> <GLink class="g-toolbar-left-logo" :href="baseUrl" />
<GLink class="g-toolbar-left-title" :href="baseUrl">可信代码库</GLink> <!-- <GLink class="g-toolbar-left-title" :href="baseUrl">可信代码库</GLink>-->
<!-- <Entrance v-if="isLogin" :is-mobile="isMobile" /> --> <!-- <Entrance v-if="isLogin" :is-mobile="isMobile" /> -->
</div> </div>
</div> </div>
<div class="flex-1 flex items-center justify-end" v-if="!isHome"> <div class="flex-1 flex items-center justify-end" v-if="!isHome">
<Search class="g-toolbar-left-search" v-if="!isMobile" :key="$route.fullPath"/> <Search class="g-toolbar-left-search" v-if="!isMobile" :key="$route.fullPath" />
</div> </div>
<div class="g-toolbar-right gap-[12px] flex-grow-0 flex-shrink-0"> <div class="g-toolbar-right gap-[12px] flex-grow-0 flex-shrink-0">
<GLink <GLink
@@ -30,21 +30,23 @@
<GIcon name="gt-plane-add" size="16px" color="#9C9DB4" /> <GIcon name="gt-plane-add" size="16px" color="#9C9DB4" />
<span>新建</span> <span>新建</span>
</d-button> </d-button>
<div class="cursor-pointer hidden-m" @click="handleLogin('login')" v-if="inSearch"><span>搜索记录</span></div> <div class="cursor-pointer hidden-m" @click="handleLogin('login')" v-if="inSearch">
<d-button variant="solid" color="primary" @click="handleLogin('login')"></d-button> <span>搜索记</span>
</div>
<d-button @click="handleLogin('register')" class="min-w-[64px]">注册</d-button> <d-button @click="handleLogin('register')" class="min-w-[64px]">注册</d-button>
<d-button variant="solid" color="primary" @click="handleLogin('login')">Gitcode账号登录</d-button>
</template> </template>
<template v-else> <template v-else>
<!--ai copilot--> <!--ai copilot-->
<!-- <a class="g-header-copilot" href="/ai-copilot/">--> <!-- <a class="g-header-copilot" href="/ai-copilot/">-->
<!-- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">--> <!-- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">-->
<!-- <path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 6C2.5 4.89543 3.39543 4 4.5 4H11.5C12.6046 4 13.5 4.89543 13.5 6V12C13.5 13.1046 12.6046 14 11.5 14H4.5C3.39543 14 2.5 13.1046 2.5 12V6ZM4.5 8C4.5 7.44772 4.94772 7 5.5 7C6.05228 7 6.5 7.44772 6.5 8V9C6.5 9.55228 6.05228 10 5.5 10C4.94772 10 4.5 9.55228 4.5 9V8ZM10.5 7C9.94772 7 9.5 7.44772 9.5 8V9C9.5 9.55228 9.94772 10 10.5 10C11.0523 10 11.5 9.55228 11.5 9V8C11.5 7.44772 11.0523 7 10.5 7Z" fill="white"/>--> <!-- <path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 6C2.5 4.89543 3.39543 4 4.5 4H11.5C12.6046 4 13.5 4.89543 13.5 6V12C13.5 13.1046 12.6046 14 11.5 14H4.5C3.39543 14 2.5 13.1046 2.5 12V6ZM4.5 8C4.5 7.44772 4.94772 7 5.5 7C6.05228 7 6.5 7.44772 6.5 8V9C6.5 9.55228 6.05228 10 5.5 10C4.94772 10 4.5 9.55228 4.5 9V8ZM10.5 7C9.94772 7 9.5 7.44772 9.5 8V9C9.5 9.55228 9.94772 10 10.5 10C11.0523 10 11.5 9.55228 11.5 9V8C11.5 7.44772 11.0523 7 10.5 7Z" fill="white"/>-->
<!-- <path opacity="0.6" fill-rule="evenodd" clip-rule="evenodd" d="M8.75 3.29933C9.19835 3.03997 9.5 2.55521 9.5 2C9.5 1.17157 8.82843 0.5 8 0.5C7.17157 0.5 6.5 1.17157 6.5 2C6.5 2.55521 6.80165 3.03997 7.25 3.29933V5.5H8.75V3.29933ZM0 7C0 6.44772 0.447715 6 1 6H1.5V12H1C0.447715 12 0 11.5523 0 11V7ZM15 6H14.5V12H15C15.5523 12 16 11.5523 16 11V7C16 6.44772 15.5523 6 15 6Z" fill="white"/>--> <!-- <path opacity="0.6" fill-rule="evenodd" clip-rule="evenodd" d="M8.75 3.29933C9.19835 3.03997 9.5 2.55521 9.5 2C9.5 1.17157 8.82843 0.5 8 0.5C7.17157 0.5 6.5 1.17157 6.5 2C6.5 2.55521 6.80165 3.03997 7.25 3.29933V5.5H8.75V3.29933ZM0 7C0 6.44772 0.447715 6 1 6H1.5V12H1C0.447715 12 0 11.5523 0 11V7ZM15 6H14.5V12H15C15.5523 12 16 11.5523 16 11V7C16 6.44772 15.5523 6 15 6Z" fill="white"/>-->
<!-- </svg>--> <!-- </svg>-->
<!-- <span class="ml-xs">AI Copilot</span>--> <!-- <span class="ml-xs">AI Copilot</span>-->
<!-- </a>--> <!-- </a>-->
<!-- <Create />--> <!-- <Create />-->
<!-- <SearchAiHistory />--> <!-- <SearchAiHistory />-->
<d-popover content="提示!" trigger="hover" style="background-color: #7693f5; color: #fff"> <d-popover content="提示!" trigger="hover" style="background-color: #7693f5; color: #fff">
<d-icon style="font-size: 16px" name="icon-helping" /> <d-icon style="font-size: 16px" name="icon-helping" />
</d-popover> </d-popover>
@@ -109,9 +111,7 @@ const { isMobile } = usePageResize();
/* store 用户信息 */ /* store 用户信息 */
/* @test 后面将清除 */ /* @test 后面将清除 */
watchEffect(() => { watchEffect(() => {});
});
microApp.router.beforeEach({ microApp.router.beforeEach({
'micoro-app-homeweb-app': (to, from) => { 'micoro-app-homeweb-app': (to, from) => {
if (to.pathname === '/search') { if (to.pathname === '/search') {
@@ -134,8 +134,8 @@ $add-radius: 48px;
$header-bg: #fff; $header-bg: #fff;
.home-background { .home-background {
background-color: #fff0 !important; background-color: #fff0 !important;
} }
.g-header { .g-header {
// overflow: hidden; // overflow: hidden;
@@ -150,7 +150,7 @@ $header-bg: #fff;
} }
.g-header-copilot { .g-header-copilot {
background: rgba(41, 81, 224, 1); background: rgba(41, 81, 224, 1);
color: #FFF; color: #fff;
width: 120px; width: 120px;
border-radius: 48px; border-radius: 48px;
height: 32px; height: 32px;
@@ -159,7 +159,7 @@ $header-bg: #fff;
cursor: pointer; cursor: pointer;
justify-content: center; justify-content: center;
&:hover { &:hover {
background: rgba(41, 81, 224, .8); background: rgba(41, 81, 224, 0.8);
} }
} }
.g-toolbar { .g-toolbar {
@@ -171,7 +171,7 @@ $header-bg: #fff;
flex-basis: 56px; flex-basis: 56px;
overflow: hidden; overflow: hidden;
padding: 0 24px; padding: 0 24px;
border-bottom: 1px solid #F1F1F8; border-bottom: 1px solid #f1f1f8;
:deep(.devui-button) { :deep(.devui-button) {
padding: 6px 16px; padding: 6px 16px;
border-radius: $add-radius; border-radius: $add-radius;
@@ -182,9 +182,9 @@ $header-bg: #fff;
gap: 25px; gap: 25px;
&-logo { &-logo {
display: inline-block; display: inline-block;
width: 28px; width: 90px;
height: 28px; height: 32px;
background: url(../../assets/imgs/logo/logo.png) no-repeat; background: url(../../assets/imgs/logo2.png) no-repeat;
background-size: contain; background-size: contain;
vertical-align: middle; vertical-align: middle;
background-position: 0 center; background-position: 0 center;
@@ -202,14 +202,14 @@ $header-bg: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
@media screen and (max-width: 576px) { @media screen and (max-width: 576px) {
@apply gap-[16px]; @apply gap-[16px];
} }
} }
&.border-b-transparent { &.border-b-transparent {
border-bottom-color: transparent !important; border-bottom-color: transparent !important;
} }
&.border-b-show { &.border-b-show {
border-bottom-color: #F1F1F8 !important; border-bottom-color: #f1f1f8 !important;
} }
} }
.g-header-gray { .g-header-gray {
@@ -256,12 +256,12 @@ $header-bg: #fff;
} }
} }
@media screen and (max-width:576px) { @media screen and (max-width: 576px) {
.hidden-m { .hidden-m {
display: none; display: none;
} }
.g-header-copilot { .g-header-copilot {
display: none!important;; display: none !important;
} }
} }
</style> </style>

View File

@@ -368,7 +368,7 @@ const columns = ref([
{ key: 'communityHash', label: '社区hash值', visible: false, filterable: false, sortable: false }, { key: 'communityHash', label: '社区hash值', visible: false, filterable: false, sortable: false },
{ key: 'softwareScore', label: '软件评分', visible: false, filterable: false, sortable: true }, { key: 'softwareScore', label: '软件评分', visible: false, filterable: false, sortable: true },
{ key: 'sourceCodeDownload', label: '源码包下载地址', visible: true, filterable: false, sortable: false }, { key: 'sourceCodeDownload', label: '源码包下载地址', visible: true, filterable: false, sortable: false },
{ key: 'copyright', label: 'CopyRight', visible: false, filterable: false, sortable: false }, { key: 'copyright', label: 'Copyright', visible: false, filterable: false, sortable: false },
{ key: 'externalVulnerabilitySource', label: '外部漏洞源的软件名称', visible: false, filterable: true, sortable: false }, { key: 'externalVulnerabilitySource', label: '外部漏洞源的软件名称', visible: false, filterable: true, sortable: false },
{ key: 'versionDescription', label: '版本描述', visible: false, filterable: false, sortable: false }, { key: 'versionDescription', label: '版本描述', visible: false, filterable: false, sortable: false },
{ key: 'compatibilityRisk', label: '兼容性风险描述', visible: false, filterable: false, sortable: false }, { key: 'compatibilityRisk', label: '兼容性风险描述', visible: false, filterable: false, sortable: false },

View File

@@ -2,7 +2,7 @@
<div class="home-container"> <div class="home-container">
<div class="home-content"> <div class="home-content">
<div class="home-title"> <div class="home-title">
<img src="@/assets/imgs/home/home-title-logo-2x.webp" alt="logo" /> <img src="@/assets/imgs/logo.png" alt="logo" />
<h1>可信开源代码库</h1> <h1>可信开源代码库</h1>
</div> </div>
<div class="home-search" ref="homeSearch" :class="{ 'glow-border': inputGlow }"> <div class="home-search" ref="homeSearch" :class="{ 'glow-border': inputGlow }">
@@ -59,9 +59,9 @@
<div class="info-title"> <div class="info-title">
<div class="sub-title"> <div class="sub-title">
<img src="@/assets/imgs/home/informIcon@2x.png"> <img src="@/assets/imgs/home/informIcon@2x.png">
<span>信息公示</span> <span>预警公告</span>
</div> </div>
<a class="devui-link" @click="checkMore">更多 ></a> <a v-if="isLogin" class="devui-link" @click="checkMore">更多 ></a>
</div> </div>
<div class="info-content"> <div class="info-content">
<d-timeline :direction="'vertical'" :time-position="'right'" :position="'right'"> <d-timeline :direction="'vertical'" :time-position="'right'" :position="'right'">
@@ -89,7 +89,7 @@
</div> </div>
</div> </div>
<d-modal class="warning-modal" v-model="warningModalVisable" title="主题:" style="width: 600px;"> <d-modal class="warning-modal" v-model="warningModalVisable" title="" style="width: 600px;">
<EarlyWarningDetail :warningData="currentWarning" :type="'user'"></EarlyWarningDetail> <EarlyWarningDetail :warningData="currentWarning" :type="'user'"></EarlyWarningDetail>
</d-modal> </d-modal>
</template> </template>
@@ -100,9 +100,10 @@ import { useRoute, useRouter } from 'vue-router';
import AdvanceSearch from '@/components/AdvanceSearch/index.vue'; import AdvanceSearch from '@/components/AdvanceSearch/index.vue';
import { getHomeNoticeList } from '@/api/jyh' import { getHomeNoticeList } from '@/api/jyh'
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue'; import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
import { useAccountStore } from '@/stores/user'; import { useDiscussGetUserInfo } from '@/api/discussion/hook';
const userStore = useAccountStore(); // 获取当前用户信息 & 是否登录
const { isLogin = false, userInfo = {}} = useDiscussGetUserInfo();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const inputGlow = ref(false); const inputGlow = ref(false);
@@ -202,7 +203,7 @@ const openWarningDetail = (event, index) => {
item.dotColor = ''; item.dotColor = '';
} }
}) })
warningModalVisable.value = true; warningModalVisable.value = true;
currentWarning.value = event; currentWarning.value = event;
} }
@@ -269,7 +270,7 @@ getNoticeList();
img { img {
width: 50px; width: 50px;
filter: brightness(0); //filter: brightness(0);
} }
} }
@@ -409,7 +410,7 @@ getNoticeList();
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
margin-right: 8px; margin-right: 8px;
span { span {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="warning-detail-container"> <div class="warning-detail-container">
<div class="warning-title"> <div class="warning-title">
<div>{{ warningData.subject }}</div> <div style="padding-right: 20px;">{{ warningData.subject }}</div>
<div class="sub-title mt-3"> <div class="sub-title mt-3">
<div> <div>
<span>重要性</span> <span>重要性</span>
@@ -20,7 +20,7 @@
:toolbar-config="toolbarConfig" :toolbar-config="toolbarConfig"
></d-editor-md> ></d-editor-md>
</div> </div>
<div :style="{'border-radius': propsData.type === 'user' ? '6px' : 0}" class="warning-from">{{warningData.group}} {{ warningData.pulishTime }}</div> <div :style="{'border-radius': propsData.type === 'user' ? '6px' : 0}" class="warning-from">{{warningData.group}} {{ warningData.publishTime }}</div>
<div v-if="propsData.type === 'system'" class="warning-operation"> <div v-if="propsData.type === 'system'" class="warning-operation">
<d-button @click="confirm" variant="solid" class="mr-2">确定</d-button> <d-button @click="confirm" variant="solid" class="mr-2">确定</d-button>
<d-button @click="$emit('close')">取消</d-button> <d-button @click="$emit('close')">取消</d-button>
@@ -40,7 +40,8 @@ const toolbarConfig = [
['ul', 'ol', 'checklist', 'code', 'link', 'image', 'table'], ['ul', 'ol', 'checklist', 'code', 'link', 'image', 'table'],
]; ];
const mode = ref('readonly'); const mode = ref('readonly');
warningData.value = JSON.parse(propsData.warningData.alertMsg ?? JSON.stringify({ console.log(propsData.warningData)
warningData.value = propsData.warningData ?? {
subject: '【漏洞排查预警】ApacheIgnite远程代码执行漏洞排查CVE-2024-52577)', subject: '【漏洞排查预警】ApacheIgnite远程代码执行漏洞排查CVE-2024-52577)',
importance: '高', importance: '高',
group: '可信开源代码库运营团队', group: '可信开源代码库运营团队',
@@ -49,7 +50,7 @@ warningData.value = JSON.parse(propsData.warningData.alertMsg ?? JSON.stringify(
近日安全中心发现Apache lgnite远程代码执行漏洞CVE-2024-52577。在 2.6.0<Apache Ignite< 2.17.0版本中由于lgnite未能正确实施类序列化过滤器攻击者能够利用恶意序列化对象绕过安全检查从而在服务器端反序列化时触发任意代码的执行。经可信开源代码库运营团队评审漏洞技术定级2级/3级若不满足利用条件可举证降为6级。请你按要求在XX时间内完成修复。 近日安全中心发现Apache lgnite远程代码执行漏洞CVE-2024-52577。在 2.6.0<Apache Ignite< 2.17.0版本中由于lgnite未能正确实施类序列化过滤器攻击者能够利用恶意序列化对象绕过安全检查从而在服务器端反序列化时触发任意代码的执行。经可信开源代码库运营团队评审漏洞技术定级2级/3级若不满足利用条件可举证降为6级。请你按要求在XX时间内完成修复。
## 二、修复方案 ## 二、修复方案
升级Apache Ignite至安全版本2.17.0` 升级Apache Ignite至安全版本2.17.0`
})); };
const confirm = () => { const confirm = () => {
emit('close'); emit('close');
}; };

View File

@@ -1,22 +1,34 @@
<template> <template>
<Card simple class="jyh-card mt-3"> <Card simple class="jyh-card mt-3">
<div class="card-title">组织预警通知列表</div>
<div class="mb-3"> <div class="mb-3">
<d-table class="jyh-table jyh-table-2" :header-bg="true" :data="licenseTableData"> <d-table v-if="tableData.length>0" class="jyh-table jyh-table-2" :header-bg="true" :data="tableData">
<d-column field="code" header="时间"></d-column> <d-column field="updateTime" header="时间">
<template #default="scope">
<span>{{ formatTime(scope.row.updateTime, 'YYYY-MM-DD') }}</span>
</template>
</d-column>
<d-column field="name" header="标题"> <d-column field="name" header="标题">
<template #default="scope"> <template #default="scope">
<a @click="openWarningDetail(scope.row)">{{ scope.row.name }}</a> <a @click="openWarningDetail(scope.row)">{{ scope.row.name }}</a>
</template> </template>
</d-column> </d-column>
<d-column field="detail" header="详情"></d-column> <d-column field="alertMsg" header="详情">
<d-column field="owner" header="订阅人"></d-column> <template #default="scope">
<span>{{ JSON.parse(scope.row.alertMsg)?.overview || ''}}</span>
</template>
</d-column>
<d-column field="level" header="级别"> <d-column field="level" header="级别">
<template #default="scope, text"> <template #default="scope">
<d-status v-if="scope.row.level === 4" type="error">危险</d-status> <d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '高'" type="error">
<d-status v-if="scope.row.level === 3" type="warning">严重</d-status> {{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
<d-status v-if="scope.row.level === 2" class="yellow-status">一般</d-status> </d-status>
<d-status v-if="scope.row.level === 1" type="running">提示</d-status> <d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '中'" type="warning">
{{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
</d-status>
<d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '低'" class="yellow-status">
{{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
</d-status>
<!-- <d-status v-if="scope.row.importance === 1" type="running">提示</d-status>-->
</template> </template>
</d-column> </d-column>
<d-column field="status" header="状态"> <d-column field="status" header="状态">
@@ -26,7 +38,17 @@
</template> </template>
</d-column> </d-column>
</d-table> </d-table>
<NoData v-else :small="false"></NoData>
</div> </div>
<div class="mt-20 mb-20 flex justify-end">
<d-pagination size="md" :page-size-options="[10, 20, 50]" :total="pager.total"
v-model:pageSize="pager.pageSize" v-model:pageIndex="pager.pageIndex" :max-items="5"
:can-change-page-size="true" :can-view-total="true" total-item-text="总计" @page-index-change="changeIndex()"
@page-size-change="changeSize()" />
</div>
</Card> </Card>
<d-modal class="warning-modal" v-model="warningModalVisable" title=""> <d-modal class="warning-modal" v-model="warningModalVisable" title="">
@@ -35,25 +57,45 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue'; import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
import NoData from "@/components/NoData/NoData.vue";
import { getgroupNoticeList, getNoticeList } from '@/api/jyh';
const licenseTableData = ref([ const tableData = ref([
{ code: '05822156', name: 'MIT License', detail: 'integer', owner: 'admin', level: 4, status: 1 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 4, status: 1 },
{ code: '05822156', name: 'MIT License', detail: 'integer', owner: 'admin', level: 3, status: 2 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 3, status: 2 },
{ code: '05822156', name: 'MIT License', detail: 'integer', owner: 'admin', level: 2, status: 2 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 2, status: 1 },
{ code: '05822156', name: 'MIT License', detail: 'integer', owner: 'admin', level: 1, status: 2 } // { code: '05822156', name: 'MIT License', detail: 'integer', level: 1, status: 2 }
]); ]);
const pager = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
const warningModalVisable = ref(false); const warningModalVisable = ref(false);
const currentWarning = ref(); const currentWarning = ref();
const openWarningDetail = (row) => { const openWarningDetail = (row) => {
warningModalVisable.value = true; warningModalVisable.value = true;
currentWarning.value = row; currentWarning.value = JSON.parse(row.alertMsg ?? '{}');
}; };
const colseWarningDetail = () => { const colseWarningDetail = () => {
warningModalVisable.value = false; warningModalVisable.value = false;
}; };
const getList = async() => {
const { data, error } = await getgroupNoticeList({ current: 1,size: pager.value.pageSize });
if (!error && data) {
tableData.value = data.data.data.records;
pager.value.total = data.data.data.total;
}
};
onMounted(async() => {
getList();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,31 +1,50 @@
<template> <template>
<Card simple class="jyh-card mt-3"> <Card simple class="jyh-card mt-3">
<div class="card-title">个人预警通知列表</div>
<div class="mb-3"> <div class="mb-3">
<d-table class="jyh-table jyh-table-2" :header-bg="true" :data="licenseTableData"> <d-table v-if="tableData.length>0" class="jyh-table jyh-table-2" :header-bg="true" :data="tableData">
<d-column field="code" header="时间"></d-column> <d-column field="updateTime" header="时间"></d-column>
<d-column field="name" header="标题"> <d-column field="name" header="标题">
<template #default="scope"> <template #default="scope">
<a @click="openWarningDetail(scope.row)">{{ scope.row.name }}</a> <a @click="openWarningDetail(scope.row)">{{ scope.row.name }}</a>
</template> </template>
</d-column> </d-column>
<d-column field="detail" header="详情"></d-column> <d-column field="alertMsg" header="详情">
<template #default="scope">
<span>{{ JSON.parse(scope.row.alertMsg)?.overview || ''}}</span>
</template>
</d-column>
<d-column field="level" header="级别"> <d-column field="level" header="级别">
<template #default="scope, text"> <template #default="scope">
<d-status v-if="scope.row.level === 4" type="error">危险</d-status> <d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '高'" type="error">
<d-status v-if="scope.row.level === 3" type="warning">严重</d-status> {{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
<d-status v-if="scope.row.level === 2" class="yellow-status">一般</d-status> </d-status>
<d-status v-if="scope.row.level === 1" type="running">提示</d-status> <d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '中'" type="warning">
{{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
</d-status>
<d-status v-if="JSON.parse(scope.row.alertMsg)?.importance === '低'" class="yellow-status">
{{ JSON.parse(scope.row.alertMsg)?.importance || ''}}
</d-status>
<!-- <d-status v-if="scope.row.importance === 1" type="running">提示</d-status>-->
</template> </template>
</d-column> </d-column>
<d-column field="status" header="状态"> <d-column field="status" header="状态">
<template #default="scope, text"> <template #default="scope, text">
<d-tag v-if="scope.row.status === 1" type="danger" size="sm">未读</d-tag> <d-tag v-if="scope.row.status === 0" type="danger" size="sm">未读</d-tag>
<d-tag v-if="scope.row.status === 2" type="success" size="sm">已读</d-tag> <d-tag v-if="scope.row.status === 1" type="success" size="sm">已读</d-tag>
</template> </template>
</d-column> </d-column>
</d-table> </d-table>
<NoData v-else :small="false"></NoData>
</div> </div>
<div class="mt-20 mb-20 flex justify-end">
<d-pagination size="md" :page-size-options="[10, 20, 50]" :total="pager.total"
v-model:pageSize="pager.pageSize" v-model:pageIndex="pager.pageIndex" :max-items="5"
:can-change-page-size="true" :can-view-total="true" total-item-text="总计" @page-index-change="changeIndex()"
@page-size-change="changeSize()" />
</div>
</Card> </Card>
<d-modal class="warning-modal" v-model="warningModalVisable" title=""> <d-modal class="warning-modal" v-model="warningModalVisable" title="">
@@ -34,25 +53,45 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue'; import EarlyWarningDetail from '@/views/Jyh/PersonalCenter/Detail/EarlyWarningDetail.vue';
import NoData from "@/components/NoData/NoData.vue";
import { getNoticeList } from '@/api/jyh';
const licenseTableData = ref([ const tableData = ref([
{ code: '05822156', name: 'MIT License', detail: 'integer', level: 4, status: 1 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 4, status: 1 },
{ code: '05822156', name: 'MIT License', detail: 'integer', level: 3, status: 2 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 3, status: 2 },
{ code: '05822156', name: 'MIT License', detail: 'integer', level: 2, status: 1 }, // { code: '05822156', name: 'MIT License', detail: 'integer', level: 2, status: 1 },
{ code: '05822156', name: 'MIT License', detail: 'integer', level: 1, status: 2 } // { code: '05822156', name: 'MIT License', detail: 'integer', level: 1, status: 2 }
]); ]);
const pager = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
const warningModalVisable = ref(false); const warningModalVisable = ref(false);
const currentWarning = ref(); const currentWarning = ref();
const openWarningDetail = (row) => { const openWarningDetail = (row) => {
warningModalVisable.value = true; warningModalVisable.value = true;
currentWarning.value = row; currentWarning.value = JSON.parse(row.alertMsg ?? '{}');
}; };
const colseWarningDetail = () => { const colseWarningDetail = () => {
warningModalVisable.value = false; warningModalVisable.value = false;
}; };
const getList = async() => {
const { data, error } = await getNoticeList({ current: 1,size: pager.value.pageSize });
if (!error && data) {
tableData.value = data.data.data.records;
pager.value.total = data.data.data.total;
}
};
onMounted(async() => {
getList();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,8 +1,7 @@
<template> <template>
<div class="invitation-notice-container"> <div class="invitation-notice-container">
<Card simple class="jyh-card mt-3"> <Card simple class="jyh-card mt-3">
<div class="card-title">邀请通知列表</div> <div class="mt-3">
<div class="mb-3">
<d-table <d-table
class="jyh-table jyh-table-2" class="jyh-table jyh-table-2"
:header-bg="true" :header-bg="true"
@@ -87,12 +86,13 @@ const handleAccept = async (row, type) => {
}); });
if (data?.data?.data?.data) { if (data?.data?.data?.data) {
Message({ Message({
type, type: 'success',
message: '成功接受', message: '成功接受',
}); });
queryInviteListData();
} else { } else {
Message({ Message({
type, type: 'error',
message: '接受失败', message: '接受失败',
}); });
} }
@@ -106,4 +106,4 @@ const handleAccept = async (row, type) => {
text-align: right; text-align: right;
} }
} }
</style> </style>

View File

@@ -1,12 +1,11 @@
<template> <template>
<Card simple class="jyh-card mt-3"> <Card simple class="jyh-card mt-3">
<div class="card-title">组织订阅列表</div>
<div class="mb-3"> <div class="mb-3">
<d-table class="jyh-table jyh-table-2" :header-bg="true" :data="tableData"> <d-table v-if="tableData.length>0" class="jyh-table jyh-table-2" :header-bg="true" :data="tableData">
<d-column field="code" header="订阅时间"></d-column> <d-column field="updateTime" header="订阅时间"></d-column>
<d-column field="name" header="软件名称"></d-column> <d-column field="name" header="软件名称"></d-column>
<d-column field="detail" header="版本号"></d-column> <d-column field="releaseId" header="版本号"></d-column>
<d-column field="owner" header="订阅人"></d-column> <d-column field="username" header="订阅人"></d-column>
<d-column header="操作" width="100"> <d-column header="操作" width="100">
<template #default="scope"> <template #default="scope">
<d-popover> <d-popover>
@@ -24,17 +23,39 @@
</template> </template>
</d-column> </d-column>
</d-table> </d-table>
<NoData v-else :small="false"></NoData>
</div> </div>
</Card> </Card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
const tableData = ref([{ code: '05822156', name: 'MIT License', detail: 'integer', owner: 'admin' }]); import { getgroupNoticeList, getGroupSubscribeList, getSubscribeList } from '@/api/jyh';
import NoData from "@/components/NoData/NoData.vue";
const tableData = ref([]);
const hidden = () => { const hidden = () => {
// 模拟body点击操作 // 模拟body点击操作
document.querySelector('body')?.click(); document.querySelector('body')?.click();
}; };
const pager = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
const getList = async() => {
const { data, error } = await getGroupSubscribeList({ current: 1,size: pager.value.pageSize });
if (!error && data) {
tableData.value = data.data.data.records;
pager.value.total = data.data.data.total;
}
};
onMounted(async() => {
getList();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,11 +1,11 @@
<template> <template>
<Card simple class="jyh-card mt-3"> <Card simple class="jyh-card mt-3">
<div class="card-title">个人订阅列表</div>
<div class="mb-3"> <div class="mb-3">
<d-table class="jyh-table jyh-table-2" :header-bg="true" :data="tableData"> <d-table v-if="tableData.length>0" class="jyh-table jyh-table-2" :header-bg="true" :data="tableData">
<d-column field="code" header="订阅时间"></d-column> <d-column field="updateTime" header="订阅时间"></d-column>
<d-column field="name" header="软件名称"></d-column> <d-column field="name" header="软件名称"></d-column>
<d-column field="detail" header="版本号"></d-column> <d-column field="releaseId" header="版本号"></d-column>
<d-column field="username" header="订阅人"></d-column>
<d-column header="操作" width="100"> <d-column header="操作" width="100">
<template #default="scope"> <template #default="scope">
<d-popover> <d-popover>
@@ -23,17 +23,39 @@
</template> </template>
</d-column> </d-column>
</d-table> </d-table>
<NoData v-else :small="false"></NoData>
</div> </div>
</Card> </Card>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { onMounted, ref } from 'vue';
const tableData = ref([{ code: '05822156', name: 'MIT License', detail: 'integer' }]); import { getgroupNoticeList, getGroupSubscribeList, getSubscribeList } from '@/api/jyh';
import NoData from "@/components/NoData/NoData.vue";
const tableData = ref([]);
const hidden = () => { const hidden = () => {
// 模拟body点击操作 // 模拟body点击操作
document.querySelector('body')?.click(); document.querySelector('body')?.click();
}; };
const pager = ref({
total: 0,
pageIndex: 1,
pageSize: 10
});
const getList = async() => {
const { data, error } = await getSubscribeList({ current: 1,size: pager.value.pageSize });
if (!error && data) {
tableData.value = data.data.data.records;
pager.value.total = data.data.data.total;
}
};
onMounted(async() => {
getList();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -32,7 +32,7 @@
<div class="font-bold text-[14px] mb-[12px]">成员管理</div> <div class="font-bold text-[14px] mb-[12px]">成员管理</div>
<div class="flex mb-[12px]"> <div class="flex mb-[12px]">
<d-button icon="add" variant="solid" class="mr-[8px]" @click="openInviteMemberModal">邀请成员</d-button> <d-button icon="add" variant="solid" class="mr-[8px]" @click="openInviteMemberModal">邀请成员</d-button>
<d-search icon-position="left" class="w-[296px]" placeholder="请输入搜索内容" /> <d-search icon-position="left" class="w-[296px]" placeholder="请输入搜索内容" @search="getMemberList" />
</div> </div>
<d-table <d-table
:data="memberTableData" :data="memberTableData"
@@ -155,7 +155,7 @@ const userInfo = shallowRef<UserInfoType>({
groupDesc: null, groupDesc: null,
}); });
const searchOrganizationLoading = ref(false); const searchOrganizationLoading = ref(false);
const hasOrganization = ref(false); const hasOrganization = ref(true);
const organizationInfo = shallowRef<OrganizationInfoType>({ const organizationInfo = shallowRef<OrganizationInfoType>({
groupId: 0, groupId: 0,
organizationName: '', organizationName: '',
@@ -218,13 +218,14 @@ async function queryUserInfo() {
userInfo.value = res.data?.data.data; userInfo.value = res.data?.data.data;
} }
if (userInfo.value.groupId) { if (userInfo.value.groupId) {
hasOrganization.value = true;
organizationInfo.value = { organizationInfo.value = {
groupId: userInfo.value.groupId, groupId: userInfo.value.groupId,
organizationName: userInfo.value.groupName as string, organizationName: userInfo.value.groupName as string,
organizationProfile: userInfo.value.groupDesc as string, organizationProfile: userInfo.value.groupDesc as string,
}; };
getMemberList(); getMemberList();
} else {
hasOrganization.value = false;
} }
} catch (e) { } catch (e) {
Message.error('查询用户信息失败'); Message.error('查询用户信息失败');

View File

@@ -4,21 +4,33 @@
<div class="text-[14px] w-full flex items-center justify-between"> <div class="text-[14px] w-full flex items-center justify-between">
<div class="font-bold mb-[16px]">基础信息</div> <div class="font-bold mb-[16px]">基础信息</div>
</div> </div>
<d-form layout="vertical" class="ml-3 mr-3" :data="forms"> <d-form ref="formRef" layout="vertical" class="ml-3 mr-3" :data="forms">
<d-row :gutter="16"> <d-row :gutter="16">
<d-col span="8"> <d-col span="8">
<d-form-item field="name" label="名称" required> <d-form-item
<d-input v-model="forms.name" /> field="nickname"
label="名称"
:rules="[{ required: true, message: '请填写名称', trigger: 'blur' }]"
>
<d-input v-model="forms.nickname" />
</d-form-item> </d-form-item>
</d-col> </d-col>
<d-col span="8"> <d-col span="8">
<d-form-item field="email" label="邮件" required> <d-form-item
field="email"
label="邮件"
:rules="[{ required: true, message: '请填写邮件', trigger: 'blur' }]"
>
<d-input v-model="forms.email" /> <d-input v-model="forms.email" />
</d-form-item> </d-form-item>
</d-col> </d-col>
<d-col span="8"> <d-col span="8">
<d-form-item field="phone" label="电话" required> <d-form-item
<d-input v-model="forms.phone" /> field="mobile"
label="电话"
:rules="[{ required: true, message: '请填写电话', trigger: 'blur' }]"
>
<d-input v-model="forms.mobile" />
</d-form-item> </d-form-item>
</d-col> </d-col>
</d-row> </d-row>
@@ -29,29 +41,71 @@
<div class="font-bold mb-[16px]">预警通知设置</div> <div class="font-bold mb-[16px]">预警通知设置</div>
</div> </div>
<d-form layout="vertical"> <d-form layout="vertical">
<d-form-item field="radio" label="是否开启邮件通知"> <d-form-item field="radio" label="是否开启预警通知">
<d-radio-group direction="row" v-model="radio"> <d-radio-group direction="row" v-model="forms.userExt.emailAlertSwitch">
<d-radio value="0">开启</d-radio> <d-radio :value="true">开启</d-radio>
<d-radio value="1">关闭</d-radio> <d-radio :value="false">关闭</d-radio>
</d-radio-group> </d-radio-group>
</d-form-item> </d-form-item>
</d-form> </d-form>
</d-card> </d-card>
<div class="flex"> <div class="flex">
<d-button variant="solid" class="mr-[8px]">提交</d-button> <d-button variant="solid" class="mr-[8px]" @click="save" :loading="loading">保存</d-button>
<d-button color="secondary" class="mr-[8px]">保存草稿</d-button> <!-- <d-button color="secondary" class="mr-[8px]">保存草稿</d-button> -->
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, shallowRef } from 'vue'; import { userEdit } from '@/api/jyh';
const radio = ref('1'); import { getUserInfo } from '@/api/user';
import { onMounted, reactive, ref, shallowRef } from 'vue';
import { Message } from 'vue-devui';
import { useAccountStore } from '@/stores/user';
const loading = ref(false);
const forms = reactive({ const forms = reactive({
name: '', nickname: '',
mobile: '',
email: '', email: '',
phone: '' userExt: {
emailAlertSwitch: true
}
});
const getInfo = async () => {
const userRes = await getUserInfo();
const user = userRes.data.data.data || {};
forms.nickname = user.nickname;
forms.mobile = user.mobile;
forms.email = user.email;
forms.userExt.emailAlertSwitch = user.userExt?.emailAlertSwitch || false;
if (userRes.data?.data) {
localStorage.setItem('userInfo', JSON.stringify(userRes.data?.data));
useAccountStore().saveAccountInfo({
...userRes.data?.data
});
// }
}
};
const formRef = ref();
const save = () => {
formRef.value.validate(async (isValid, invalidFields) => {
if (isValid) {
loading.value = true;
await userEdit(forms);
loading.value = false;
Message.success('保存成功');
getInfo();
}
});
};
onMounted(() => {
getInfo();
}); });
</script> </script>

View File

@@ -219,7 +219,7 @@ const currentReusltFilter = ref(null);
// 定义 tableKey用于强制刷新表格 // 定义 tableKey用于强制刷新表格
const tableKey = ref(0); const tableKey = ref(0);
const pager = ref({ const pager = ref({
total: 10, total: 0,
pageIndex: 1, pageIndex: 1,
pageSize: 10 pageSize: 10
}); });

View File

@@ -107,7 +107,7 @@
import AdvanceSearch from '@/components/AdvanceSearch/index.vue' import AdvanceSearch from '@/components/AdvanceSearch/index.vue'
import SettingTitle from '@/components/Setting/SettingTitle/index.vue'; import SettingTitle from '@/components/Setting/SettingTitle/index.vue';
import SettingText from '@/components/Setting/SettingText/index.vue'; import SettingText from '@/components/Setting/SettingText/index.vue';
import { ref,reactive, onMounted } from 'vue'; import { ref,reactive, onMounted,watch } from 'vue';
import { getGroupClaList, setGroupClaStatus, deleteGroupCla } from '@/api/cla'; import { getGroupClaList, setGroupClaStatus, deleteGroupCla } from '@/api/cla';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { GModal } from '@/components/Setting/index'; import { GModal } from '@/components/Setting/index';
@@ -180,7 +180,7 @@ const columns = ref([
{ key: 'contributorCountries', label: '贡献者国家/地区分布', visible: false, filterable: false, sortable: false }, { key: 'contributorCountries', label: '贡献者国家/地区分布', visible: false, filterable: false, sortable: false },
{ key: 'contributorOrganizations', label: '贡献者组织/公司分布', visible: false, filterable: false, sortable: false }, { key: 'contributorOrganizations', label: '贡献者组织/公司分布', visible: false, filterable: false, sortable: false },
{ key: 'communityHash', label: '社区hash值', visible: false, filterable: false, sortable: false }, { key: 'communityHash', label: '社区hash值', visible: false, filterable: false, sortable: false },
{ key: 'copyright', label: 'CopyRight', visible: false, filterable: false, sortable: false }, { key: 'copyright', label: 'Copyright', visible: false, filterable: false, sortable: false },
{ key: 'externalVulnerabilitySource', label: '外部漏洞源的软件名称', visible: false, filterable: true, sortable: false }, { key: 'externalVulnerabilitySource', label: '外部漏洞源的软件名称', visible: false, filterable: true, sortable: false },
{ key: 'versionDescription', label: '版本描述', visible: false, filterable: false, sortable: false }, { key: 'versionDescription', label: '版本描述', visible: false, filterable: false, sortable: false },
{ key: 'compatibilityRisk', label: '兼容性风险描述', visible: false, filterable: false, sortable: false }, { key: 'compatibilityRisk', label: '兼容性风险描述', visible: false, filterable: false, sortable: false },
@@ -322,6 +322,18 @@ onMounted(() => {
...query ...query
}; };
}); });
// 监听路由变化,更新 searchWord
watch(
() => route.query.searchWord, // 监听路由的 searchWord 参数
(newSearchWord) => {
if (newSearchWord) {
newFormData.value.searchWord = newSearchWord; // 更新组件的 searchWord
getReleaseList(); // 重新调用接口
}
},
{ immediate: true } // 立即执行一次
);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -5,25 +5,22 @@
<d-row class="mb-3"> <d-row class="mb-3">
<d-col :span="8"> <d-col :span="8">
<span class="card-key width-90">社区名称</span> <span class="card-key width-90">社区名称</span>
<span class="card-val">开发者社区</span> <span class="card-val">{{ infos.communityName }}</span>
</d-col> </d-col>
<d-col :span="8"> <d-col :span="8">
<span class="card-key width-90">官网地址</span> <span class="card-key width-90">官网地址</span>
<span class="card-val">https://www.huaweicloud.com</span> <span class="card-val">{{ infos.communityWebsite }}</span>
</d-col> </d-col>
<d-col :span="8"> <d-col :span="8">
<span class="card-key width-90">联系方式</span> <span class="card-key width-90">联系方式</span>
<span class="card-val">950808-1</span> <span class="card-val">{{ infos.communityContact }}</span>
</d-col> </d-col>
</d-row> </d-row>
<d-row class="mb-3"> <d-row class="mb-3">
<d-col :span="24"> <d-col :span="24">
<div class="flex"> <div class="flex">
<span class="card-key width-90 flex-shrink-0">社区描述</span> <span class="card-key width-90 flex-shrink-0">社区描述</span>
<span class="card-val flex-grow-1" <span class="card-val flex-grow-1">{{ infos.communityDescription }}</span>
>华为开发者社区致力于打造华为开发者专属的官方技术交流平台帮助开发者探索开发实践交流心得经验获悉业界动态解决开发问题汇聚华为云社区华为云领域博
问答视频等精彩内容形成开发者和技术爱好者交流与分享主阵地</span
>
</div> </div>
</d-col> </d-col>
</d-row> </d-row>
@@ -32,14 +29,28 @@
<div class="card-title">贡献者分布</div> <div class="card-title">贡献者分布</div>
<p class="card-desc">有关Pull Request创建者的公司信息和地区分布(使用公共GitHub信息进行分析)</p> <p class="card-desc">有关Pull Request创建者的公司信息和地区分布(使用公共GitHub信息进行分析)</p>
<div class="mt-3"> <div class="mt-3">
<chart-line /> <chart-line ref="chartLine" :companyGraph="infos.companyGraph" :countryGraph="infos.countryGraph" />
</div> </div>
</Card> </Card>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted } from 'vue';
import SBOMDetail from './SBOMDetail.vue';
import { communityInfo } from '@/api/jyh';
import { useRoute } from 'vue-router';
import ChartLine from '@/components/ChartLine/index.vue'; import ChartLine from '@/components/ChartLine/index.vue';
const route = useRoute(); // 获取路由对象
const chartLine = ref();
const infos = ref({});
onMounted(async () => {
const { data } = await communityInfo(Number(route.params.versionId));
infos.value = data?.data?.data || {};
chartLine.value.onInited();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -20,9 +20,13 @@
</d-drawer> </d-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import SBOMDetail from './SBOMDetail.vue'; import SBOMDetail from './SBOMDetail.vue';
import { dependencyTree } from '@/api/jyh';
import { useRoute } from 'vue-router';
const checked = ref(false); const checked = ref(false);
const route = useRoute(); // 获取路由对象
const showDetail = ref(false); const showDetail = ref(false);
const baseTreeTableData1 = ref([ const baseTreeTableData1 = ref([
@@ -84,6 +88,10 @@ const baseTreeTableData1 = ref([
const treeCheckChange = (val, row, selection) => { const treeCheckChange = (val, row, selection) => {
console.log('treeCheckChange', selection); console.log('treeCheckChange', selection);
}; };
onMounted(async () => {
await dependencyTree(Number(route.params.versionId));
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,28 +1,22 @@
<template> <template>
<div class="soft-detail-container"> <div class="soft-detail-container">
<div class="mt-3"> <div class="mt-3">
<d-table class="jyh-table" v-if="tableData.length" :striped="false" :data="tableData" table-layout="auto"> <d-table class="jyh-table" v-if="tableData.length" :striped="false" :data="valLists" table-layout="auto">
<d-column type="index" width="40"></d-column> <d-column type="index" width="40"></d-column>
<d-column <d-column field="vulnId" header="编码" filterable :filter-list="filterList" @filter-change="handleFilterChange">
field="versionName"
header="编码"
filterable
:filter-list="filterList"
@filter-change="handleFilterChange"
>
<template #default="scope"> <template #default="scope">
<a @click="openVulnDetail(scope.row)">{{ scope.row.versionName }}</a> <a @click="openVulnDetail(scope.row)">{{ scope.row.vulnId }}</a>
</template> </template>
</d-column> </d-column>
<d-column <d-column
field="name" field="cweId"
header="CVE ID" header="CVE ID"
filterable filterable
:filter-list="filterList" :filter-list="filterList"
@filter-change="handleFilterChange" @filter-change="handleFilterChange"
></d-column> ></d-column>
<d-column <d-column
field="code" field="cvssScore"
header="CVSS 打分" header="CVSS 打分"
filterable filterable
:filter-list="filterList" :filter-list="filterList"
@@ -40,7 +34,7 @@
</template> </template>
</d-column> </d-column>
<d-column <d-column
field="versionCode" field="severity"
header="漏洞级别" header="漏洞级别"
sortable sortable
:sort-method="sortNameMethod" :sort-method="sortNameMethod"
@@ -49,11 +43,11 @@
@filter-change="handleFilterChange" @filter-change="handleFilterChange"
> >
<template #default="scope"> <template #default="scope">
<a>{{ scope.row.versionCode }}</a> <a>{{ scope.row.severity }}</a>
</template> </template>
</d-column> </d-column>
<d-column <d-column
field="versionCode" field="fixVersion"
header="补丁版本" header="补丁版本"
sortable sortable
:sort-method="sortNameMethod" :sort-method="sortNameMethod"
@@ -62,10 +56,14 @@
@filter-change="handleFilterChange" @filter-change="handleFilterChange"
> >
<template #default="scope"> <template #default="scope">
<a>{{ scope.row.versionCode }}</a> <a>{{ scope.row.fixVersion }}</a>
</template>
</d-column>
<d-column field="publishDate" header="补丁修复时间" fixed-right="0px">
<template #default="scope">
{{ dayjs(scope.row.publishDate).format('YYYY-MM-DD') }}
</template> </template>
</d-column> </d-column>
<d-column field="created" header="补丁修复时间" fixed-right="0px"></d-column>
</d-table> </d-table>
<DataPanel v-else skeleton :card="false" :empty="true"> </DataPanel> <DataPanel v-else skeleton :card="false" :empty="true"> </DataPanel>
@@ -100,25 +98,27 @@
>你确认删除此项{{ item.cla_name }} </span >你确认删除此项{{ item.cla_name }} </span
> >
</GModal> </GModal>
<!-- 漏洞详情 --> <!-- 漏洞详情 -->
<d-drawer v-model="vulnDetailVisable" style="width: auto;"> <d-drawer v-model="vulnDetailVisable" style="width: auto">
<VulnerabilityDetail :softwareId="currentVuln.softwareId" :vulnId="currentVuln.id"></VulnerabilityDetail> <VulnerabilityDetail :softwareId="currentVuln.softwareId" :vulnId="currentVuln.id"></VulnerabilityDetail>
</d-drawer> </d-drawer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import * as dayjs from 'dayjs';
import SettingTitle from '@/components/Setting/SettingTitle/index.vue'; import SettingTitle from '@/components/Setting/SettingTitle/index.vue';
import SettingText from '@/components/Setting/SettingText/index.vue'; import SettingText from '@/components/Setting/SettingText/index.vue';
import { ref, reactive } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import { getGroupClaList, setGroupClaStatus, deleteGroupCla } from '@/api/cla'; import { getGroupClaList, setGroupClaStatus, deleteGroupCla } from '@/api/cla';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { GModal } from '@/components/Setting/index'; import { GModal } from '@/components/Setting/index';
import { reqCatch } from '@/utils/catch'; import { reqCatch } from '@/utils/catch';
import { getOrgInfo } from '@/views/Org/hooks/orgInfo'; import { getOrgInfo } from '@/views/Org/hooks/orgInfo';
import { Message } from 'vue-devui'; import { Message } from 'vue-devui';
import VulnerabilityDetail from '@/views/Jyh/Version/Detail/VulnerabilityDetail.vue' import VulnerabilityDetail from '@/views/Jyh/Version/Detail/VulnerabilityDetail.vue';
import { getVulnList } from '@/api/jyh';
const { namespace } = getOrgInfo(); const { namespace } = getOrgInfo();
const tableData = ref([ const tableData = ref([
@@ -244,15 +244,25 @@ const vulnDetailVisable = ref(false);
const currentVuln = ref(); const currentVuln = ref();
const openVulnDetail = (row) => { const openVulnDetail = (row) => {
vulnDetailVisable.value = true; vulnDetailVisable.value = true;
if(row.softwareId && row.id) { if (row.softwareId && row.id) {
currentVuln.value = row; currentVuln.value = row;
} else { } else {
currentVuln.value = { currentVuln.value = {
softwareId: 47, softwareId: 47,
id: 72 id: 72
} };
} }
} };
const valLists = ref([]);
onMounted(async () => {
const data = await getVulnList({
softwareId: 47,
current: 1,
size: 10
});
valLists.value = data?.data?.data?.data?.records || [];
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">