CN-299 feat: detection布局
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
@import './views/entityExplorer/entityList/card';
|
@import './views/entityExplorer/entityList/card';
|
||||||
@import './views/entityExplorer/entityList/row';
|
@import './views/entityExplorer/entityList/row';
|
||||||
@import 'views/entityExplorer/entityList/detail-overview';
|
@import 'views/entityExplorer/entityList/detail-overview';
|
||||||
|
@import './views/detections/detections';
|
||||||
@import './views/charts/panel';
|
@import './views/charts/panel';
|
||||||
@import 'views/charts/chartIpOpenPortBar';
|
@import 'views/charts/chartIpOpenPortBar';
|
||||||
@import './views/charts/chartTable';
|
@import './views/charts/chartTable';
|
||||||
|
|||||||
19
src/assets/css/components/views/detections/detections.scss
Normal file
19
src/assets/css/components/views/detections/detections.scss
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
.detection__event-severity-bar {
|
||||||
|
flex: 0 0 175px;
|
||||||
|
background-color: white;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.detection__list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.detection__list-statistics {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 192px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,10 +10,6 @@ const routes = [
|
|||||||
path: '/entityDetail',
|
path: '/entityDetail',
|
||||||
component: () => import('@/views/entityExplorer/EntityDetail')
|
component: () => import('@/views/entityExplorer/EntityDetail')
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/detections',
|
|
||||||
component: () => import('@/views/detections/Index')
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@/components/layout/Home'),
|
component: () => import('@/components/layout/Home'),
|
||||||
@@ -42,6 +38,10 @@ const routes = [
|
|||||||
path: '/entityExplorer',
|
path: '/entityExplorer',
|
||||||
component: () => import('@/views/entityExplorer/EntityExplorer')
|
component: () => import('@/views/entityExplorer/EntityExplorer')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/detections',
|
||||||
|
component: () => import('@/views/detections/Index')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/galaxyProxy',
|
path: '/galaxyProxy',
|
||||||
component: () => import('@/views/settings/GalaxyProxy')
|
component: () => import('@/views/settings/GalaxyProxy')
|
||||||
|
|||||||
11
src/views/detections/DetectionFilter.vue
Normal file
11
src/views/detections/DetectionFilter.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<div class="entity-filter-case" style="background-color: white; height: 1000px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'DetectionFilter'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
76
src/views/detections/DetectionList.vue
Normal file
76
src/views/detections/DetectionList.vue
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<div class="entity-list" id="detectionList">
|
||||||
|
<div class="entity__loading" style="background: #eff2f5;opacity: .6;" v-show="loading">
|
||||||
|
<i class="el-icon-loading"></i>
|
||||||
|
</div>
|
||||||
|
<div class="entity-list__content">
|
||||||
|
<div class="entity-list--list">
|
||||||
|
<div class="no-data" v-if="noData">No data</div>
|
||||||
|
<div v-if="!isCollapse" @click="collapse" class="cn-entity__shadow"></div>
|
||||||
|
<detection-row
|
||||||
|
v-for="(data, index) in listData"
|
||||||
|
:detection="data"
|
||||||
|
:timeFilter="timeFilter"
|
||||||
|
:key="index"
|
||||||
|
:ref="`detectionRow${index}`"
|
||||||
|
:index="index"
|
||||||
|
@switchCollapse="switchCollapse"
|
||||||
|
></detection-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DetectionRow from '@/views/detections/DetectionRow'
|
||||||
|
export default {
|
||||||
|
name: 'DetectionList',
|
||||||
|
components: {
|
||||||
|
DetectionRow
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
listData: Array,
|
||||||
|
from: String,
|
||||||
|
pageObj: Object,
|
||||||
|
loading: Boolean,
|
||||||
|
timeFilter: Object
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showDetail: false,
|
||||||
|
typeName: '',
|
||||||
|
detectionList: [],
|
||||||
|
isCollapse: true,
|
||||||
|
collapseIndex: 0,
|
||||||
|
tableId: 'detectionList',
|
||||||
|
listDataCopy: [],
|
||||||
|
noData: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
switchCollapse (isCollapse, index) {
|
||||||
|
this.isCollapse = isCollapse
|
||||||
|
this.collapseIndex = index
|
||||||
|
},
|
||||||
|
collapse () {
|
||||||
|
this.isCollapse = true
|
||||||
|
this.$refs[`detectionRow${this.collapseIndex}`].collapse()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
listData: {
|
||||||
|
deep: true,
|
||||||
|
handler (n) {
|
||||||
|
if (!n || n.length === 0) {
|
||||||
|
this.timeout = setTimeout(() => {
|
||||||
|
this.noData = true
|
||||||
|
}, 500)
|
||||||
|
} else {
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
this.noData = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
9
src/views/detections/DetectionOverview.vue
Normal file
9
src/views/detections/DetectionOverview.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'DetectionOverview'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
75
src/views/detections/DetectionRow.vue
Normal file
75
src/views/detections/DetectionRow.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cn-entity--list" :style="{zIndex: !isCollapse ? 1 : 'unset'}">
|
||||||
|
<!-- 左侧下拉按钮 -->
|
||||||
|
<div class="cn-entity__collapse">
|
||||||
|
<span @click="switchCollapse" :class="{'reg-down': !isCollapse}"><i class="cn-icon cn-icon-arrow-right"></i></span>
|
||||||
|
</div>
|
||||||
|
<div class="cn-entity__case">
|
||||||
|
<div class="cn-entity__icon"><i class="el-icon-search"></i></div>
|
||||||
|
<div class="cn-entity__row">
|
||||||
|
<div class="cn-entity__header">3.4.5.6</div>
|
||||||
|
<div class="cn-entity__body">
|
||||||
|
<div class="body__basic-info">
|
||||||
|
<div class="basic-info">
|
||||||
|
<div class="basic-info__item">
|
||||||
|
<i class="cn-icon cn-icon-country"></i>
|
||||||
|
<span>{{$t('overall.country')}} : </span>
|
||||||
|
<span>hehe</span>
|
||||||
|
</div>
|
||||||
|
<div class="basic-info__item">
|
||||||
|
<i class="cn-icon cn-icon-position"></i>
|
||||||
|
<span>{{$t('overall.region')}} : </span>
|
||||||
|
<span>xixi</span>
|
||||||
|
</div>
|
||||||
|
<div class="basic-info__item">
|
||||||
|
<i class="cn-icon cn-icon-cloud"></i>
|
||||||
|
<span>{{$t('entities.asn')}} : </span>
|
||||||
|
<span>heihei</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-collapse-transition>
|
||||||
|
<div class="cn-entity__detail-overview" v-if="!isCollapse">
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<detection-overview
|
||||||
|
:entity="entityData"
|
||||||
|
:time-filter="timeFilter"
|
||||||
|
></detection-overview>
|
||||||
|
</div>
|
||||||
|
</el-collapse-transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DetectionOverview from '@/views/detections/DetectionOverview'
|
||||||
|
export default {
|
||||||
|
name: 'DetectionRow',
|
||||||
|
components: {
|
||||||
|
DetectionOverview
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
index: Number,
|
||||||
|
timeFilter: Object
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
entityData: [],
|
||||||
|
isCollapse: true // 是否是折叠状态
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* 切换折叠状态 */
|
||||||
|
switchCollapse () {
|
||||||
|
this.isCollapse = !this.isCollapse
|
||||||
|
this.$emit('switchCollapse', this.isCollapse, this.index)
|
||||||
|
},
|
||||||
|
/* 设为折叠状态 */
|
||||||
|
collapse () {
|
||||||
|
this.isCollapse = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
42
src/views/detections/DetectionSearch.vue
Normal file
42
src/views/detections/DetectionSearch.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="explorer-search">
|
||||||
|
<div class="explorer-search__input-case explorer-search__input-case--question-mark-in-line">
|
||||||
|
<div class="explorer-search__input">
|
||||||
|
<advanced-search
|
||||||
|
ref="search"
|
||||||
|
:column-list="columnList"
|
||||||
|
:operator-list="operatorList"
|
||||||
|
:connection-list="connectionList"
|
||||||
|
:full-text="true"
|
||||||
|
class="advanced-search--show-list"
|
||||||
|
@search="search"
|
||||||
|
></advanced-search>
|
||||||
|
</div>
|
||||||
|
<div class="search-symbol-inline">
|
||||||
|
<i class="cn-icon cn-icon-help"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import AdvancedSearch from '@/components/advancedSearch/Index'
|
||||||
|
export default {
|
||||||
|
name: 'DetectionSearch',
|
||||||
|
components: {
|
||||||
|
AdvancedSearch
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
columnList: [],
|
||||||
|
operatorList: [],
|
||||||
|
connectionList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
search () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,13 +1,148 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div
|
||||||
|
class="entity-explorer entity-explorer--show-list"
|
||||||
|
>
|
||||||
|
<!-- 顶部工具栏,在列表页显示 -->
|
||||||
|
<div class="explorer-top-tools">
|
||||||
|
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
||||||
|
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
||||||
|
</div>
|
||||||
|
<!-- 搜索组件 -->
|
||||||
|
<detection-search
|
||||||
|
ref="search"
|
||||||
|
@search="search"
|
||||||
|
></detection-search>
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<div class="explorer-container" style="height: calc(100% - 20px); flex-direction: column">
|
||||||
|
<div class="detection__event-severity-bar"></div>
|
||||||
|
<div style="display: flex; height: 100%;">
|
||||||
|
<detection-filter
|
||||||
|
:filter-data="filterData"
|
||||||
|
:q="q"
|
||||||
|
:time-filter="timeFilter"
|
||||||
|
@filter="filter"
|
||||||
|
></detection-filter>
|
||||||
|
<div class="detection__list">
|
||||||
|
<div class="detection__list-statistics"></div>
|
||||||
|
<detection-list
|
||||||
|
:list-data="listData"
|
||||||
|
:pageObj="pageObj"
|
||||||
|
:time-filter="timeFilter"
|
||||||
|
@pageSize="pageSize"
|
||||||
|
@pageNo="pageNo"
|
||||||
|
:loading="listLoading"
|
||||||
|
></detection-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entity__pagination" style="position: absolute; bottom: 0; width: 100%;">
|
||||||
|
<Pagination
|
||||||
|
ref="pagination"
|
||||||
|
:page-obj="pageObj"
|
||||||
|
@pageNo='pageNo'
|
||||||
|
@pageSize='pageSize'
|
||||||
|
@size-change="pageSize"
|
||||||
|
@prev-click="prev"
|
||||||
|
@next-click="next"
|
||||||
|
>
|
||||||
|
</Pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import DetectionSearch from '@/views/detections/DetectionSearch'
|
||||||
|
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
|
||||||
|
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
|
||||||
|
import DetectionFilter from '@/views/detections/DetectionFilter'
|
||||||
|
import DetectionList from '@/views/detections/DetectionList'
|
||||||
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
import { defaultPageSize } from '@/utils/constants'
|
||||||
|
import { getNowTime } from '@/utils/date-util'
|
||||||
|
import { ref } from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'Index'
|
name: 'Index',
|
||||||
|
components: {
|
||||||
|
DetectionSearch,
|
||||||
|
DateTimeRange,
|
||||||
|
TimeRefresh,
|
||||||
|
DetectionFilter,
|
||||||
|
DetectionList,
|
||||||
|
Pagination
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
pageObj: {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: defaultPageSize,
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
|
q: '',
|
||||||
|
filterData: [],
|
||||||
|
listData: [],
|
||||||
|
listLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
timeRefreshChange () {
|
||||||
|
if (!this.$refs.dateTimeRange.isCustom) {
|
||||||
|
const value = this.timeFilter.dateRangeValue
|
||||||
|
this.$refs.dateTimeRange.quickChange(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reload (s, e, v) {
|
||||||
|
this.dateTimeRangeChange(s, e, v)
|
||||||
|
},
|
||||||
|
// methods
|
||||||
|
dateTimeRangeChange (s, e, v) {
|
||||||
|
this.timeFilter = { startTime: s, endTime: e, dateRangeValue: v }
|
||||||
|
},
|
||||||
|
search () {
|
||||||
|
|
||||||
|
},
|
||||||
|
filter () {
|
||||||
|
|
||||||
|
},
|
||||||
|
pageSize (val) {
|
||||||
|
this.pageObj.pageSize = val
|
||||||
|
this.search(this.metaList, this.q)
|
||||||
|
},
|
||||||
|
pageNo (val) {
|
||||||
|
this.pageObj.pageNo = val
|
||||||
|
this.search(this.metaList, this.q)
|
||||||
|
},
|
||||||
|
// 点击上一页箭头
|
||||||
|
prev () {
|
||||||
|
this.scrollbarToTop()
|
||||||
|
},
|
||||||
|
// 点击下一页箭头
|
||||||
|
next () {
|
||||||
|
this.scrollbarToTop()
|
||||||
|
},
|
||||||
|
// currentPage 改变时会触发
|
||||||
|
current (val) {
|
||||||
|
this.$emit('pageNo', val)
|
||||||
|
this.scrollbarToTop()
|
||||||
|
},
|
||||||
|
scrollbarToTop () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const wraps = document.querySelector('#detectionList')
|
||||||
|
wraps.scrollTop = 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
timeFilter (n) {
|
||||||
|
this.search(this.metaList, this.q)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const dateRangeValue = 60
|
||||||
|
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||||
|
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||||
|
return {
|
||||||
|
timeFilter
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
></entity-list>
|
></entity-list>
|
||||||
</div>
|
</div>
|
||||||
<div class="entity__pagination" style="position: absolute; bottom: 0; width: 100%;">
|
<div class="entity__pagination" style="position: absolute; bottom: 0; width: 100%;">
|
||||||
<pagination
|
<Pagination
|
||||||
ref="pagination"
|
ref="pagination"
|
||||||
:page-obj="pageObj"
|
:page-obj="pageObj"
|
||||||
@pageNo='pageNo'
|
@pageNo='pageNo'
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
@prev-click="prev"
|
@prev-click="prev"
|
||||||
@next-click="next"
|
@next-click="next"
|
||||||
>
|
>
|
||||||
</pagination>
|
</Pagination>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="explorer-foot" v-else>
|
<div class="explorer-foot" v-else>
|
||||||
@@ -126,7 +126,7 @@ import { get } from '@/utils/http'
|
|||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import pagination from '@/components/common/Pagination'
|
import Pagination from '@/components/common/Pagination'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'entity-explorer',
|
name: 'entity-explorer',
|
||||||
@@ -136,7 +136,7 @@ export default {
|
|||||||
TimeRefresh,
|
TimeRefresh,
|
||||||
EntityFilter,
|
EntityFilter,
|
||||||
EntityList,
|
EntityList,
|
||||||
pagination: pagination
|
Pagination
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -155,7 +155,6 @@ export default {
|
|||||||
entityIpNew: '-',
|
entityIpNew: '-',
|
||||||
entityIpActive: '-',
|
entityIpActive: '-',
|
||||||
|
|
||||||
showFilter: ['ip', 'app', 'domain'], // ip,domain,app
|
|
||||||
pageObj: {
|
pageObj: {
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: defaultPageSize,
|
pageSize: defaultPageSize,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
import AdvancedSearch from '@/components/advancedSearch/Index'
|
import AdvancedSearch from '@/components/advancedSearch/Index'
|
||||||
import { columnType } from '@/components/advancedSearch/meta/meta'
|
import { columnType } from '@/components/advancedSearch/meta/meta'
|
||||||
import SqlParser from '@/components/advancedSearch/meta/sql-parser'
|
import SqlParser from '@/components/advancedSearch/meta/sql-parser'
|
||||||
import {storageKey} from "@/utils/constants";
|
import { storageKey } from '@/utils/constants'
|
||||||
export default {
|
export default {
|
||||||
name: 'CnSearch',
|
name: 'CnSearch',
|
||||||
components: {
|
components: {
|
||||||
|
|||||||
Reference in New Issue
Block a user