diff --git a/src/components/advancedSearch/TagMode.vue b/src/components/advancedSearch/TagMode.vue index d086f32f..163053fa 100644 --- a/src/components/advancedSearch/TagMode.vue +++ b/src/components/advancedSearch/TagMode.vue @@ -40,7 +40,8 @@
({{meta.column.label}},
-
+ +
+ + +
+ + + + +
+
0) { + let str = '' + value.forEach(item => { + str += `'${item}',` + }) + str = str.substring(0, str.length - 1) + str = `(${str})` + meta.value.value = str + meta.value.label = str + } else { + meta.value.value = '' + } + }, selectConnection (value, meta) { meta.isEditing = false }, - columnClick (meta) { - meta.column.isEditing = true - this.$nextTick(() => { - this.$refs.columnSelect[this.$refs.columnSelect.length - 1].focus() - }) - }, columnBlur (meta, index) { setTimeout(() => { const parser = new Parser(this.columnList) @@ -276,27 +325,60 @@ export default { this.operatorList = obj ? obj.doc.constraints.operator_functions.split(',') : ['=', 'IN'] if (meta.column && meta.column.type === 'fullText') { meta.operator.value = '=' - meta.column.show = false + meta.column.show = true meta.column.isFullText = true - meta.operator.show = false + meta.operator.show = true const label = JSON.parse(JSON.stringify(meta.column.label)) meta.column.label = parser.getEntityTypeByValue(meta.column.label) meta.value.value = label meta.value.label = label - // if (meta.column.label === 'domain') { - // meta.operator.value = 'like' - // meta.value.value = `%${this.delSingleQuote(label)}` - // meta.value.label = `${this.delSingleQuote(label)}` - // } else if (meta.column.label === 'app') { - // meta.operator.value = 'like' - // meta.value.value = `%${this.delSingleQuote(label)}%` - // meta.value.label = `${this.delSingleQuote(label)}` - // } + if (meta.column.label === 'domain') { + meta.operator.value = 'like' + meta.value.value = `%${this.delSingleQuote(label)}` + meta.value.label = `%${this.delSingleQuote(label)}` + } else if (meta.column.label === 'app') { + meta.operator.value = 'like' + meta.value.value = `%${this.delSingleQuote(label)}%` + meta.value.label = `%${this.delSingleQuote(label)}%` + } meta.column.type = 'string' } }, 200) }, + valueBlur1 (meta) { + setTimeout(() => { + meta.value.isEditing = false + }, 200) + }, + valuesBlur (meta) { + this.$nextTick(() => { + }) + }, + valuesFocus (meta) { + this.$nextTick(() => { + meta.value.isEditing = true + setTimeout(() => { + if (meta.value.value && this.myCheckboxList.length === 0) { + let valueArr = [] + if (!_.isArray(meta.value.value)) { + let value = meta.value.value + if (value.indexOf('(') === 0 && value.indexOf(')') === value.length - 1) { + value = value.substring(1, value.length) + value = value.substring(0, value.length - 1) + } + valueArr = value.split(',') + valueArr.forEach((item, index) => { + if (item[0] === "'" && item[item.length - 1] === "'") { + item = item.substring(1, item.length - 1) + this.myCheckboxList.push(item) + } + }) + } + } + }, 100) + }) + }, connectionClick (meta) { meta.isEditing = true }, @@ -314,7 +396,7 @@ export default { // 若是in或not in,column的type要改成array,否则是string if (operator.toLowerCase().indexOf('in') > -1) { meta.column.type = columnType.array - meta.value.value = [] + // meta.value.value = [] } else if (['>', '<', '>=', '<='].indexOf(operator) > -1) { meta.column.type = columnType.number } else { @@ -480,10 +562,26 @@ export default { } meta.value.isEditing = !meta.isCompleteCondition() }, + columnClick (meta) { + meta.column.isEditing = true + this.$nextTick(() => { + this.$refs.columnSelect[this.$refs.columnSelect.length - 1].focus() + }) + }, valueClick (meta) { meta.value.isEditing = true + const obj = enumerateData.find(d => d.name === meta.column.label) + if (obj) { + meta.doc = obj + } this.$nextTick(() => { - this.$refs.valueInput[0].focus() + if (this.$refs.valueInput) { + this.$refs.valueInput[0].focus() + } + if (this.$refs.valuesSelect) { + // 触发focus后,select弹窗并没有生效 + this.$refs.valuesSelect[0].focus(meta) + } }) }, // 判断是否是用户自己添加的内容,用于判断是否是全局搜索 @@ -515,7 +613,8 @@ export default { const str = strObj.str ? strObj.str : strObj const str2 = strObj.str2 ? strObj.str2 : strObj // str为将metaList转成字符串的值,str2为地址栏展示的值 - const key = parser.handleEntityTypeByStr(str) + let key = parser.handleEntityTypeByStr(str) + key = parser.conversionEnum(key) this.$emit('search', { ...parser.parseStr(key), str: str2, keywordList: keywordList }) } else { this.$message.error(handleErrorTip(errorList[0])) diff --git a/src/components/advancedSearch/TextMode.vue b/src/components/advancedSearch/TextMode.vue index 451acb0d..59bfdc76 100644 --- a/src/components/advancedSearch/TextMode.vue +++ b/src/components/advancedSearch/TextMode.vue @@ -178,9 +178,13 @@ export default { } }) if (keyInfo.isKey) { - const errorList = parser.validateStr(keyInfo.key) + // 检查是否包含枚举字段,包含的话进行替换 + const enumKey = parser.conversionEnum(keyInfo.key) + const errorList = parser.validateStr(newKey) if (_.isEmpty(errorList)) { - this.$emit('search', { ...parser.parseStr(keyInfo.key), str: str, keywordList: keywordList }) + // 补全模糊搜索 + toRaw(this.codeMirror).setValue(parser.handleEntityTypeByStr(str)) + this.$emit('search', { ...parser.parseStr(enumKey), str: parser.handleEntityTypeByStr(str), keywordList: keywordList }) } else { this.$message.error(handleErrorTip(errorList[0])) } diff --git a/src/components/advancedSearch/meta/parser.js b/src/components/advancedSearch/meta/parser.js index 7650bbb4..16048c06 100644 --- a/src/components/advancedSearch/meta/parser.js +++ b/src/components/advancedSearch/meta/parser.js @@ -12,6 +12,7 @@ const strReg = { value: /^[\da-zA-Z\u4E00-\u9FA5\u3040-\u309F\u0800-\u4e00\u0400-\u04FF\u2000-\u206F\s.'-_%]$/ } const operatorList = ['=', ' in ', ' IN ', ' like ', ' LIKE ', 'HAS(', 'has('] +const enumList = ['status', 'eventType', 'severity'] export default class Parser { constructor (columnList) { @@ -1476,6 +1477,47 @@ export default class Parser { return this.columnList.find(t => t.label.toLowerCase() === label.toLowerCase()) } + + /** + * 检测str是否包含枚举字段,包含的话,进行替换 + * @param str + * @returns {string|*} + */ + conversionEnum (str) { + if (str) { + let enumFlag = false // 判断字符串是否包含枚举类型的key,不包含则直接返回 + enumList.forEach(item => { + if (str.toLocaleLowerCase().indexOf(item.toLocaleLowerCase()) > -1) { + enumFlag = true + } + }) + if (enumFlag) { + let key = _.cloneDeep(str) + let searchList = [] // 将字符串按AND分割成单独的搜索条件 + if (key.indexOf(' AND ') > -1) { + searchList = key.split(' AND ') + } else { + searchList = [key] + } + searchList.forEach((item, index) => { + const obj = this.columnList.find(d => item.indexOf(d.label) > -1) + if (obj && obj.doc.data) { + obj.doc.data.forEach(item1 => { + if (item.indexOf(item1.code) > -1) { + searchList[index] = searchList[index].replace(new RegExp(item1.code, 'g'), item1.value) + } + }) + } + }) + key = searchList.join(' AND ') + return key + } else { + return str + } + } else { + return str + } + } } // 使用单引号包裹 diff --git a/src/views/detections/DetectionFilter.vue b/src/views/detections/DetectionFilter.vue index 220ba96e..bacce05b 100644 --- a/src/views/detections/DetectionFilter.vue +++ b/src/views/detections/DetectionFilter.vue @@ -57,17 +57,17 @@ export default { 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) - } + // 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) diff --git a/src/views/detections/DetectionSearch.vue b/src/views/detections/DetectionSearch.vue index fb726a23..56c27b0f 100644 --- a/src/views/detections/DetectionSearch.vue +++ b/src/views/detections/DetectionSearch.vue @@ -181,7 +181,7 @@ export default { } localStorage.setItem(storageKey.detectionSearchHistory, JSON.stringify(arr)) } - this.$emit('search', { q, metaList }) + this.$emit('search', { q, metaList, str }) }, changeParams (params) { this.$refs.search.addParams(params) diff --git a/src/views/detections/Index.vue b/src/views/detections/Index.vue index 2d576be2..ac181e4f 100644 --- a/src/views/detections/Index.vue +++ b/src/views/detections/Index.vue @@ -140,6 +140,8 @@ import ChartTabs from '@/components/common/ChartTabs' import { useStore } from 'vuex' import { tooLongFormatter } from '@/views/charts/charts/tools' import { format } from 'echarts' +import Parser from '@/components/advancedSearch/meta/parser' +import { schemaDetectionSecurity } from '@/utils/static-data' export default { name: 'Index', @@ -763,11 +765,11 @@ export default { // 参数q,避免切换页码时,地址栏参数q为空 let urlQ = '' if (param && param.str) { - // urlQ = encodeURI(param.str) - urlQ = param.str + urlQ = param.str.indexOf('%') > -1 ? encodeURI(param.str) : param.str + this.str = param.str } else if (this.q) { // urlQ = encodeURI(this.q) - urlQ = this.q + urlQ = this.q.indexOf('%') > -1 ? encodeURI(this.q) : this.q } const mode = this.$route.query.mode || 'text' const newUrl = urlParamsHandler(window.location.href, this.$route.query, { @@ -778,8 +780,8 @@ export default { mode: mode }) overwriteUrl(newUrl) - this.queryFilter(urlQ) - this.queryList(urlQ) + this.queryFilter(this.q) + this.queryList(this.q) }, resetFilterData () { this.filterData.securityEvent.forEach(d => { @@ -921,10 +923,12 @@ export default { } // %位置不为0,即内容包含非英文时 const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3) - if (q && q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) { + if (q && q.indexOf('%') > 0 && (str1 === '%20' || str1 === '%25')) { q = decodeURI(q) } } + const parser = new Parser(schemaDetectionSecurity) + q = parser.conversionEnum(q) this.queryFilter(q) if (this.initFlag) { this.timer = setTimeout(() => { diff --git a/src/views/entityExplorer/EntityExplorer.vue b/src/views/entityExplorer/EntityExplorer.vue index 4c956650..3b43ce2f 100644 --- a/src/views/entityExplorer/EntityExplorer.vue +++ b/src/views/entityExplorer/EntityExplorer.vue @@ -282,6 +282,7 @@ export default { ], listData: [], q: '', + str: '', metaList: [], listLoading: false, // 实体详情搜索页面 底部列表 @@ -387,9 +388,12 @@ export default { // 参数q,避免切换页码时,地址栏参数q为空 let urlQ = '' if (param.str) { - urlQ = encodeURI(param.str) + // urlQ = encodeURI(param.str) + urlQ = param.str.indexOf('%') > -1 ? encodeURI(param.str) : param.str + this.str = param.str } else if (this.q) { - urlQ = encodeURI(this.q) + // urlQ = encodeURI(this.q) + urlQ = this.q.indexOf('%') > -1 ? encodeURI(this.q) : this.q } else if (!this.q) { this.isHideRelatedEntities = false } @@ -444,10 +448,10 @@ export default { const keywordList = this.getKeywordListByMetaList(this.metaList) if (this.initFlag) { if (val !== 20) { - this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList }) + this.search({ metaList: this.metaList, q: this.q, str: this.str, keywordList: keywordList }) } } else { - this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList }) + this.search({ metaList: this.metaList, q: this.q, str: this.str, keywordList: keywordList }) } }, pageNo (val) { @@ -455,7 +459,7 @@ export default { this.pageObj.pageNo = val this.pageObj.resetPageNo = false const keywordList = this.getKeywordListByMetaList(this.metaList) - this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList }) + this.search({ metaList: this.metaList, q: this.q, str: this.str, keywordList: keywordList }) } }, // 点击上一页箭头 @@ -827,6 +831,8 @@ export default { if (q && q.indexOf('%') > 0 && (str1 === '%20' || str1 === '%25')) { q = decodeURI(q) } + const parser = new Parser(columnList) + q = parser.conversionEnum(q) this.initSearch(q) this.listMode = listMode // 查询评分基准 @@ -840,7 +846,7 @@ export default { }, watch: { timeFilter () { - this.search({ metaList: this.metaList, q: this.q }) + this.search({ metaList: this.metaList, q: this.q, str: this.str }) } }, setup () {