CN-784: Detection列表样式按新版UI图修改

This commit is contained in:
刘洪洪
2022-11-07 15:25:00 +08:00
parent 32a2359e0d
commit ec98178d45
8 changed files with 263 additions and 68 deletions

View File

@@ -2,12 +2,12 @@
display: flex; display: flex;
.cn-detection__collapse { .cn-detection__collapse {
margin-bottom: 1px;
padding-top: 18px;
width: 24px; width: 24px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: flex-start; align-items: flex-start;
margin-bottom: 1px;
padding-top: 33px;
background-color: #F3F7FA; background-color: #F3F7FA;
span { span {

View File

@@ -28,7 +28,7 @@
.explorer-top-tools { .explorer-top-tools {
display: flex; display: flex;
justify-content: flex-end; justify-content: space-between;
align-items: center; align-items: center;
padding-bottom: 18px; padding-bottom: 18px;

View File

@@ -20,7 +20,8 @@ export default {
entityDetectionStyle () { entityDetectionStyle () {
const route = this.$route.name !== undefined ? this.$route.name : this.$route const route = this.$route.name !== undefined ? this.$route.name : this.$route
if (listScrollPath.indexOf(route.path) > -1) { if (listScrollPath.indexOf(route.path) > -1) {
return 'overflow:auto;background-color: #EFF2F5;' const style = route.path === listScrollPath[0] ? 'overflow:auto;background-color: #EFF2F5;' : 'overflow:auto;'
return style
} else { } else {
return '' return ''
} }

View File

@@ -37,7 +37,7 @@
</div> </div>
<div class="cn-header__nav"> <div class="cn-header__nav">
<i class="cn-icon cn-icon-a-NetworkAnalytics"></i> <i class="cn-icon cn-icon-a-NetworkAnalytics"></i>
<el-breadcrumb class="header__left-breadcrumb" separator=">"> <el-breadcrumb class="header__left-breadcrumb" :separator="route.indexOf('detection') === -1 ? '>' : ''">
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item}`" :title="item" v-for="(item,index) in breadcrumb" :key="item"> <el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item}`" :title="item" v-for="(item,index) in breadcrumb" :key="item">
<template v-if="index===3"> <template v-if="index===3">
<div class="header__left-breadcrumb-item-select"> <div class="header__left-breadcrumb-item-select">
@@ -96,30 +96,30 @@
</template> </template>
<template v-else-if="index===1"> <template v-else-if="index===1">
<span class="route-menu" @click="jump(route,'','',2)" v-if="route.indexOf('detection') === -1">{{item}}</span> <span class="route-menu" @click="jump(route,'','',2)" v-if="route.indexOf('detection') === -1">{{item}}</span>
<div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1"> <!-- <div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1">-->
<el-popover placement="bottom-start" <!-- <el-popover placement="bottom-start"-->
v-if="route.indexOf('detection') > -1" <!-- v-if="route.indexOf('detection') > -1"-->
ref="breadcrumbPopover" <!-- ref="breadcrumbPopover"-->
:show-arrow="false" <!-- :show-arrow="false"-->
:append-to-body="false" <!-- :append-to-body="false"-->
:hide-after="0" <!-- :hide-after="0"-->
:show-after="0" <!-- :show-after="0"-->
popper-class="breadcrumb__popper" <!-- popper-class="breadcrumb__popper"-->
trigger="click"> <!-- trigger="click">-->
<template #reference> <!-- <template #reference>-->
<div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1"> <!-- <div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1">-->
<span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i> <!-- <span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>-->
</div> <!-- </div>-->
</template> <!-- </template>-->
<el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;"> <!-- <el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">-->
<ul class="select-dropdown" id="breadcrumbSelectDropdown2"> <!-- <ul class="select-dropdown" id="breadcrumbSelectDropdown2">-->
<li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)"> <!-- <li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)">-->
<span>{{$t(item.i18n)}}</span> <!-- <span>{{$t(item.i18n)}}</span>-->
</li> <!-- </li>-->
</ul> <!-- </ul>-->
</el-row> <!-- </el-row>-->
</el-popover> <!-- </el-popover>-->
</div> <!-- </div>-->
</template> </template>
<template v-else> <template v-else>
<span>{{item}}</span> <span>{{item}}</span>

View File

@@ -6,6 +6,8 @@
<div class="no-data" v-if="noData">No data</div> <div class="no-data" v-if="noData">No data</div>
<div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow"></div> <div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow"></div>
<detection-row <detection-row
style="margin-bottom: 10px"
class="detection-border"
v-for="(data, index) in listData" v-for="(data, index) in listData"
:detection="data" :detection="data"
:page-type="pageType" :page-type="pageType"

View File

@@ -2,12 +2,19 @@
<div class="cn-detection--list" :style="{zIndex: !isCollapse ? 1 : 'unset'}"> <div class="cn-detection--list" :style="{zIndex: !isCollapse ? 1 : 'unset'}">
<!-- 左侧下拉按钮 --> <!-- 左侧下拉按钮 -->
<div class="cn-detection__collapse"> <div class="cn-detection__collapse">
<span @click="switchCollapse" :class="{'reg-down': !isCollapse}"><i class="cn-icon cn-icon-arrow-right"></i></span> <span @click="switchCollapse" :class="{'reg-down': !isCollapse}">
<i class="cn-icon cn-icon-arrow-right"></i>
</span>
</div> </div>
<div class="cn-detection__case"> <div class="cn-detection__case">
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[detection.eventSecurity]}`"></div> <div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[detection.eventSecurity]}`"></div>
<div class="cn-detection__row"> <div class="cn-detection__row">
<div class="cn-detection__header" v-if="pageType === detectionPageType.securityEvent"> <div class="cn-detection__header" v-if="pageType === detectionPageType.securityEvent">
<span
class="detection-event-severity-color-block"
:style="`background-color: ${eventSeverityColor[detection.eventSeverity]}`">
</span>
<span class="detection-event-severity-block">{{ detection.securityType || '-' }}</span>
<i class="cn-icon cn-icon-attacker" ></i>{{detection.offenderIp || '-'}} <i class="cn-icon cn-icon-attacker" ></i>{{detection.offenderIp || '-'}}
<div v-if="detection.domain" class="domain">{{detection.domain}}</div> <div v-if="detection.domain" class="domain">{{detection.domain}}</div>
<span class="line">-------</span> <span class="line">-------</span>
@@ -31,11 +38,6 @@
<span>{{$t('detections.eventSeverity')}}&nbsp;:&nbsp;&nbsp;</span> <span>{{$t('detections.eventSeverity')}}&nbsp;:&nbsp;&nbsp;</span>
<span>{{detection.eventSeverity || '-'}}</span> <span>{{detection.eventSeverity || '-'}}</span>
</div> </div>
<div class="basic-info__item" v-if="detection.securityType">
<i class="cn-icon cn-icon-event-type"></i>
<span>{{$t('detection.list.securityType')}}&nbsp;:&nbsp;&nbsp;</span>
<span>{{detection.securityType || '-'}}</span>
</div>
<div class="basic-info__item" v-if="detection.eventType"> <div class="basic-info__item" v-if="detection.eventType">
<i class="cn-icon cn-icon-event-type"></i> <i class="cn-icon cn-icon-event-type"></i>
<span>{{$t('detections.eventType')}}&nbsp;:&nbsp;&nbsp;</span> <span>{{$t('detections.eventType')}}&nbsp;:&nbsp;&nbsp;</span>
@@ -176,3 +178,25 @@ export default {
} }
} }
</script> </script>
<style>
.detection-event-severity-color-block {
width: 5px;
height: 20px;
border-radius: 2.5px;
margin-left: -16px;
margin-right: 12px;
}
.detection-event-severity-block {
font-family: NotoSansHans-Medium;
font-size: 12px;
color: #046EC9;
font-weight: 500;
padding: 2px 10px;
background: rgba(56,172,210,0.10);
border: 1px solid #ADC7DB;
box-shadow: 0 2px 0.28571rem 0 rgb(51 51 51 / 2%);
border-radius: 3px;
margin-right: 10px;
}
</style>

View File

@@ -0,0 +1,94 @@
<template>
<div class="npm-tabs">
12345678
<div class="npm-tabs__active-bar"></div>
<el-tabs v-model="currentTab" ref="elTabs" type="border-card" @tab-click="jumpPage">
<el-tab-pane
v-for="(tab,index) in tabs"
:key="tab.i18n"
:name="index"
:disabled="tab.disable">
<template #label>
<div class="npm-tab__label">
<i :class="tab.icon"></i>
<span>{{ $t(tab.i18n) }}</span>
</div>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import chartMixin from '@/views/charts2/chart-mixin'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
export default {
name: 'DetectionTabs',
data () {
return {
leftOffset: 27
}
},
mixins: [chartMixin],
setup (props) {
const tabs = ref([])
if (props.chart) {
tabs.value = [...props.chart]
tabs.value.forEach(item => {
item.disable = false
})
}
const { query } = useRoute()
const tabIndexParam = query.tabIndex
const currentTab = ref(tabIndexParam ? parseInt(tabIndexParam) : 0)
return {
currentTab,
tabs
}
},
watch: {
currentTab (n) {
const { query } = this.$route
const newUrl = urlParamsHandler(window.location.href, query, {
tabIndex: n
})
overwriteUrl(newUrl)
this.$nextTick(() => {
this.handleActiveBar(n)
})
}
},
methods: {
handleActiveBar (index) {
const tabDom = document.getElementById('tab-' + index)
if (tabDom) {
const offsetLeft = tabDom.offsetLeft
const clientWidth = tabDom.clientWidth
const clientLeft = tabDom.clientLeft
const activeBar = document.querySelector('.npm-tabs .npm-tabs__active-bar')
activeBar.style.cssText += `width: ${clientWidth + 2}px; left: ${offsetLeft + this.leftOffset + clientLeft - 1}px;`
}
},
jumpPage (item) {
this.$router.push({
path: this.tabs[item.index].path,
query: {
t: +new Date(),
tabIndex: this.currentTab
}
})
}
},
mounted () {
// setTimeout(() => {
this.$nextTick(() => {
this.handleActiveBar(this.currentTab)
})
// }, 120)
}
}
</script>

View File

@@ -1,37 +1,57 @@
<template> <template>
<div <div class="entity-explorer entity-explorer--show-list">
class="entity-explorer entity-explorer--show-list"
>
<!-- 顶部工具栏在列表页显示 --> <!-- 顶部工具栏在列表页显示 -->
<div class="explorer-top-tools"> <div class="explorer-top-tools">
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" :date-range="timeFilter.dateRangeValue" ref="dateTimeRange" @change="reload"/> <div class="explorer-top-tools-title">{{$t('overall.detections')}}</div>
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/> <div style="display: flex">
<div class="explorer-top-tools-block">
<i class="cn-icon cn-icon-setting detection-icon-setting"></i>
<span>Configure Policies</span>
</div>
<DateTimeRange
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"/>
<TimeRefresh
class="date-time-range"
@change="timeRefreshChange"
:end-time="timeFilter.endTime"/>
</div>
</div> </div>
<div style="width: 100%;padding-bottom: 26px;">
<detection-tabs :time-filter="timeFilter" :chart="tabsData" />
</div>
<!-- 搜索组件 --> <!-- 搜索组件 -->
<detection-search <detection-search
class="detection-border"
ref="search" ref="search"
:page-type="pageType" :page-type="pageType"
@search="search" @search="search"
></detection-search> ></detection-search>
<!-- 内容区 --> <!-- 内容区 -->
<div class="explorer-container" style="height: calc(100% - 20px); flex-direction: column"> <div class="explorer-container" style="height: calc(100% - 20px);flex-direction: column">
<loading :loading="loading"></loading> <loading :loading="loading"></loading>
<template v-if="isEventSeverityNoData"> <template v-if="isEventSeverityNoData">
<div class="no-data detection__event-severity-bar" >No data</div> <div class="no-data detection__event-severity-bar" >No data</div>
</template> </template>
<template v-if="!isEventSeverityNoData"> <template v-if="!isEventSeverityNoData">
<div class="detection__event-severity-bar" :id="`eventSeverityTrendBar${pageType}`"> <div class="detection__event-severity-bar detection-border" :id="`eventSeverityTrendBar${pageType}`">
</div> </div>
</template> </template>
<div style="display: flex; flex-grow: 1; height: 100%;"> <div style="display: flex; flex-grow: 1; height: 100%;">
<detection-filter <detection-filter
class="detection-border"
:filter-data="filterData[pageType]" :filter-data="filterData[pageType]"
:q="q" :q="q"
:time-filter="timeFilter" :time-filter="timeFilter"
></detection-filter> ></detection-filter>
<div class="detection__list"> <div class="detection__list">
<div class="detection__list-statistics"> <div class="detection__list-statistics detection-border">
<div class="statistics__severity"> <div class="statistics__severity">
<div class="chart-header"> <div class="chart-header">
<div class="chart-header__title">{{$t('detection.severity')}}</div> <div class="chart-header__title">{{$t('detection.severity')}}</div>
@@ -81,15 +101,14 @@
></detection-list> ></detection-list>
<div class="entity__pagination" > <div class="entity__pagination" >
<Pagination <Pagination
ref="pagination" ref="pagination"
:page-obj="pageObj" :page-obj="pageObj"
@pageNo='pageNo' @pageNo='pageNo'
@pageSize='pageSize' @pageSize='pageSize'
@size-change="pageSize" @size-change="pageSize"
@prev-click="prev" @prev-click="prev"
@next-click="next" @next-click="next"
> ></Pagination>
</Pagination>
</div> </div>
</div> </div>
</div> </div>
@@ -108,12 +127,13 @@ import { defaultPageSize, detectionPageType } from '@/utils/constants'
import { getNowTime, getSecond, rTime } from '@/utils/date-util' import { getNowTime, getSecond, rTime } from '@/utils/date-util'
import { ref, shallowRef } from 'vue' import { ref, shallowRef } from 'vue'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor, getSeriesIndex } from '@/views/detections/options/detectionOptions' import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor } from '@/views/detections/options/detectionOptions'
import { api, getData } from '@/utils/api' import { api, getData } from '@/utils/api'
import { reverseSortBy, sortBy, extensionEchartY } from '@/utils/tools' import { reverseSortBy, extensionEchartY } from '@/utils/tools'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import DetectionNoData from '@/views/detections/DetectionNoData' // import DetectionNoData from '@/views/detections/DetectionNoData'
import Loading from '@/components/common/Loading' import Loading from '@/components/common/Loading'
import DetectionTabs from '@/views/detections/DetectionTabs'
export default { export default {
name: 'Index', name: 'Index',
@@ -125,10 +145,32 @@ export default {
DetectionFilter, DetectionFilter,
DetectionList, DetectionList,
Pagination, Pagination,
DetectionNoData // DetectionNoData,
DetectionTabs
}, },
data () { data () {
return { return {
tabsData: [
// todo icon名称可能不一致后续改
{
name: 'SecurityEvents',
i18n: 'entities.securityEvents',
path: '/detection/securityEvent',
icon: 'cn-icon cn-icon-SecurityEvent'
},
{
name: 'Regulatory Risk Event',
i18n: 'entities.regulatoryRiskEvents',
path: '/detection/securityEvent',
icon: 'cn-icon cn-icon-RegulatoryRiskEvent'
},
{
name: 'PerformanceEvents',
i18n: 'overall.performanceEvents',
path: '/detection/performanceEvent',
icon: 'cn-icon cn-icon-PerformanceEvent'
}
],
chartInit: [], chartInit: [],
pageObj: { pageObj: {
pageNo: 1, pageNo: 1,
@@ -231,7 +273,6 @@ export default {
isStatisticsCategoryNoData: false, isStatisticsCategoryNoData: false,
isStatisticsActiveAttackNoData: false, isStatisticsActiveAttackNoData: false,
loading: false, loading: false,
oldActiveEntitySearchValue: '' oldActiveEntitySearchValue: ''
} }
}, },
@@ -270,8 +311,10 @@ export default {
const seriesData = [] const seriesData = []
xData.forEach(item => { xData.forEach(item => {
if (dataMap.has(serie.name)) { if (dataMap.has(serie.name)) {
// todo 下面这行注释可解决eslint报红线的问题暂不知道原因后续解决
// eslint-disable-next-line array-callback-return
const hasX = dataMap.get(serie.name).some(function (v) { const hasX = dataMap.get(serie.name).some(function (v) {
if (item == v[0]) { if (item === v[0]) {
seriesData.push(Number(v[1])) seriesData.push(Number(v[1]))
return true return true
} }
@@ -296,7 +339,7 @@ export default {
// this.isEventSeverityNoData = true // this.isEventSeverityNoData = true
} }
}).catch(error => { }).catch(error => {
console.log(error)
}).finally(() => { }).finally(() => {
this.$nextTick(() => { this.$nextTick(() => {
this.loading = false this.loading = false
@@ -329,7 +372,7 @@ export default {
}) })
} }
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initEventTypeData (params) { initEventTypeData (params) {
@@ -357,7 +400,7 @@ export default {
}) })
} }
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initSecurityTypeData (params) { initSecurityTypeData (params) {
@@ -385,7 +428,7 @@ export default {
}) })
} }
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initOffenderIpData (params) { initOffenderIpData (params) {
@@ -419,7 +462,7 @@ export default {
}) })
} }
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
@@ -430,7 +473,7 @@ export default {
this.filterData[this.pageType][2].showMore = showMore this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex this.filterData[this.pageType][2].showIndex = showIndex
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initVictimLocationData (params) { initVictimLocationData (params) {
@@ -440,7 +483,7 @@ export default {
this.filterData[this.pageType][3].showMore = showMore this.filterData[this.pageType][3].showMore = showMore
this.filterData[this.pageType][3].showIndex = showIndex this.filterData[this.pageType][3].showIndex = showIndex
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initOffenderLocationData (params) { initOffenderLocationData (params) {
@@ -450,7 +493,7 @@ export default {
this.filterData[this.pageType][5].showMore = showMore this.filterData[this.pageType][5].showMore = showMore
this.filterData[this.pageType][5].showIndex = showIndex this.filterData[this.pageType][5].showIndex = showIndex
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
initActiveEntity (params) { initActiveEntity (params) {
@@ -510,6 +553,7 @@ export default {
}) })
} }
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
triggerFilterDataValue (array, value) { triggerFilterDataValue (array, value) {
@@ -539,12 +583,12 @@ export default {
getData(api.detection[this.pageType].listBasic, params).then(data => { getData(api.detection[this.pageType].listBasic, params).then(data => {
this.listData = data this.listData = data
}).catch(error => { }).catch(error => {
console.log(error)
}) })
getData(api.detection[this.pageType].listCount, params).then(data => { getData(api.detection[this.pageType].listCount, params).then(data => {
this.pageObj.total = data this.pageObj.total = data
}).catch(error => { }).catch(error => {
console.log(error)
}) })
}, },
timeRefreshChange () { timeRefreshChange () {
@@ -789,3 +833,33 @@ export default {
} }
} }
</script> </script>
<style>
.explorer-top-tools-title {
font-size: 24px;
line-height: 24px;
font-weight: 900;
color: #353636;
}
.explorer-top-tools-block {
font-family: NotoSansHans-Medium;
height: 28px;
line-height: 28px;
font-size: 14px;
color: #353636;
font-weight: 500;
padding: 0 10px;
margin-right: 10px;
border: 1px solid #E0E0E0;
border-radius: 2px;
cursor: pointer;
}
.detection-icon-setting {
margin-right: 10px;
font-size: 14px;
}
.detection-border {
border: 1px solid #E0E0E0;
border-radius: 4px;
}
</style>