This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
cyber-narrator-cn-ui/src/views/detections/detectionPolicies/PolicyForm.vue
2024-04-10 16:50:39 +08:00

573 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="detection-form">
<loading :loading="myLoading"></loading>
<div class="detection-form-header">
{{ ruleId ? $t('detection.editEventPolicies') : $t('detection.createEventPolicies') }}
</div>
<div class="detection-form-content">
<!--第一步General Settings-->
<div class="detection-form-collapse">
<el-collapse v-model="activeNames">
<el-collapse-item name="1">
<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">{{ $t('detection.create.generalSettings') }}</div>
</div>
</template>
<div class="form-collapse-content">
<general-settings ref="form" :editObj="editObj" :isComplete="isCompleteSetting" @setSettingForm="getFormSetting" />
</div>
</el-collapse-item>
</el-collapse>
</div>
<!--第二步Rule Definition-->
<div class="detection-form-collapse">
<el-collapse v-model="activeNames" class="rule-definition">
<el-collapse-item name="2">
<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">{{ $t('detection.create.ruleDefinition') }}</div>
</div>
</template>
<div class="form-collapse-content">
<rule-definition :settingObj="settingObj" :editObj="editObj" :isComplete="isCompleteRule" @setRuleObj="getRuleObj" />
</div>
</el-collapse-item>
</el-collapse>
</div>
<!--第三步Trigger-->
<div class="detection-form-collapse">
<el-collapse v-model="activeNames" class="policy-form-trigger">
<el-collapse-item name="3">
<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">{{ $t('detection.create.trigger') }}</div>
</div>
</template>
<div class="form-collapse-content margin-t-18">
<el-form v-if="language===EN" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<div class="trigger-block-item margin-b-10">
<div>At least</div>
<el-form-item prop="atLeast">
<el-input maxlength="5" size="small" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
<div>times within</div>
<el-form-item prop="interval" class="policy-form-item">
<el-input maxlength="5" size="small" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
<el-form-item prop="intervalVal" class="form-trigger__select">
<el-select v-model="triggerObj.intervalVal" placeholder=" " size="small" @change="resetEditFlag">
<el-option
v-for="item in intervalList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</div>
<div class="trigger-block-item">
<div>With the counter resetting after no activity for</div>
<el-form-item prop="resetInterval" class="policy-form-item">
<el-input maxlength="5" size="small" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
<el-form-item prop="resetIntervalVal" class="form-trigger__select">
<el-select v-model="triggerObj.resetIntervalVal" placeholder=" " size="small" @change="resetEditFlag">
<el-option
v-for="item in intervalList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</div>
</el-form>
<el-form v-if="language===ZH" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<div class="trigger-block-item margin-b-10">
<el-form-item prop="interval">
<el-input size="small" maxlength="5" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
<el-form-item prop="intervalVal" class="form-trigger__select">
<el-select size="small" v-model="triggerObj.intervalVal" placeholder=" " @change="resetEditFlag">
<el-option
v-for="item in intervalList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
内至少发生
<el-form-item prop="atLeast">
<el-input size="small" maxlength="5" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
</div>
<div class="trigger-block-item">
若连续
<el-form-item prop="resetInterval">
<el-input size="small" maxlength="5" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')" @input="resetEditFlag"></el-input>
</el-form-item>
<el-form-item prop="resetIntervalVal" class="form-trigger__select">
<el-select size="small" v-model="triggerObj.resetIntervalVal" placeholder=" " @change="resetEditFlag">
<el-option
v-for="item in intervalList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
不活跃将重置计数
</div>
</el-form>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
<div class="policy-form__footer">
<div class="policy-form__footer__btn">
<div class="btn1">
<el-button @click="cancel">{{ $t('overall.cancel') }}</el-button>
</div>
<el-button @click="createPolicy">{{ $t('overall.save') }}</el-button>
</div>
</div>
</div>
</template>
<script>
import GeneralSettings from '@/components/table/detection/GeneralSettings'
import RuleDefinition from '@/components/table/detection/RuleDefinition'
import { api } from '@/utils/api'
import axios from 'axios'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { getDurationsTimeByType, getTimeByDurations } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { storageKey, detectionUnitList, ZH, EN } from '@/utils/constants'
import { ElMessageBox } from 'element-plus'
export default {
name: 'DetectionForm',
data () {
const intervalValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.intervalVal)
if (obj && !obj.flag && obj.msg) {
callback(new Error(obj.msg))
} else {
callback()
}
}
const intervalValValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, this.triggerObj.intervalVal, value)
if (obj && !obj.flag && obj.msg) {
this.$refs.form3.validateField('interval')
callback()
} else {
callback()
}
}
const resetIntervalValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.resetIntervalVal)
if (obj && !obj.flag && obj.msg) {
callback(new Error(obj.msg))
} else {
callback()
}
}
const resetIntervalValValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, this.triggerObj.resetIntervalVal, value)
if (obj && !obj.flag && obj.msg) {
this.$refs.form3.validateField('resetInterval')
callback()
} else {
callback()
}
}
return {
activeNames: ['1'],
rules: {
atLeast: [
{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
}
],
interval: [
{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
},
{
validator: intervalValidator,
trigger: 'blur'
}
],
intervalVal: [
{
required: true,
message: this.$t('validate.required'),
trigger: 'change'
},
{
validator: intervalValValidator,
trigger: 'change'
}
],
resetInterval: [
{
required: true,
message: this.$t('validate.required'),
trigger: 'blur'
},
{
validator: resetIntervalValidator,
trigger: 'blur'
}
],
resetIntervalVal: [
{
required: true,
message: this.$t('validate.required'),
trigger: 'change'
},
{
validator: resetIntervalValValidator,
trigger: 'change'
}
]
},
intervalList: [],
editObj: {},
isCompleteSetting: true, // 参数完整标识默认完整照顾编辑模式false即不完整
isCompleteRule: true, // 参数完整标识默认完整照顾编辑模式false即不完整
language: EN,
ZH,
EN
}
},
components: {
GeneralSettings,
RuleDefinition,
Loading
},
mounted () {
this.language = localStorage.getItem(storageKey.language) || EN
if (this.language === EN) {
this.intervalList = detectionUnitList.intervalList
} else if (this.language === ZH) {
this.intervalList = detectionUnitList.intervalListCN
}
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: '',
resetIntervalVal: '',
editFlag: false
})
return {
ruleId,
myLoading,
pageNoForTable,
settingObj,
ruleObj,
triggerObj
}
},
methods: {
/** 编辑时获取详情 */
getDetailInfo () {
if (this.ruleId) {
axios.get(`${api.detection.detail}/${this.ruleId}`).then(response => {
if (response.status === 200) {
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.resetIntervalVal = getTimeByDurations(this.triggerObj.resetInterval).type
this.triggerObj.resetInterval = getTimeByDurations(this.triggerObj.resetInterval).value
this.activeNames = ['1', '2', '3']
} else {
console.error(response.data)
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
this.$router.push({
path: '/detection/policy',
query: {
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
t: +new Date()
}
})
})
}
},
/** 获取General Settings折叠板form数据 */
getFormSetting (data) {
if (data.saveFlag) {
this.handleActiveNames('1', this.activeNames, data.settingNoContinue)
}
this.settingObj = JSON.parse(JSON.stringify(data))
},
/** 获取Rule Definition折叠板form数据 */
getRuleObj (data) {
if (data.dataSource && data.knowledgeId && data.level) {
data.editFlag = false
data.saveFlag = true
this.handleActiveNames('2', this.activeNames, data.ruleNoContinue)
}
this.ruleObj = JSON.parse(JSON.stringify(data))
},
/** 自动展开收起折叠板 */
handleActiveNames (name, arr, flag) {
if (!flag) {
const list = arr
list.splice(list.indexOf(name), 1)
if (name === '1' && list.indexOf('2') < 0) {
list.push('2')
}
if (name === '2' && list.indexOf('3') < 0) {
list.push('3')
}
this.activeNames = []
list.forEach(t => {
this.activeNames.push(t)
})
}
},
/** 创建policy */
createPolicy () {
const settingLen = Object.keys(this.settingObj).length
const ruleLen = Object.keys(this.ruleObj).length
if (settingLen > 0 && ruleLen > 0) {
this.$refs.form3.validate(valid => {
if (valid) {
// 最终提交form
const formObj = this.$_.cloneDeep({ ...this.settingObj, ruleConfig: JSON.stringify(this.ruleObj), ruleTrigger: this.triggerObj })
// 将时间转为参数所需如5分钟转为PT5M
formObj.ruleTrigger.resetInterval = getDurationsTimeByType(formObj.ruleTrigger.resetInterval, formObj.ruleTrigger.resetIntervalVal)
formObj.ruleTrigger.interval = getDurationsTimeByType(formObj.ruleTrigger.interval, formObj.ruleTrigger.intervalVal)
formObj.ruleTrigger.atLeast = parseInt(formObj.ruleTrigger.atLeast)
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')
})
this.$router.push({
path: '/detection/policy',
query: {
t: +new Date()
}
})
} else {
console.error(response.data.message)
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')
})
const { query } = this.$route
const queryInfo = {
pageNo: self.pageNoForTable ? Number(self.pageNoForTable) : 1,
t: +new Date()
}
if (query.name && query.id) {
queryInfo.ruleId = query.id
queryInfo.name = this.settingObj.name
}
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
} else {
console.error(response.data.message)
this.$message.error(this.errorMsgHandler(response))
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
}).finally(() => {
this.myLoading = false
})
}
} else {
this.isCompleteSetting = false
this.isCompleteRule = false
}
})
} else if (settingLen === 0) {
this.isCompleteSetting = false
this.handleFormError('1')
} else if (ruleLen === 0) {
this.isCompleteRule = false
this.handleFormError('2')
}
},
handleFormError (name) {
const list = this.activeNames
if (list.indexOf(name) < 0) {
list.push(name)
this.activeNames = []
list.forEach(t => {
this.activeNames.push(t)
})
}
this.$message.error(this.$t('detection.create.informationFilled'))
},
handleIntervalByDateType (rule, value, type) {
if (value && (type === 'hours' || type === '小时')) {
if (parseInt(value) <= 24) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeHours') }
}
}
if (value && (type === 'minutes' || type === '分钟')) {
if (parseInt(value) <= 1440) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeMinutes') }
}
}
if (value && (type === 'seconds' || type === '秒')) {
if (parseInt(value) <= 86400) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeSeconds') }
}
}
},
cancel () {
const { query } = this.$route
const queryInfo = {
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
t: +new Date()
}
if (query.name && query.id) {
queryInfo.ruleId = query.id
queryInfo.name = this.settingObj.name
}
if (this.settingObj.editFlag || this.ruleObj.editFlag || this.triggerObj.editFlag) {
// if (this.settingObj.editFlag) {
// this.isCompleteSetting = false
// this.handleFormError('1')
// }
// if (this.ruleObj.editFlag) {
// this.isCompleteRule = false
// this.handleFormError('2')
// }
if (this.triggerObj.editFlag) {
this.$refs.form3.validate(valid => {
if (!valid) {
this.confirmMessage(queryInfo)
} else {
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
}
})
} else {
this.confirmMessage(queryInfo)
}
} else {
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
}
},
confirmMessage (queryInfo) {
ElMessageBox.confirm(this.$t('tip.leavePage'), {
confirmButtonText: this.$t('tip.confirm'),
cancelButtonText: this.$t('overall.cancel'),
message: this.$t('tip.leavePageTips'),
title: this.$t('tip.leavePage'),
// type: 'warning',
iconClass: 'width:0px;height:0px;',
customClass: 'del-model'
}).then(() => {
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
}).catch(() => {})
},
resetEditFlag () {
this.triggerObj.editFlag = true
}
}
}
</script>