CN-1458 fix: detection事件列表的筛选功能与实体的统一

This commit is contained in:
刘洪洪
2023-11-10 14:11:46 +08:00
parent de698f0a71
commit bb2a7676e6
6 changed files with 218 additions and 335 deletions

View File

@@ -2,164 +2,120 @@
display: flex;
flex-direction: column;
width: 280px;
padding: 10px;
margin-right: 10px;
background-color: white;
margin-right: 20px;
overflow: auto;
z-index: 1;
border: 1px solid rgba(226, 229, 236, 1) !important;
border-radius: 4px !important;
.detection-filter {
display: flex;
flex-direction: column;
margin-bottom: 10px;
.filter__header {
display: flex;
flex: 0 0 32px;
align-items: center;
padding-left: 10px;
.filter-case__header {
padding-left: 8px;
height: 36px;
line-height: 36px;
color: #666;
//background-color: #F3F7FA;
cursor: pointer;
span {
font-size: 14px;
padding-left: 6px;
}
i {
font-size: 12px;
transition: all linear .1s;
transform: rotate(0) translate(0, 2px);
}
i.arrow-rotate {
transform: rotate(90deg) translate(2px, 3px);
}
.new-detection-filter-header-title {
font-size: 14px;
color: #353636;
font-weight: 600;
}
.new-detection-filter-icon {
margin-left: 8px;
margin-bottom: 2px;
font-weight: bold !important;
}
}
.filter__body {
padding: 5px 0 0 15px;
.el-checkbox-group {
display: flex;
flex-direction: column;
.el-checkbox {
display: flex;
align-items: center;
padding: 5px 0;
margin-right: 5px;
.el-checkbox__label {
width: 100%;
}
.filter__checkbox-label {
display: flex;
justify-content: space-between;
align-items: center;
.severity-color-block {
width: 4px;
height: 15px;
border-radius: 2px;
}
}
&:last-of-type {
padding-bottom: 0;
}
}
}
}
}
.new-detection-filter-title {
display: flex;
flex: 0 0 32px;
align-items: center;
padding-left: 27px;
background-color: #EFF2F5;
cursor: pointer;
font-size: 14px;
color: #353636;
font-weight: 600;
margin: -10px;
margin-bottom: 10px;
}
}
.new-detection-filter-title {
height: 32px;
line-height: 32px;
background: #F7F7F7;
padding: 0 20px;
box-shadow: 0 1px 0 0 rgba(226,229,236,1);
border-radius: 4px 4px 0 0;
}
.new-detection-filter-content {
padding: 20px;
.new-filter-content-title {
font-family: NotoSansHans-Medium;
.filter__header {
height: 46px;
line-height: 46px;
margin: 0 20px;
font-size: 14px;
line-height: 14px;
margin-bottom: 10px;
color: #353636;
font-weight: 500;
}
.new-filter-content-content {
.filter__body {
width: calc(100% - 30px);
margin: 0 10px 0 20px;
max-height: 265px;
overflow-y: scroll;
overflow-x: hidden;
.filter__body-item {
height: 26px;
line-height: 26px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
cursor: pointer;
.new-filter-content-checkbox {
line-height: 16px;
margin-bottom: 10px;
font-family: NotoSansSChineseRegular;
.filter__body-item-left {
display: flex;
align-items: center;
font-size: 14px;
color: #353636;
font-weight: 400;
.el-checkbox__inner {
width: 16px !important;
height: 16px !important;
text-align: center !important;
line-height: 16px !important;
.filter__body-item-left-index {
width: 16px;
height: 16px;
text-align: center;
background: #EFF2F5;
border-radius: 2px;
margin-right: 6px;
font-family: NotoSansHans-Black;
font-size: 9px;
color: #96A2B0;
font-weight: 900;
display: flex;
align-items: center;
justify-content: center;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
border-color: #38ACD2;
background: #38ACD2;
border-radius: 2px;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner:before {
background: #FFFFFF;
border-radius: 1px;
}
.el-checkbox__input.is-checked {
.el-checkbox__inner {
border-color: #38ACD2;
background: #38ACD2;
border-radius: 2px;
}
}
.el-checkbox__input.is-focus {
.el-checkbox__inner {
border-color: #38ACD2;
}
}
.el-checkbox__label {
.filter__body-item-left-label {
max-width: 180px;
font-family: NotoSansSChineseRegular;
font-size: 14px;
color: #353636;
font-weight: 400;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.filter__body-item-right {
flex-shrink: 0;
font-family: NotoSansSChineseRegular;
font-size: 12px;
color: #717171;
font-weight: 400;
margin-right: 10px;
}
}
}
}
.filter-country-flag {
width: 18px;
height: 12px;
margin-right: 6px;
border: 1px solid #E8E8E8;
}
.filter-show-more, .filter-no-show-more {
cursor: pointer;
height: 26px;
line-height: 26px;
margin-left: 20px;
color: #046ECA;
user-select: none; // 禁止文本选中
font-size: 12px;
}
.filter-no-show-more {
cursor: not-allowed;
color: rgba(16, 16, 16, 0.3);
}
.filter-hr {
width: calc(100% - 40px);
margin-left: 20px;
margin-top: 6px;
height: 1px;
background: #EFF2F5;
//background: #000;
}

View File

@@ -635,6 +635,9 @@ export default {
let { q } = this.$route.query
if (q && !this.convertMetaList) {
const parser = new Parser(this.columnList)
if (q.indexOf('+') > -1) {
q = q.replace('+', '')
}
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
q = decodeURI(q)
} else {

View File

@@ -234,6 +234,9 @@ export default {
toRaw(this.codeMirror).setValue(this.str)
}
if (q) {
if (q.indexOf('+') > -1) {
q = q.replace('+', '')
}
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
q = decodeURI(q)
} else {

View File

@@ -1,31 +1,36 @@
<template>
<div class="detection-filter-case">
<div class="new-detection-filter-title">{{$t('detections.filters')}}</div>
<div class="filter-case__header">{{$t('detections.filters')}}</div>
<div class="no-data" v-if="isNoData">{{ $t('npm.noData') }}</div>
<template v-for="(filter, index) in filterData" :key="index">
<div class="detection-filter" v-show="filter.data.length > 0">
<div class="filter__header" @click="filter.collapse = !filter.collapse">
<span class="new-detection-filter-header-title">{{filter.title}}</span>
<i class="el-icon-arrow-right new-detection-filter-icon" :class="{ 'arrow-rotate': !filter.collapse }"></i>
<div class="filter__header">{{filter.title}}</div>
<div class="filter__body" style="position: relative">
<loading :loading="loadingLeft" style="top: -5px;"></loading>
<div class="filter__body-item"
v-for="(data, i) in filter.data.slice(0, filter.showIndex)"
:key="i"
@click="clickFilterItem(data.label, filter.column, index)">
<div class="filter__body-item-left">
<div class="filter__body-item-left-index">{{ i+1 }}</div>
<div class="filter__body-item-left-label">
<el-tooltip :content="data.label" placement="top" effect="light" :disabled="disabledLabel">
<span @mouseenter="handleMouse(`filter${index}${i}`)" :id="`filter${index}${i}`">
<span>{{ data.label }}</span>
</span>
</el-tooltip>
</div>
<el-collapse-transition>
<div class="filter__body" v-show="!filter.collapse">
<el-checkbox-group v-model="filter.value">
<template v-for="(d, i) in filter.data" :key="i">
<el-checkbox :label="d.value" v-if="!filter.showIndex || filter.showIndex >= i">
<div class="filter__checkbox-label">
<div style="display: flex">
<span class="severity-color-block" v-if="filter.column === 'eventSeverity'" :style="`background-color: ${eventSeverityColor[d.value]}`"></span>
<span :style="filter.column === 'eventSeverity' ? 'padding-left: 10px' : ''">{{d.label}}</span>
</div>
<div v-if="d.count || d.count === 0">{{d.count}}</div>
<div class="filter__body-item-right">{{ data.count }}</div>
</div>
</el-checkbox>
</template>
</el-checkbox-group>
<div class="filter__more" v-if="filter.showMore" @click="showMore(filter)">{{$t('overall.showMore')}}</div>
</div>
</el-collapse-transition>
<div v-show="filter.showMore" @click="showMore(filter)"
:class="filter.showDisabled? 'filter-no-show-more' : 'filter-show-more'">
{{ $t('overall.showMore') }}
</div>
<div class="filter-hr"></div>
</div>
</template>
</div>
@@ -42,13 +47,36 @@ export default {
},
data () {
return {
eventSeverityColor
eventSeverityColor,
disabledLabel: true
}
},
methods: {
showMore (filter) {
filter.showIndex && (filter.showIndex += 10)
filter.showIndex >= (filter.data.length - 1) && (filter.showMore = false)
filter.showIndex && (filter.showIndex += 5)
filter.showIndex >= (filter.data.length - 1) && (filter.showDisabled = true)
},
clickFilterItem (name, data, index) {
if (index === 0) {
let status = 0
if (name === this.$t('detections.active')) {
status = '0'
} else if (name === this.$t('detections.ended')) {
status = '1'
}
this.$emit('filter', status, data)
} else {
this.$emit('filter', name, data)
}
},
handleMouse (id) {
const dom = document.getElementById(id)
if (dom) {
const width = document.getElementById(id).offsetWidth
this.disabledLabel = width < 180
} else {
this.disabledLabel = true
}
}
},
computed: {

View File

@@ -125,67 +125,8 @@ export default {
search ({ q, metaList }) {
this.$emit('search', { q, metaList })
},
changeParams (params) { // params: { column: columnName, oldValue: [...], newValue: [...] }
// 向下传递时需要再转换一次param格式为[{column, operator, value}, ...]
if (params.oldValue.length === 0 && params.newValue.length === 1) {
// 1.参数值数量从0到1直接addParams
const p = {
column: params.column,
operator: '=',
value: params.newValue
}
this.$refs.search.addParams([p])
} else if (params.oldValue.length === 1 && params.newValue.length === 0) {
// 2.参数值数量从1到0直接removeParams
const p = {
column: params.column,
operator: '=',
value: params.oldValue
}
this.$refs.search.removeParams([p])
} else if (params.oldValue.length === 2 && params.newValue.length === 1) {
// 3.参数值数量从多到1operator由'in'改为'='
const oldParam = {
column: params.column,
operator: 'IN',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: '=',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
} else if (params.oldValue.length === 1 && params.newValue.length === 2) {
// 4.参数值数量从1到多, operator由'='改为'in'
const oldParam = {
column: params.column,
operator: '=',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: 'IN',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
} else {
// 5.参数值数量从多到多加1或者减1
const oldParam = {
column: params.column,
operator: 'IN',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: 'IN',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
}
this.$nextTick(() => {
this.emitter.emit('advanced-search')
})
changeParams (params) {
this.$refs.search.addParams(params)
}
}
}

View File

@@ -48,6 +48,7 @@
:filter-data="filterData[pageType]"
:q="q"
:time-filter="timeFilter"
@filter="getFilter"
></detection-filter>
<div class="detection__list">
@@ -189,6 +190,7 @@ export default {
topColumn: 'status',
collapse: false,
value: [], // value之间是or的关系
showMore: false,
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
},
{
@@ -197,6 +199,7 @@ export default {
topColumn: 'severity',
collapse: false,
value: [], // value之间是or的关系
showMore: false,
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
},
{
@@ -205,6 +208,9 @@ export default {
topColumn: 'event_type',
collapse: false,
value: [],
showMore: true,
showDisabled: true,
showIndex: 5, // index作为showMore分割从1开始而非0
data: [] // 从接口动态获取
},
{
@@ -214,43 +220,21 @@ export default {
collapse: false,
value: [],
showMore: true,
showIndex: 9,
showDisabled: true,
showIndex: 5,
data: [] // 从接口动态获取
},
// {
// title: this.$t('detections.victimLocation'),
// column: 'victimLocationCountry',
// collapse: false,
// value: [],
// showMore: false,
// showIndex: 9,
// data: [
// {
// label: 'China',
// value: 'china',
// count: 50
// }
// ] // 从接口动态获取
// },
{
title: this.$t('detections.offenderIp'),
column: 'offenderIP',
topColumn: 'offender_ip',
collapse: false,
value: [],
showMore: false,
showIndex: 9,
showMore: true,
showDisabled: true,
showIndex: 5,
data: [] // 从接口动态获取
}
// {
// title: this.$t('detections.offenderLocation'),
// column: 'offenderLocationCountry',
// collapse: false,
// value: [],
// showMore: false,
// showIndex: 9,
// data: [] // 从接口动态获取
// }
],
performanceEvent: [
{
@@ -431,6 +415,11 @@ export default {
value: r.eventType,
count: r.count
}))
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][2].data)
this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex
this.filterData[this.pageType][2].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
let detectionChart = echarts.getInstanceByDom(chartDom)
if (detectionChart) {
@@ -453,6 +442,9 @@ export default {
}).catch(e => {
console.error(e)
this.filterData[this.pageType][2].data = []
this.filterData[this.pageType][2].showMore = false
this.filterData[this.pageType][2].showIndex = 5
this.filterData[this.pageType][2].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -468,6 +460,10 @@ export default {
count: r.count
}))
this.isCheckFilterByQ(params, 2)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][2].data)
this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex
this.filterData[this.pageType][2].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
let detectionChart = echarts.getInstanceByDom(chartDom)
if (detectionChart) {
@@ -493,6 +489,9 @@ export default {
}).catch(e => {
console.error(e)
this.filterData[this.pageType][2].data = []
this.filterData[this.pageType][2].showMore = false
this.filterData[this.pageType][2].showIndex = 5
this.filterData[this.pageType][2].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -508,9 +507,10 @@ export default {
count: r.count
}))
this.isCheckFilterByQ(params, 4)
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][4].data)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][4].data)
this.filterData[this.pageType][4].showMore = showMore
this.filterData[this.pageType][4].showIndex = showIndex
this.filterData[this.pageType][4].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionActiveAttacker${this.pageType}`)
let detectionChart = echarts.getInstanceByDom(chartDom)
@@ -537,7 +537,8 @@ export default {
console.error(e)
this.filterData[this.pageType][4].data = []
this.filterData[this.pageType][4].showMore = false
this.filterData[this.pageType][4].showIndex = 9
this.filterData[this.pageType][4].showIndex = 5
this.filterData[this.pageType][4].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -547,14 +548,16 @@ export default {
const data = res.data.data.result
this.filterData[this.pageType][3].data = data.map(r => ({ label: r.victimIp, value: r.victimIp, count: r.count }))
this.isCheckFilterByQ(params, 3)
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][3].data)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][3].data)
this.filterData[this.pageType][3].showMore = showMore
this.filterData[this.pageType][3].showIndex = showIndex
this.filterData[this.pageType][3].showDisabled = showDisabled
}).catch(e => {
console.error(e)
this.filterData[this.pageType][3].data = []
this.filterData[this.pageType][3].showMore = false
this.filterData[this.pageType][3].showIndex = 9
this.filterData[this.pageType][3].showIndex = 5
this.filterData[this.pageType][3].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -635,8 +638,9 @@ export default {
},
computeFilterPage (data) {
return {
showMore: data.length > 10,
showIndex: 9
showMore: data.length > 0,
showDisabled: data.length <= 5,
showIndex: 5
}
},
queryList (q) {
@@ -835,6 +839,26 @@ export default {
this.filterData[this.pageType][index].value = []
this.filterData[this.pageType][index].flag = true
}
},
getFilter (name, topColumn) {
if (topColumn === 'tag') {
const params = {
column: topColumn,
operator: 'has',
value: name
}
this.$refs.search.changeParams([params])
} else {
const params = {
column: topColumn,
operator: '=',
value: name
}
this.$refs.search.changeParams([params])
}
this.$nextTick(() => {
this.emitter.emit('advanced-search')
})
}
},
mounted () {
@@ -927,78 +951,6 @@ export default {
},
timeFilter () {
this.search(this.metaList, this.q)
},
'filterData.securityEvent.0.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[0].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[0].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[0].flag = false
}
}
},
'filterData.securityEvent.1.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[1].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[1].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[1].flag = false
}
}
},
'filterData.securityEvent.2.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[2].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[2].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[2].flag = false
}
}
},
'filterData.securityEvent.3.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[3].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[3].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[3].flag = false
}
}
},
'filterData.securityEvent.4.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[4].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[4].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[4].flag = false
}
}
},
'filterData.securityEvent.5.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[5].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[5].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[5].flag = false
}
}
},
'filterData.performanceEvent.0.value': {
deep: true,
handler (n, o) {
this.$refs.search.changeParams({ column: this.filterData.performanceEvent[0].column, oldValue: o, newValue: n })
}
},
'filterData.performanceEvent.1.value': {
deep: true,
handler (n, o) {
this.$refs.search.changeParams({ column: this.filterData.performanceEvent[1].column, oldValue: o, newValue: n })
}
}
},
beforeUnmount () {