CN-1173 fix: 检测功能UI开发与接口对接

This commit is contained in:
刘洪洪
2023-10-16 17:53:46 +08:00
parent 85db8cd745
commit 0e82bebaac
19 changed files with 725 additions and 437 deletions

View File

@@ -208,6 +208,15 @@
font-weight: 500;
padding: 0 14px;
}
.btn1 {
margin-right: 10px;
.el-button {
background: #F5F6F7;
border: 1px solid rgba(215,215,215,1);
color: #353636;
}
}
}
.form-setting__btn1 {

View File

@@ -15,7 +15,7 @@
background-color: rgba(0, 0, 0, 0.16) !important;
}
.detection-drawer-title, .basic-function-value, basic-description-value {
.detection-drawer-title, .basic-function-value, basic-description-value, .drawer-trigger-minutes {
font-family: NotoSansSChineseRegular;
font-size: 14px;
color: #717171;
@@ -58,6 +58,10 @@
color: #046ECA;
}
.drawer-trigger-minutes {
color: #353636;
}
.detection-drawer-collapse {
background: #FFFFFF;
border: 1px solid rgba(226, 229, 236, 1);

View File

@@ -18,7 +18,7 @@
</div>
</div>
<div class="block-mode">
<div class="block-mode" style="cursor: no-drop;">
<!--todo 图标没有后期换-->
<div class="block-mode-left">
<i class="cn-icon cn-icon-setting2 block-mode-icon"></i>
@@ -29,40 +29,44 @@
<div class="block-mode-content">
Aggregate query results to detect when number of matches exceeds threshold.
</div>
<div :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'"
@click="selectMode(detectionRuleType.threshold)">select
<!--todo 当前版本暂时不可选择-->
<div style="cursor: no-drop;" :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'"
>select
</div>
<!-- <div :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'"-->
<!-- @click="selectMode(detectionRuleType.threshold)">select-->
<!-- </div>-->
</div>
</div>
</div>
<!--category-->
<el-form ref="form" :model="settingObj" label-position="top" :rules="rules">
<el-form-item label="Category" prop="category" class="form-setting__block margin-b-20">
<el-select v-model="settingObj.category" class="form-setting__select" placeholder=" " size="mini" @change="changeEditFlag">
<el-form-item :label="$t('overall.category')" prop="category" class="form-setting__block margin-b-20">
<el-select :disabled="settingObj.ruleId" v-model="settingObj.category" class="form-setting__select" placeholder=" " size="mini" @change="changeEditFlag">
<el-option
v-for="item in categoryList"
:key="item.value"
:label="item.label"
:value="item.value"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<!--type-->
<el-form-item label="Type" prop="eventType" class="form-setting__block margin-b-20">
<el-form-item :label="$t('overall.type')" prop="eventType" class="form-setting__block margin-b-20">
<el-select v-model="settingObj.eventType" placeholder=" " size="mini" class="form-setting__select" @change="changeEditFlag">
<el-option
v-for="item in typeList"
:key="item.value"
:label="item.label"
:value="item.value"
v-for="item in eventTypeList"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<!--name-->
<el-form-item label="Name" prop="name" class="form-setting__block margin-b-20">
<el-form-item :label="$t('overall.name')" prop="name" class="form-setting__block margin-b-20">
<el-input
maxlength="64"
show-word-limit
@@ -74,7 +78,7 @@
<!--Description-->
<div class="form-setting__block margin-b-20">
<div class="block-title">Description</div>
<div class="block-title">{{ $t('config.dataSet.description') }}</div>
<el-input
maxlength="255"
show-word-limit
@@ -87,7 +91,7 @@
</el-form>
<div class="form-setting__block margin-b-20">
<div class="block-title">Policy Status</div>
<div class="block-title">{{ $t('detection.create.policyStatus') }}</div>
<el-switch
v-model="settingObj.status"
@change="changeEditFlag"
@@ -95,11 +99,11 @@
inactive-color="#C0CEDB"
:active-value="1"
:inactive-value="0"
:active-text="switchStatus(settingObj.status)"/>
:active-text="$t(switchStatus(settingObj.status))"/>
</div>
<div class="form-setting__btn">
<el-button @click="onContinue">Continue</el-button>
<el-button @click="onContinue">{{ $t('detection.create.continue') }}</el-button>
</div>
</div>
</template>
@@ -107,18 +111,24 @@
<script>
import { detectionRuleType } from '@/utils/constants'
import { switchStatus } from '@/utils/tools'
import axios from 'axios'
import { detectionUnitList } from '@/utils/static-data'
import axios from '_axios@0.21.4@axios'
import { api } from '@/utils/api'
export default {
name: 'GeneralSettings',
props: {
editObj: {
type: Object
}
},
data () {
return {
detectionRuleType,
categoryList: [],
typeList: [],
eventTypeList: [],
settingObj: {
ruleType: detectionRuleType.threshold,
ruleType: detectionRuleType.indicator,
category: '',
eventType: '',
name: '',
@@ -152,20 +162,46 @@ export default {
}
}
},
watch: {
editObj (newVal) {
if (newVal.ruleId) {
this.settingObj = JSON.parse(JSON.stringify({ ...newVal }))
this.settingObj.editFlag = false
this.settingObj.saveFlag = true
}
}
},
mounted () {
this.initData()
},
methods: {
switchStatus,
initData () {
axios.get(api.detection.statistics, { params: { pageSize: -1 } }).then(response => {
this.categoryList = detectionUnitList.categoryList || []
this.eventTypeList = detectionUnitList.eventTypeList || []
axios.get(api.detection.statistics).then(response => {
if (response.status === 200) {
this.categoryList = response.data.data.categoryList || []
this.typeList = response.data.data.typeList || []
const data = response.data.data
if (data.categoryList) {
this.categoryList = data.categoryList
} else {
this.categoryList = []
}
if (data.eventTypeList) {
this.eventTypeList = data.eventTypeList
} else {
this.eventTypeList = []
}
} else {
console.error(response.data)
this.categoryList = []
this.eventTypeList = []
}
}).finally(() => {
}).catch((e) => {
console.error(e)
this.categoryList = []
this.eventTypeList = []
})
},
selectMode (ruleType) {
@@ -188,7 +224,3 @@ export default {
}
}
</script>
<style lang="scss">
</style>

View File

@@ -9,8 +9,7 @@
<div class="key-search">
<el-input v-model="searchKey" @keyup.enter="onSearch" size="mini" placeholder="Search for">
<template #prefix>
<!--todo 该图标名称错误已在iconfont修改后续记得改过来-->
<i class="cn-icon cn-icon-serach key-search-icon"></i>
<i class="cn-icon cn-icon-search key-search-icon"></i>
</template>
</el-input>
@@ -24,7 +23,7 @@
<div class="key-table">
<loading :loading="loading"></loading>
<el-table :data="tableData" style="width: 100%" @row-click="rowClick">
<el-table :data="tableData" style="width: 100%" :row-class-name="tableRowClassName" @row-click="rowClick">
<el-table-column
v-for="(item, index) in tableTitle"
:key="`col-${index}`"
@@ -73,6 +72,9 @@ export default {
showDrawer: {
type: Boolean,
default: false
},
delKeyId: {
type: String
}
},
components: {
@@ -116,6 +118,16 @@ export default {
this.myDrawer = this.showDrawer
this.getTopKeysData()
},
watch: {
delKeyId (newVal) {
if (newVal) {
const obj = this.tableData.find(d => d.keyId === newVal)
if (obj) {
obj.filterKey = false
}
}
}
},
methods: {
unitConvert,
dateFormatByAppearance,
@@ -150,6 +162,7 @@ export default {
},
/** 单击topKeys弹窗某一项 */
rowClick (data) {
data.filterKey = true
this.$emit('keyRowClick', data)
},
onRefresh () {
@@ -161,6 +174,11 @@ export default {
httpError (e) {
this.showError = true
this.errorMsg = this.errorMsgHandler(e)
},
tableRowClassName (row) {
if (row.row.filterKey) {
return 'key-click-row'
}
}
}
}
@@ -231,4 +249,8 @@ export default {
margin-left: 4px;
}
}
.el-table .key-click-row {
background: #F5F7FA !important;
}
</style>

View File

@@ -4,7 +4,7 @@
<div>
<el-form ref="form" :model="thresholdRuleObj" label-position="top" :rules="rules">
<!--source-->
<el-form-item label="Source" prop="dataSource" class="form-setting__block margin-b-20">
<el-form-item :label="$t('config.user.source')" prop="dataSource" class="form-setting__block margin-b-20">
<el-select v-model="thresholdRuleObj.dataSource" placeholder=" " size="mini" class="form-setting__select">
<el-option
v-for="item in sourceList"
@@ -18,7 +18,7 @@
<!--Dimensions-->
<div class="form-setting__block margin-b-20">
<div class="block-title">Dimensions</div>
<div class="block-title">{{ $t('detection.create.dimensions') }}</div>
<div class="block-dimension">
<div class="block-dimension-tag" v-for="(ite, ind) in dimensionList" :key="ind">{{ ite.label }}</div>
</div>
@@ -52,7 +52,7 @@
size="mini"
oninput="value=value.replace(/[^\d]/g,'')"
v-model="item.value"></el-input>
<i class="cn-icon cn-icon-close" @click="delFilterItem(index)"></i>
<i class="cn-icon cn-icon-close" @click="delFilterItem(index, item)"></i>
</div>
<div style="height: 10px;"></div>
@@ -65,7 +65,7 @@
<!--Condition模块-->
<div class="form-setting__block margin-b-20">
<div class="block-title">Condition</div>
<div class="block-title">{{ $t('detection.create.condition') }}</div>
<el-form ref="form2" :model="thresholdRuleObj" label-position="top">
<div class="definition-condition-block" v-for="(item, index) in thresholdRuleObj.conditionData" :key="index">
@@ -97,7 +97,7 @@
v-for="item in metricList"
:key="item.label"
:label="item.label"
:value="item.value"
:value="item.label"
/>
</el-select>
</el-form-item>
@@ -144,7 +144,7 @@
</el-form>
<div class="condition-add" @click="addCondition">
<i class="cn-icon cn-icon-add"></i>Add Condition
<i class="cn-icon cn-icon-add"></i>{{ $t('detection.create.addCondition') }}
</div>
</div>
</div>
@@ -154,6 +154,7 @@
<history-top-keys
v-if="showDrawer"
:showDrawer="showDrawer"
:delKeyId="delKeyId"
@closeDrawer="onCloseDrawer"
@keyRowClick="getRowClick"
></history-top-keys>
@@ -163,7 +164,7 @@
<div v-if="mySettingObj.ruleType===detectionRuleType.indicator">
<el-form ref="form" :model="indicatorRuleObj" label-position="top" :rules="rules">
<!--Source-->
<el-form-item label="Source" prop="dataSource" class="form-setting__block margin-b-20">
<el-form-item :label="$t('config.user.source')" prop="dataSource" class="form-setting__block margin-b-20">
<el-select v-model="indicatorRuleObj.dataSource" class="form-setting__select" placeholder=" " size="mini">
<el-option
v-for="item in sourceList"
@@ -175,13 +176,13 @@
</el-form-item>
<!--Library-->
<el-form-item label="Library" prop="knowledgeId" class="form-setting__block margin-b-20">
<el-select v-model="indicatorRuleObj.knowledgeId" class="form-setting__select" placeholder=" " size="mini">
<el-form-item :label="$t('detection.library')" prop="knowledgeId" class="form-setting__block margin-b-20">
<el-select v-model="indicatorRuleObj.name" class="form-setting__select" placeholder=" " size="mini">
<el-option
v-for="item in libraryList"
:key="item.knowledgeId"
:label="item.label"
:value="item.knowledgeId"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
@@ -207,22 +208,27 @@
</div>
<div class="form-setting__btn">
<el-button @click="onContinue">Continue</el-button>
<el-button @click="onContinue">{{ $t('detection.create.continue') }}</el-button>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { api } from '@/utils/api'
import HistoryTopKeys from '@/components/table/detection/HistoryTopKeys'
import { eventSeverityColor, detectionRuleType } from '@/utils/constants'
import { detectionUnitList } from '@/utils/static-data'
import axios from '_axios@0.21.4@axios'
import _ from 'lodash'
import { api } from '@/utils/api'
export default {
name: 'RuleDefinition',
props: {
settingObj: {
type: Object
},
editObj: {
type: Object
}
},
components: {
@@ -232,11 +238,26 @@ export default {
settingObj: {
immediate: true,
deep: true,
handler (newVal, oldVal) {
handler (newVal) {
if (!newVal.editFlag && newVal.saveFlag) {
this.mySettingObj = JSON.parse(JSON.stringify(newVal))
}
}
},
editObj: {
immediate: true,
deep: true,
handler (newVal) {
if (newVal) {
if (newVal.ruleType === detectionRuleType.indicator) {
this.indicatorRuleObj = this.$_.cloneDeep(newVal.ruleConfigObj)
this.indicatorRuleObj.knowledgeId = newVal.ruleConfigObj.knowledgeBase.knowledgeId
}
if (newVal.ruleType === detectionRuleType.threshold) {
this.thresholdRuleObj = this.$_.cloneDeep(newVal.ruleConfigObj)
}
}
}
}
},
data () {
@@ -244,7 +265,7 @@ export default {
eventSeverityColor,
detectionRuleType,
mySettingObj: {
ruleType: detectionRuleType.threshold
ruleType: detectionRuleType.indicator
},
dimensionList: [], // Dimensions数据
// ruleType为Indicator时表单数据
@@ -327,7 +348,8 @@ export default {
than: '>',
less: '<',
equal: '='
}
},
delKeyId: '' // 删除的keyId
}
},
mounted () {
@@ -341,18 +363,28 @@ export default {
},
methods: {
initData () {
axios.get(api.detection.statistics, { params: { pageSize: -1 } }).then(response => {
this.sourceList = detectionUnitList.sourceList || []
this.levelList = detectionUnitList.levelList || []
// threshold模式还没确定所以数据暂时静态数据后续根据需要修改
this.conditionList = detectionUnitList.conditionList || []
this.metricList = detectionUnitList.metricList || []
if (this.mySettingObj.ruleType === this.detectionRuleType.indicator) {
axios.get(api.knowledgeBaseList, { params: this.searchLabel }).then(response => {
if (response.status === 200) {
this.sourceList = response.data.data.sourceList || []
this.levelList = response.data.data.levelList || []
this.conditionList = response.data.data.conditionList || []
this.metricList = response.data.data.metricList || []
this.libraryList = response.data.data.libraryList || []
this.libraryList = _.get(response, 'data.data.list', [])
} else {
console.error(response.data)
this.libraryList = []
if (response.data.message) {
this.$message.error(response.data.message)
} else {
this.$message.error(this.$t('tip.somethingWentWrong'))
}
}).finally(() => {
}
}).catch(() => {
this.libraryList = []
})
}
},
/** 单击History Top Keys列表某行filter添加数据 */
getRowClick (data) {
@@ -364,6 +396,7 @@ export default {
},
/** filter模块点击add按钮 */
addFilter (data) {
this.delKeyId = ''
this.showFilter = true
if (this.selectList.length === 0) {
this.getFilterList()
@@ -445,7 +478,8 @@ export default {
]
},
/** 删除filter某一项 */
delFilterItem (i) {
delFilterItem (i, item) {
this.delKeyId = item.keyId
this.thresholdRuleObj.filterList.splice(i, 1)
},
/** 点击继续,展开第三步 */

View File

@@ -110,43 +110,6 @@ export default {
if (this.listUrl) {
listUrl = this.listUrl
}
// todo 此段是为了避免mock没开启打开detection界面报错提示后续再开发detection时删除
if (listUrl === api.detection.list) {
const list = []
for (let i = 0; i < 20; i++) {
const obj = {
ruleId: 100000 + i,
ruleType: 'indicator_match',
status: 1,
name: 'name123',
category: 'Security Event',
eventType: 'C&C',
description: 'Built-in darkweb IoC',
ruleConfig: {
knowledge: {
name: 'VPN Server IP',
category: 'user_defined'
}
}
}
if (i % 2 === 0) {
obj.ruleType = 'threshold'
obj.ruleConfig = {
dimensions: 'Destination IP/CIDR'
}
obj.description = 'abuse.ch is providing community driven threat intelligence on \n' +
'cyber threats. It is the home of a couple of projects that are \n' +
'helping internet service providers and network operators protect …'
} else {
obj.status = 0
}
list.push(obj)
}
this.tableData = list
this.pageObj.total = list.length
this.loading = false
} else {
axios.get(listUrl, { params: this.searchLabel }).then(response => {
if (response.status === 200) {
this.tableData = _.get(response, 'data.data.list', [])
@@ -167,7 +130,6 @@ export default {
this.toggleLoading(false)
this.loading = false
})
}
},
del (row) {
this.$confirm(this.$t('tip.confirmDelete'), {
@@ -400,10 +362,23 @@ export default {
this.searchLabel.orderBy = orderBy
this.getTableData()
},
search (params) {
search (params, flag, list) {
this.pageObj.pageNo = 1
if (flag !== 'detection') {
delete this.searchLabel.category
delete this.searchLabel.source
}
if (list && list.length > 0) {
if (list.indexOf('status') > -1) {
delete this.searchLabel.status
}
if (list.indexOf('category') > -1) {
delete this.searchLabel.category
}
if (list.indexOf('eventType') > -1) {
delete this.searchLabel.eventType
}
}
this.getTableData(params)
},
getTimeString () {

View File

@@ -7,7 +7,7 @@ if (openMock) {
const list = []
for (let i = 0; i < 20; i++) {
const obj = {
ruleId: 100000 + i,
ruleId: 163 + i,
ruleType: 'indicator_match',
status: 1,
name: 'name123',
@@ -50,51 +50,17 @@ if (openMock) {
Mock.mock(new RegExp(urlAndVersion + '/detection/statistics.*'), 'get', function (requestObj) {
const data = {
statusList: [
{ status: 1 },
{ status: 0 }
{ status: 1, count: 34 },
{ status: 0, count: 28 }
],
categoryList: [
{ value: 'security', label: 'Security Event' },
{ value: 'performance', label: 'Performance Event' },
{ value: 'regulatory_risk', label: 'Regulatory Risk Event' }
{ name: 'Security Event', count: 32 },
{ name: 'Performance Event', count: 28 }
],
typeList: [
{ value: 'c&c', label: 'C&C' },
{ value: 'ddos', label: 'DDos' },
{ value: 'lateral_movement', label: 'Lateral movement' },
{ value: 'brute_force', label: 'Brute force' }
],
sourceList: [
{ value: 'ip_metric', label: 'IP metric' },
{ value: 'performance_event', label: 'performance event' }
],
levelList: [
{ value: 'critical', label: 'Critical' },
{ value: 'high', label: 'High' },
{ value: 'medium', label: 'Medium' },
{ value: 'low', label: 'Low' },
{ value: 'info', label: 'Info' }
],
metricList: [
{ value: 'tcp_lostlen_ratio', label: 'Bits/second' },
{ value: 's2c_byte_retrans_ratio', label: 'Packets/second' },
{ value: 's2c_byte_retrans_ratio1', label: 'Sessions/second' }
],
conditionList: [
{ value: 'than', label: 'Greater Than' },
{ value: 'less', label: 'Greater Less' },
{ value: 'equal', label: 'Greater Equal' }
],
libraryList: [
{ value: 'library name2', knowledgeId: '101', label: 'Library name' },
{ value: 'library name1', knowledgeId: '102', label: 'Library name1' },
{ value: 'library name2', knowledgeId: '103', label: 'Library name2' }
],
intervalList: [
{ value: 'minutes', label: 'minutes' },
{ value: 'hours', label: 'hours' },
{ value: 'days', label: 'days' },
{ value: 'weeks', label: 'weeks' }
eventTypeList: [
{ name: 'DDos', count: 15 },
{ name: 'Lateral movement', count: 17 },
{ name: 'Brute force', count: 12 }
]
}
@@ -129,28 +95,50 @@ if (openMock) {
const ruleId = getLastValue(requestObj.url)
const data = {
name: 'name123',
category: 'Security Event',
category: 'security_event',
ruleType: 'indicator_match',
eventType: 'C&C',
description: 'Built-in darkweb IoC',
status: 1,
ruleConfig: {
dataSource: 'VPN Server IP',
knowledgeBase: {
knowledgeId: 10,
level: 10
name: 'cn_ioc_darkweb',
category: 'websketch',
source: 'cn_ioc_darkweb'
},
trigger: {
level: 'critical'
},
ruleConfigObj: {
dataSource: 'VPN Server IP',
knowledgeBase: {
knowledgeId: '101',
name: 'cn_ioc_darkweb',
category: 'websketch',
source: 'cn_ioc_darkweb'
},
level: 'critical'
},
ruleTrigger: {
atLeast: 1,
interval: 'PT5M',
resetInterval: 'PT10M'
},
ruleTriggerObj: {
atLeast: 1,
interval: 'PT5M',
resetInterval: 'PT10M'
}
}
data.ruleConfig = JSON.stringify(data.ruleConfig)
data.trigger = JSON.stringify(data.trigger)
if (ruleId % 2 === 0) {
data.ruleType = 'threshold'
data.status = 1
} else {
data.status = 0
} else {
data.status = 1
}
return {

View File

@@ -103,6 +103,10 @@ const routes = [
{
path: '/detection/policies/create',
component: () => import('@/views/detectionsNew/DetectionForm')
},
{
path: '/detection/policies/edit',
component: () => import('@/views/detectionsNew/DetectionForm')
}
]
}

View File

@@ -139,13 +139,13 @@ export const api = {
},
list: apiVersion + '/rule/detection/list', // 检测规则列表
detail: apiVersion + '/rule/detection', // 检测规则详情
delete: apiVersion + '/rule', // 检测规则删除
delete: apiVersion + '/rule/detection', // 检测规则删除
// 获取单位列表如source、type、metric等
statistics: apiVersion + '/detection/statistics',
statistics: apiVersion + '/rule/detection/statistics',
// 规则新建模块
create: {
topKeys: apiVersion + '/detection/topKeys', // topKeys列表
create: apiVersion + '/rule/detection/create' // todo 规则新建编辑此api为模拟后续需要修改
create: apiVersion + '/rule/detection'
}
},
// Dashboard

View File

@@ -2479,8 +2479,8 @@ export const psiphon3IpType = [
]
// detection新增页的第一步选择mode
export const detectionRuleType = {
indicator: 'Indicator Match',
threshold: 'Threshold'
indicator: 'indicator_match',
threshold: 'threshold'
}
// 顶级域名列表

View File

@@ -137,3 +137,73 @@ export const xAxisTimeRich = {
fontWeight: 'bold'
}
}
function switchDateTypeByStr (str) {
switch (str) {
case 'Y':
return 'years'
case 'M':
return 'months'
case 'W':
return 'weeks'
case 'D':
return 'days'
case 'H':
return 'hours'
case 'm':
return 'minutes'
case 'S':
return 'seconds'
}
}
function switchValueByDateType (str) {
switch (str) {
case 'years':
return 'Y'
case 'months':
return 'M'
case 'weeks':
return 'W'
case 'days':
return 'D'
case 'hours':
return 'H'
case 'minutes':
return 'm'
case 'seconds':
return 'S'
}
}
export function getTimeByDurations (str) {
if (str && str.indexOf('P') === 0) {
const obj = {
type: '',
value: ''
}
for (let i = 1; i < str.length; i++) {
const item = str[i]
// P5M表示持续5个月PT5M持续5分钟T是位于时间分量之前的时间指示符即T之前是年月周日T之后是时分秒
if (isNaN(item) && item !== 'T') {
if (item === 'M' && i < str.indexOf('T')) {
obj.type = switchDateTypeByStr('m')
} else {
obj.type = switchDateTypeByStr(item)
}
} else if (!isNaN(item)) {
obj.value += item
}
}
return obj
}
}
export function getDurationsTimeByType (number, type) {
let T = ''
if (['hours', 'minutes', 'seconds'].indexOf(type) > -1) {
T = 'T'
}
return `P${T}${number}${switchValueByDateType(type)}`
}

View File

@@ -350,3 +350,53 @@ export const connectionList = [
// label: 'OR'
// }
]
export const detectionUnitList = {
statusList: [
{ status: 1 },
{ status: 0 }
],
categoryList: [
{ value: 'security_event', label: 'Security Event' },
{ value: 'performance_event', label: 'Performance Event' }
],
eventTypeList: [
{ value: 'ddos', label: 'DDos' },
{ value: 'lateral_movement', label: 'Lateral movement' },
{ value: 'brute_force', label: 'Brute force' }
],
sourceList: [
{ value: 'session_record', label: 'session_record' }
],
levelList: [
{ value: 'critical', label: 'Critical' },
{ value: 'high', label: 'High' },
{ value: 'medium', label: 'Medium' },
{ value: 'low', label: 'Low' },
{ value: 'info', label: 'Info' }
],
metricList: [
{ value: 'tcp_lostlen_ratio', label: 'Bits/second' },
{ value: 's2c_byte_retrans_ratio', label: 'Packets/second' },
{ value: 's2c_byte_retrans_ratio1', label: 'Sessions/second' }
],
conditionList: [
{ value: 'than', label: 'Greater Than' },
{ value: 'less', label: 'Greater Less' },
{ value: 'equal', label: 'Greater Equal' }
],
libraryList: [
{ value: 'library name', knowledgeId: 7, label: 'Library name' },
{ value: 'library name1', knowledgeId: 8, label: 'Library name1' },
{ value: 'library name2', knowledgeId: 9, label: 'Library name2' }
],
intervalList: [
{ value: 'year', label: 'years' },
{ value: 'months', label: 'months' },
{ value: 'weeks', label: 'weeks' },
{ value: 'days', label: 'days' },
{ value: 'hours', label: 'hours' },
{ value: 'minutes', label: 'minutes' },
{ value: 'seconds', label: 'seconds' }
]
}

View File

@@ -1320,9 +1320,9 @@ export function numberWithCommas (num) {
export function switchStatus (status) {
switch (status) {
case 0:
return 'Disabled'
return 'detection.create.disabled'
case 1:
return 'Enabled'
return 'detection.create.enabled'
}
}

View File

@@ -3,62 +3,62 @@
<div class="drawer-basic">
<div class="drawer-basic-header">
<div class="drawer-basic-id">ID: {{ drawerInfo.ruleId }}</div>
<div :class="`detection-tag-status${detailData.status}`">
{{ switchStatus(detailData.status) }}
<div :class="`detection-tag-status${drawerInfo.status}`">
{{ $t(switchStatus(drawerInfo.status)) }}
</div>
</div>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Name</div>
<div class="detection-drawer-title">{{ $t('overall.name') }}</div>
<div class="basic-function-value">{{ detailData.name }}</div>
</div>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Type</div>
<div class="detection-drawer-title">{{ $t('overall.type') }}</div>
<div class="basic-function-value">{{ detailData.eventType }}</div>
</div>
<div class="drawer-basic-description">
<div class="detection-drawer-title">Description</div>
<div class="detection-drawer-title">{{ $t('config.dataSet.description') }}</div>
<div class="basic-description-value">{{ detailData.description }}</div>
</div>
</div>
<div class="detection-drawer-collapse">
<el-collapse v-model="activeRule">
<el-collapse-item title="Rule Definitcm" name="rule">
<el-collapse-item :title="$t('detection.ruleDefinition')" name="rule">
<div class="drawer-collapse-content">
<div class="drawer-basic-function">
<div class="detection-drawer-title">Source</div>
<div class="detection-drawer-title">{{ $t('config.user.source') }}</div>
<div class="basic-function-value">{{ detailData.category }}</div>
</div>
<div v-if="detailData.ruleType==='indicator_match'">
<div class="drawer-basic-function">
<div class="detection-drawer-title">Library</div>
<span class="basic-function-value">{{ detailData.library }}</span>
<div class="detection-drawer-title">{{ $t('detection.library') }}</div>
<span class="basic-function-value">{{ detailData.ruleConfigObj.knowledgeBase.name }}</span>
</div>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Level</div>
<div class="detection-drawer-title">{{ $t('detection.level') }}</div>
<div class="detection-drawer-title">
<div class="detection__icon" :style="`background-color: ${eventSeverityColor['critical']}`"></div>
<div class="basic-function-value">Critical</div>
<div class="detection__icon" :style="`background-color: ${eventSeverityColor[detailData.ruleConfigObj.level]}`"></div>
<div class="basic-function-value">{{ detailData.ruleConfigObj.level }}</div>
</div>
</div>
</div>
<div v-else>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Dimensions</div>
<div class="detection-drawer-title">{{ $t('detection.create.dimensions') }}</div>
<span class="detection-tag-blue">{{ detailData.dimensions }}</span>
</div>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Filters</div>
<span class="detection-tag-blue">source</span>
<span style="margin: 0 6px;">equal</span><span>19890</span>
<div class="detection-drawer-title">{{ $t('detections.filters') }}</div>
<span class="detection-tag-blue">Source Port</span>
<span style="margin: 0 6px;">{{ $t('detections.equal') }}</span><span>19890</span>
</div>
<div class="drawer-basic-function" v-for="item in severityList" :key="item.severity"
@@ -67,7 +67,7 @@
<div class="detection__icon" :style="`background-color: ${eventSeverityColor[item.severity]}`"></div>
<div>{{ toUpperCaseByString(item.severity) }}</div>
</div>
<div class="detection-drawer-title">Conditions</div>
<div class="detection-drawer-title">{{ $t('detections.conditions') }}</div>
<div>
<div class="detection-tag-gray margin-r-10">> 60 Kpackets/s</div>
<div class="detection-tag-gray">> 50 Unique Src IPs</div>
@@ -81,22 +81,25 @@
<div class="detection-drawer-collapse" style="margin: 20px 0">
<el-collapse v-model="activeTrigger">
<el-collapse-item title="Trigger" name="trigger">
<el-collapse-item :title="$t('detection.create.trigger')" name="trigger">
<div class="drawer-collapse-content">
<div class="drawer-collapse-trigger">
Triggered when conditions occur at least
<span style="color: #046ECA" v-if="detailData.trigger">
{{ detailData.trigger.atLeast }} time
<span style="color: #046ECA">
{{ $_.get(detailData, 'ruleTriggerObj.atLeast', '-') || '-' }} time
</span> in
<span style="color: #046ECA" v-if="detailData.trigger">
<!--todo 此处返回的是PT5M具体时间处理根据后续字段来看-->
{{ getNumberFromStr(detailData.trigger.interval) }} minutes
<span style="color: #046ECA">
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.interval', '0')) || '-' }}
{{ $_.get(detailData, 'ruleTriggerObj.intervalVal', '-') || '-' }}
</span>
</div>
<div class="drawer-basic-function">
<div class="detection-drawer-title">Evaluation Frequency</div>
<div class="basic-function-value" v-if="detailData.trigger">{{ getNumberFromStr(detailData.trigger.resetInterval) }} minutes</div>
<div class="detection-drawer-title">{{ $t('detection.evaluationFrequency') }}</div>
<div class="drawer-trigger-minutes">
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.resetInterval', '0')) || '-' }}
{{ $_.get(detailData, 'ruleTriggerObj.intervalVal', '-') || '-' }}
</div>
</div>
</div>
</el-collapse-item>
@@ -156,7 +159,8 @@ export default {
axios.get(`${api.detection.detail}/${this.drawerInfo.ruleId}`).then(res => {
if (res.status === 200) {
this.detailData = res.data.data
const data = res.data.data
this.detailData = data
}
}).catch(err => {
console.error(err)

View File

@@ -8,8 +8,8 @@
<div class="new-filter-content-title">{{ $t('overall.status') }}</div>
<div class="new-filter-content-content">
<el-checkbox-group v-model="checkStatus" @change="onChangeCategory" style="display: flex;flex-direction: column">
<el-checkbox v-for="item in statusList" :key="item.label" class="new-filter-content-checkbox" :label="item.status">
<div>{{ item.label }}</div>
<el-checkbox v-for="item in statusList" :key="item.name" class="new-filter-content-checkbox" :label="item.status">
<div>{{ item.name }}</div>
</el-checkbox>
</el-checkbox-group>
</div>
@@ -19,8 +19,8 @@
<div class="new-filter-content-title">{{ $t('overall.category') }}</div>
<div class="new-filter-content-content">
<el-checkbox-group v-model="checkCategory" @change="onChangeCategory">
<el-checkbox v-for="item in categoryList" :key="item.value" class="new-filter-content-checkbox" :label="item.value">
{{ item.label }}
<el-checkbox v-for="item in categoryList" :key="item.name" class="new-filter-content-checkbox" :label="item.name">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div>
@@ -29,9 +29,9 @@
<div>
<div class="new-filter-content-title">{{ $t('overall.type') }}</div>
<div class="new-filter-content-content">
<el-checkbox-group v-model="checkType" @change="onChangeCategory" style="display: flex;flex-direction: column">
<el-checkbox v-for="item in typeList" :key="item.value" class="new-filter-content-checkbox" :label="item.value">
{{ item.label }}
<el-checkbox-group v-model="checkEventType" @change="onChangeCategory" style="display: flex;flex-direction: column">
<el-checkbox v-for="item in eventTypeList" :key="item.name" class="new-filter-content-checkbox" :label="item.name">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div>
@@ -43,100 +43,76 @@
<script>
import axios from 'axios'
import { api } from '@/utils/api'
import { switchStatus } from '@/utils/tools'
export default {
name: 'DetectionFilter',
data () {
return {
statusList: [],
categoryList: [],
typeList: [],
checkStatus: [],
checkCategory: [],
checkType: [],
url: api.detection.statistics
statusList: [], // 状态列表数据
categoryList: [], // 类别列表
eventTypeList: [], // 事件类型列表
checkStatus: [], // checkbox选择的状态列表
checkCategory: [], // checkbox选择的类别
checkEventType: [], // checkbox选择的事件类型
policyTotal: 0, // 策略总条数,与筛选条件无关
policyEnabledNum: 0 // 策略中状态为enabled的数量
}
},
mounted () {
// 开发时删除---start
this.statusList = [
{ status: 1, label: 'Enabled' },
{ status: 0, label: 'Disabled' }
]
this.checkStatus = [0, 1]
this.categoryList = [
{ value: 'security', label: 'Security Event' },
{ value: 'performance', label: 'Performance Event' },
{ value: 'regulatory_risk', label: 'Regulatory Risk Event' }
]
this.checkCategory = ['security', 'performance', 'regulatory_risk']
this.typeList = [
{ value: 'c&c', label: 'C&C' },
{ value: 'ddos', label: 'DDos' },
{ value: 'lateral_movement', label: 'Lateral movement' },
{ value: 'brute_force', label: 'Brute force' }
]
this.checkType = ['c&c', 'ddos', 'lateral_movement', 'brute_force']
// 开发时删除---end
// todo 暂时禁用,后续再开发时解禁
// this.getFilterData()
this.getFilterData()
},
methods: {
getFilterData (params) {
let searchParams = { pageSize: -1 }
if (params) {
searchParams = { ...searchParams, ...params }
}
axios.get(this.url, { params: searchParams }).then(response => {
getFilterData () {
axios.get(api.detection.statistics).then(response => {
if (response.status === 200) {
if (response.data.data.statusList) {
const data = response.data.data
if (data.statusList) {
data.statusList.forEach(item => {
this.policyTotal += item.count
if (item.status === 1) {
this.policyEnabledNum = item.count
}
this.statusList.push({ status: item.status, name: this.$t(switchStatus(item.status)) })
})
this.$emit('policyTotal', this.policyTotal, this.policyEnabledNum)
} else {
this.statusList = []
response.data.data.statusList.forEach(item => {
this.statusList.push({ status: item.status, label: this.switchStatus(item.status) })
this.checkStatus.push(item.status)
})
}
this.categoryList = response.data.data.categoryList
if (response.data.data.categoryList) {
response.data.data.categoryList.forEach(item => {
this.checkCategory.push(item.value)
})
if (data.categoryList) {
this.categoryList = data.categoryList
} else {
this.categoryList = []
}
this.typeList = response.data.data.typeList
if (response.data.data.typeList) {
response.data.data.typeList.forEach(item => {
this.checkType.push(item.value)
})
if (data.eventTypeList) {
this.eventTypeList = data.eventTypeList
} else {
this.eventTypeList = []
}
} else {
console.error(response.data)
}
}).finally(() => {
// this.initTypeData()
// this.initStatusData()
// const self = this
// this.$nextTick(() => {
// if (self.$refs.knowledgeTreeTypeFilter) {
// self.$refs.knowledgeTreeTypeFilter.setCheckedKeys(this.defaultCheckedCategory)
// }
// if (self.$refs.knowledgeTreeStatusFilter) {
// self.$refs.knowledgeTreeStatusFilter.setCheckedKeys(this.defaultCheckedStatus)
// }
// })
}).catch((e) => {
console.error(e)
this.statusList = []
this.categoryList = []
this.eventTypeList = []
})
},
onChangeCategory (data) {
// todo 暂时禁用,后续再开发时解禁
// 根据选择的值,构造不同入参,传给列表页,调用查询列表接口
},
switchStatus (status) {
switch (status) {
case 0: return 'Disabled'
case 1: return 'Enabled'
onChangeCategory () {
const obj = {}
if (this.checkStatus.length > 0) {
obj.status = this.checkStatus.join(',')
}
if (this.checkCategory.length > 0) {
obj.category = this.checkCategory.join(',')
}
if (this.checkEventType.length > 0) {
obj.eventType = this.checkEventType.join(',')
}
this.$emit('filterParams', obj)
}
}
}

View File

@@ -1,8 +1,9 @@
<template>
<div class="detection-form">
<loading :loading="myLoading"></loading>
<div class="detection-form-header">
Create Alert Policies
{{ $t('detection.createEventPolicies') }}
</div>
<!--第一步General Settings-->
@@ -13,11 +14,11 @@
<template #title>
<div class="form-collapse-header">
<div :class="activeNames[0]==='1' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">1</div>
<div class="form-collapse-header-title">General Settings</div>
<div class="form-collapse-header-title">{{ $t('detection.create.generalSettings') }}</div>
</div>
</template>
<div class="form-collapse-content">
<general-settings ref="form" @setSettingForm="getFormSetting" />
<general-settings ref="form" :editObj="editObj" @setSettingForm="getFormSetting" />
</div>
</el-collapse-item>
</el-collapse>
@@ -30,11 +31,11 @@
<template #title>
<div class="form-collapse-header">
<div :class="activeNames[0]==='2' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">2</div>
<div class="form-collapse-header-title">Rule Definition</div>
<div class="form-collapse-header-title">{{ $t('detection.create.ruleDefinition') }}</div>
</div>
</template>
<div class="form-collapse-content">
<rule-definition :settingObj="settingObj" @setRuleObj="getRuleObj" />
<rule-definition :settingObj="settingObj" :editObj="editObj" @setRuleObj="getRuleObj" />
</div>
</el-collapse-item>
</el-collapse>
@@ -47,7 +48,7 @@
<template #title>
<div class="form-collapse-header">
<div :class="activeNames[0]==='3' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">3</div>
<div class="form-collapse-header-title">Trigger</div>
<div class="form-collapse-header-title">{{ $t('detection.create.trigger') }}</div>
</div>
</template>
@@ -78,15 +79,18 @@
<div class="trigger-block-item">
<div>With the counter resetting after no activity for</div>
<el-form-item prop="minute">
<el-input size="mini" v-model="triggerObj.minute" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
<el-form-item prop="resetInterval">
<el-input size="mini" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item>
<div>minutes</div>
<div>{{ triggerObj.intervalVal }}</div>
</div>
</el-form>
<div class="form-setting__btn1">
<el-button @click="createPolicy">Create & enable rule</el-button>
<div class="btn1">
<el-button @click="createPolicy">{{ $t('overall.create') }}</el-button>
</div>
<el-button @click="createPolicy('enabled')">{{ $t('overall.create') }} & {{ $t('detection.create.enablePolicy') }}</el-button>
</div>
</div>
</el-collapse-item>
@@ -101,23 +105,17 @@ import GeneralSettings from '@/components/table/detection/GeneralSettings'
import RuleDefinition from '@/components/table/detection/RuleDefinition'
import { api } from '@/utils/api'
import axios from 'axios'
import _ from 'lodash'
import { useRoute } from 'vue-router'
import { detectionUnitList } from '@/utils/static-data'
import { ref } from 'vue'
import { getDurationsTimeByType, getTimeByDurations } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
export default {
name: 'DetectionForm',
data () {
return {
activeNames: ['1'],
settingObj: {}, // General Settings即第一步的form表单信息
ruleObj: {}, // 第二步的form表单信息
// 第三步的form表单信息
triggerObj: {
atLeast: '',
interval: '',
intervalVal: '',
minute: '',
finishFlag: false
},
rules: {
atLeast: [
{
@@ -130,7 +128,7 @@ export default {
{
required: true,
message: this.$t('validate.required'),
trigger: 'change'
trigger: 'blur'
}
],
intervalVal: [
@@ -140,7 +138,7 @@ export default {
trigger: 'change'
}
],
minute: [
resetInterval: [
{
required: true,
message: this.$t('validate.required'),
@@ -148,27 +146,80 @@ export default {
}
]
},
intervalList: []
intervalList: detectionUnitList.intervalList || [],
editObj: {}
}
},
components: {
GeneralSettings,
RuleDefinition
RuleDefinition,
Loading
},
mounted () {
this.getStatistics()
this.getDetailInfo()
},
setup () {
const { query } = useRoute()
const ruleId = ref(query.id || '')
const pageNoForTable = ref(query.pageNoForTable || 1)
const myLoading = ref(!!ruleId.value)
// General Settings即第一步的form表单信息
const settingObj = ref({})
// 第二步的form表单信息
const ruleObj = ref({})
// 第三步的form表单信息
const triggerObj = ref({
atLeast: '',
interval: '',
intervalVal: '',
resetInterval: '',
finishFlag: false
})
return {
ruleId,
myLoading,
pageNoForTable,
settingObj,
ruleObj,
triggerObj
}
},
methods: {
/** 获取下拉列表数据 */
getStatistics () {
axios.get(api.detection.statistics, { pageSize: -1 }).then(response => {
/** 编辑时获取详情 */
getDetailInfo () {
if (this.ruleId) {
axios.get(`${api.detection.detail}/${this.ruleId}`).then(response => {
if (response.status === 200) {
this.intervalList = _.get(response, 'data.data.intervalList', [])
if (!response.data.data) {
throw new Error('No data found, id: ' + this.ruleId)
}
this.myLoading = false
this.editObj = { ...response.data.data, ruleId: this.ruleId }
this.settingObj = this.$_.cloneDeep(this.editObj)
this.settingObj.editFlag = false
this.settingObj.saveFlag = true
this.ruleObj = this.$_.cloneDeep(this.editObj.ruleConfigObj)
this.triggerObj = this.$_.cloneDeep(this.editObj.ruleTriggerObj)
this.triggerObj.intervalVal = getTimeByDurations(this.triggerObj.interval).type
this.triggerObj.interval = getTimeByDurations(this.triggerObj.interval).value
this.triggerObj.resetInterval = getTimeByDurations(this.triggerObj.resetInterval).value
this.activeNames = ['1', '2', '3']
} else {
console.error(response.data)
}
}).finally(() => {
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
this.$router.push({
path: '/detection/policies',
query: {
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
t: +new Date()
}
})
})
}
},
/** 获取General Settings折叠板form数据 */
getFormSetting (data) {
@@ -190,7 +241,7 @@ export default {
})
},
/** 创建policy */
createPolicy () {
createPolicy (flag) {
const settingLen = Object.keys(this.settingObj).length
const ruleLen = Object.keys(this.ruleObj).length
@@ -198,36 +249,73 @@ export default {
this.$refs.form3.validate(valid => {
if (valid) {
// 最终提交form
// const formObj = { ...this.settingObj, ...this.ruleObj, ...this.triggerObj }
const formObj = this.$_.cloneDeep({ ...this.settingObj, ruleConfig: JSON.stringify(this.ruleObj), ruleTrigger: this.triggerObj })
if (flag) {
formObj.status = 1
}
// 将时间转为参数所需如5分钟转为PT5
formObj.ruleTrigger.resetInterval = getDurationsTimeByType(formObj.ruleTrigger.resetInterval, formObj.ruleTrigger.intervalVal)
formObj.ruleTrigger.interval = getDurationsTimeByType(formObj.ruleTrigger.interval, formObj.ruleTrigger.intervalVal)
formObj.ruleTrigger = JSON.stringify(formObj.ruleTrigger)
// 删除多余参数
delete formObj.ruleConfigObj
delete formObj.ruleTriggerObj
delete formObj.editFlag
delete formObj.saveFlag
if (!this.ruleId) {
// post调用是新增put是编辑
this.myLoading = true
axios.post(api.detection.create.create, formObj).then(response => {
if (response.status === 200) {
this.$message({
duration: 2000,
type: 'success',
message: this.$t('tip.saveSuccess')
})
// axios.post('api', formObj).then(response => {
// if (response.status === 200) {
// this.$message({
// duration: 2000,
// type: 'success',
// message: this.$t('tip.saveSuccess')
// })
//
// this.$router.push({
// path: '/detectionNew',
// query: {
// t: +new Date()
// }
// })
// } else {
// this.$message.error(this.errorMsgHandler(response))
// }
// }).catch(e => {
// console.error(e)
// this.$message.error(this.errorMsgHandler(e))
// }).finally(() => {
// //
// })
this.$router.push({
path: '/detectionsNew',
query: {
t: +new Date()
}
})
} else {
this.$message.error(this.errorMsgHandler(response))
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
}).finally(() => {
this.myLoading = false
})
} else {
this.myLoading = true
axios.put(api.detection.create.create, formObj).then(response => {
if (response.status === 200) {
this.$message({
duration: 2000,
type: 'success',
message: this.$t('tip.saveSuccess')
})
this.$router.push({
path: '/detectionsNew',
query: {
pageNo: self.pageNoForTable ? Number(self.pageNoForTable) : 1,
t: +new Date()
}
})
} else {
this.$message.error(this.errorMsgHandler(response))
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
}).finally(() => {
this.myLoading = false
})
}
}
})
} else if (settingLen === 0) {

View File

@@ -50,7 +50,7 @@
</template>
<template v-else-if="item.prop === 'status'">
<div :class="`detection-tag-status${scope.row[item.prop]}`">
{{ switchStatus(scope.row[item.prop]) }}
{{ $t(switchStatus(scope.row[item.prop])) }}
</div>
</template>
<template v-else-if="item.prop === 'description'">
@@ -151,9 +151,9 @@ export default {
if (n) {
n.forEach(t => {
if (t.ruleType === 'indicator_match') {
t.library = t.ruleConfig.knowledge.name
t.library = t.ruleConfigObj.knowledgeBase.name
} else if (t.ruleType === 'threshold') {
t.dimensions = t.ruleConfig.dimensions
t.dimensions = t.ruleConfigObj.dimensions
}
})
}

View File

@@ -11,14 +11,16 @@
<span>{{ $t('overall.create') }}</span>
</button>
<!-- <button-->
<!-- id="knowledge-base-edit"-->
<!-- :title="$t('knowledgeBase.editKnowledgeBase')"-->
<!-- class="top-tool-btn margin-r-10"-->
<!-- style="width:72px;">-->
<!-- <i class="cn-icon-edit cn-icon" ></i>-->
<!-- <span>{{$t('overall.edit')}}</span>-->
<!-- </button>-->
<button
:disabled="disableEdit"
id="knowledge-base-edit"
:title="$t('knowledgeBase.editKnowledgeBase')"
class="top-tool-btn margin-r-10"
@click="onEdit"
style="width:72px;">
<i class="cn-icon-edit cn-icon" ></i>
<span>{{$t('overall.edit')}}</span>
</button>
<button
:disabled="disableDelete"
@@ -51,6 +53,10 @@ export default {
disableDelete: {
type: Boolean,
default: true
},
disableEdit: {
type: Boolean,
default: true
}
},
data () {
@@ -65,6 +71,9 @@ export default {
onCreate () {
this.$emit('create')
},
onEdit () {
this.$emit('edit')
},
onDelete (data) {
this.$emit('delete', data)
}

View File

@@ -1,22 +1,24 @@
<template>
<div class="detection">
<div class="detection-title">
<span>{{ $t('overall.detections') }}</span>
<span>{{ $t('overall.policies') }}</span>
<span class="detection-title-label">
60 polices created(200 max) | 32 polices enabled(100 max)
{{ policyTotal }} {{ $t('detection.policesCreated') }} | {{ policyEnabledNum }} {{ $t('detection.policesEnabled') }}
</span>
</div>
<div class="detection-content">
<div class="detection-filter">
<detection-filter></detection-filter>
<detection-filter @filterParams="getFilterParams" @policyTotal="getPolicyTotal" />
</div>
<div class="detection-block">
<detection-tools
@delete="toDelete"
@create="onCreate"
@edit="onEdit"
@search="onSearch"
:disableEdit="disableEdit"
:disableDelete="disableDelete"/>
<div class="detection-table" style="position: relative">
@@ -32,7 +34,6 @@
:all-count="18"
@selectionChange="selectionChange"
@reload="reloadRowList"
@toggleLoading="toggleLoading"
@rowDoubleClick="onRowDoubleClick"
></detection-table>
</div>
@@ -61,10 +62,8 @@
cell-style="padding:4px 0px;font-size: 12px;color: #353636;font-weight: 400;"
header-cell-style="padding:4px 0px;background: #F5F8FA;font-size: 12px;color: #353636;font-weight: 500;">
<el-table-column :resizable="false" align="center" type="selection" width="50"></el-table-column>
<el-table-column property="ruleId" label="ID" width="70"></el-table-column>
<el-table-column property="ruleId" label="ID" width="150"></el-table-column>
<el-table-column property="name" label="Name"></el-table-column>
<el-table-column property="category" label="Category" width="100" :formatter="categoryFormat"></el-table-column>
<el-table-column property="function" label="Function" width="110" :formatter="sourceFormat"></el-table-column>
</el-table>
<template #footer>
<span class="dialog-footer">
@@ -89,6 +88,7 @@ import DetectionTable from '@/views/detectionsNew/DetectionTable'
import { api } from '@/utils/api'
import dataListMixin from '@/mixins/data-list'
import DetectionDrawer from '@/views/detectionsNew/DetectionDrawer'
import axios from 'axios'
export default {
name: 'Index',
@@ -101,8 +101,8 @@ export default {
mixins: [dataListMixin],
data () {
return {
// url: api.detection.list,
url: api.knowledgeBase,
url: api.detection.list,
// url: api.knowledgeBase,
listUrl: api.detection.list,
tableId: 'detectionTable',
isNoData: false,
@@ -110,42 +110,52 @@ export default {
isSelectedStatus: false,
batchDeleteObjs: [], // 待删除列表
secondBatchDeleteObjs: [],
disableEdit: true,
disableDelete: true,
showConfirmDialog: false,
delItemList: [],
showDrawer: false,
drawerInfo: {}
drawerInfo: {},
filterParams: {},
policyTotal: 0,
policyEnabledNum: 0
}
},
methods: {
onSearch () {
// todo 暂时禁用,后续再开发时解禁
// const params = {
// ...this.filterParams,
// name: this.keyWord
// }
// this.clearList()
// this.search(params)
// this.$refs.knowledgeFilter.reloadFilter(this.checkedCategoryIds, this.checkedStatusIds)
onSearch (keyWord) {
this.filterParams = {
...this.filterParams,
name: keyWord
}
this.search(this.filterParams, 'detection')
},
toDelete (data) {
// todo 暂时禁用,后续再开发时解禁
// if (data && data.ruleId) {
// this.secondBatchDeleteObjs = []
// this.batchDeleteObjs = []
// this.secondBatchDeleteObjs.push(data)
// this.batchDeleteObjs.push(data)
// }
// this.showDelDialog()
if (data && data.ruleId) {
this.secondBatchDeleteObjs = []
this.batchDeleteObjs = []
this.secondBatchDeleteObjs.push(data)
this.batchDeleteObjs.push(data)
}
this.showDelDialog()
},
onCreate () {
// todo 暂时禁用,后续再开发时解禁
// this.$router.push({
// path: '/detection/policies/create',
// query: {
// t: +new Date()
// }
// })
this.$router.push({
path: '/detection/policies/create',
query: {
t: +new Date()
}
})
},
onEdit () {
const pageNo = this.$router.currentRoute.value.query.pageNo
this.$router.push({
path: '/detection/policies/edit',
query: {
t: +new Date(),
pageNoForTable: pageNo || 1,
id: this.batchDeleteObjs[0].ruleId
}
})
},
selectionChange (objs) {
this.batchDeleteObjs = []
@@ -161,8 +171,6 @@ export default {
reloadRowList () {
this.getTableData()
},
toggleLoading () {
},
showDelDialog () {
this.showConfirmDialog = true
this.$nextTick(() => {
@@ -177,16 +185,6 @@ export default {
secondSelectionChange (objs) {
this.secondBatchDeleteObjs = objs
},
categoryFormat (row, column) {
// const category = row.category
// const t = knowledgeBaseCategory.find(t => t.value === category)
// return t ? t.name : category
},
sourceFormat (row, column) {
// const source = row.source
// const t = knowledgeBaseSource.find(t => t.value === source)
// return t ? t.name : source
},
submit () {
this.delBatchDetection()
this.showConfirmDialog = false
@@ -206,39 +204,64 @@ export default {
})
} else {
// todo 调用接口删除
// this.toggleLoading(true)
// axios.delete(api.detection.delete + '?ruleIds=' + ids).then(response => {
// if (response.status === 200) {
// this.delFlag = true
// this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
// this.secondBatchDeleteObjs.forEach((item) => {
// this.$refs.delDataTable.toggleRowSelection(item, false)
// })
// this.$refs.knowledgeFilter.reloadFilter()
// this.secondBatchDeleteObjs = []
// this.batchDeleteObjs = []
// delete this.searchLabel.category
// delete this.searchLabel.source
// this.getTableData()
// } else {
// this.$message.error(response.data.message)
// }
// }).finally(() => {
// this.toggleLoading(false)
// if (this.isSelectedStatus != undefined) {
// this.isSelectedStatus = false
// this.disableDelete = true
// this.secondBatchDeleteObjs = []
// this.batchDeleteObjs = []
// this.showConfirmDialog = false
// }
// })
this.toggleLoading(true)
axios.delete(api.detection.delete + '?ruleIds=' + ids).then(response => {
if (response.status === 200) {
this.delFlag = true
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
this.secondBatchDeleteObjs.forEach((item) => {
this.$refs.delDataTable.toggleRowSelection(item, false)
})
this.secondBatchDeleteObjs = []
this.batchDeleteObjs = []
delete this.searchLabel.category
delete this.searchLabel.source
this.getTableData()
} else {
this.$message.error(response.data.message)
}
}).finally(() => {
this.toggleLoading(false)
if (this.isSelectedStatus) {
this.isSelectedStatus = false
this.disableDelete = true
this.secondBatchDeleteObjs = []
this.batchDeleteObjs = []
this.showConfirmDialog = false
}
})
}
},
onRowDoubleClick (data) {
// todo 暂时禁用,后续再开发时解禁
// this.showDrawer = true
// this.drawerInfo = data
this.showDrawer = true
this.drawerInfo = data
},
getFilterParams (params) {
const delList = []
if (params.status) {
this.filterParams.status = params.status
} else {
delete this.filterParams.status
delList.push('status')
}
if (params.category) {
this.filterParams.category = params.category
} else {
delete this.filterParams.category
delList.push('category')
}
if (params.eventType) {
this.filterParams.eventType = params.eventType
} else {
delete this.filterParams.eventType
delList.push('eventType')
}
this.search(this.filterParams, 'detection', delList)
},
getPolicyTotal (total, enabledNum) {
this.policyTotal = total
this.policyEnabledNum = enabledNum
}
}
}