fix: 修复实体搜索框如下问题:1.模糊搜索与精准搜索并列时报错,以及搜索value包含and导致搜索异常;2.tag模式清除搜索条件后,转text模式又恢复;3.tag模式下has右括号是全角;4.点击左侧tag条件时,搜索语句应是has;5.tag模式下,多个条件且其中一个为全文检索时,全文检索在请求参数中丢失。

This commit is contained in:
刘洪洪
2023-08-29 19:12:49 +08:00
parent 778dd21b3a
commit 7f94254a8a
3 changed files with 107 additions and 22 deletions

View File

@@ -31,7 +31,7 @@
</div>
<span v-if="!meta.column.isEditing && meta.operator.value !== 'has'" @click="columnClick(meta)">{{meta.column.label}}</span>
<!--操作符是has时has需前置-->
<span v-else class="condition__operator">{{ meta.operator.value.toUpperCase() }}</span>
<span v-else class="condition__operator">{{ meta.operator.value }}</span>
</div>
<!-- 已选操作符显示 -->
<div class="condition__operator" @click="operatorClick(meta)" v-if="meta.operator.show && meta.operator.value !== 'has'">{{meta.operator.value}}</div>
@@ -44,7 +44,7 @@
</div>
<span v-else @click="valueClick(meta)">{{meta.value.label}}</span>
</div>
<div v-if="meta.operator.show && meta.operator.value === 'has'">)</div>
<div class="condition__value" v-if="meta.operator.show && meta.operator.value === 'has'">)</div>
<!-- 操作符选择器 -->
<div class="condition__operation-select" v-if="meta.operator.show && meta.operator.isEditing">
@@ -446,6 +446,9 @@ export default {
},
cleanMetaList () {
this.metaList = []
const routeQuery = this.$route.query
delete routeQuery.q
this.reloadUrl(routeQuery, 'cleanOldParams')
}
},
mounted () {

View File

@@ -3,6 +3,7 @@ import Token, { types } from './token'
import ParserError, { errorTypes, errorDesc } from '@/components/advancedSearch/meta/error'
import _ from 'lodash'
import { columnList } from '@/utils/static-data'
import { getEntityTypeByValue } from '@/utils/tools'
const strReg = {
all: /^[\da-zA-Z\s.'><!=-_(),%]$/,
@@ -789,6 +790,16 @@ export function handleOperatorSpace (operator) {
* @returns {string|*}
*/
export function handleMetaListToStr (metaList) {
// 将模糊搜索的值转换为对应类型如1.1.1.1,则添加操作符,类型等,以便于后面的操作
metaList.forEach(item => {
if (item.column.type === 'fullText') {
item.operator.value = '='
item.value.value = item.column.label
item.value.label = item.column.label
item.column.label = getEntityTypeByValue(item.column.label)
item.column.type = 'string'
}
})
// 长度为1时即模糊搜索例如搜索框值为1.1.1.1则直接返回1.1.1.1
// 如果为IP='1.1.1.1'的情况则从metaList拼接成IP='1.1.1.1'返回出去
if (metaList && metaList.length === 1) {

View File

@@ -1411,6 +1411,7 @@ export function comparedEntityKey (str) {
// 判断是否包含=或者in
const keyEqual = item.substring(0, item.indexOf('='))
const keyIn = item.substring(0, item.indexOf(' IN '))
const keyLike = item.substring(0, item.indexOf(' LIKE '))
let keyHas // 目前只有Tag操作符为has函数避免以后会增加其他实体使用has故不单独将has作为tag使用
let objHas
@@ -1421,10 +1422,13 @@ export function comparedEntityKey (str) {
const objEqual = columnList.find(t => t.label.toLowerCase() === keyEqual.toLowerCase())
const objIn = columnList.find(t => t.label.toLowerCase() === keyIn.toLowerCase())
const objLike = columnList.find(t => t.label.toLowerCase() === keyLike.toLowerCase())
if (objEqual) {
newQ += objEqual.label + item.substring(item.indexOf('='), item.length) + ' AND '
} else if (objIn) {
newQ += objIn.label + item.substring(item.indexOf(' IN '), item.length) + ' AND '
} else if (objLike) {
newQ += objLike.label + item.substring(item.indexOf(' LIKE '), item.length) + ' AND '
} else if (objHas) {
newQ += item.substring(item.indexOf(' has'), item.length) + ' AND '
} else {
@@ -1494,9 +1498,51 @@ export const handleEntityTypeByStr = (str) => {
}
// 检查str字段在arr中是否出现,true为出现过
const result = arr.some(item => newStr.includes(item))
if (result) {
if (newStr.indexOf(' and ') > -1) {
// 将单引号包裹的and拿出来放到数组tempList里原来的单引号包裹内容用temp即'it is test keyword{键值}'代替
// 再将字符串用and转换为数组遍历数组发现值为temp的获取键值根据键值获取tempList的值组合起来
// 最后将键值删除,后续再多次测试验证
const tempList = []
const regex = /'([^']*?)'/g
let match
// 将单引号包裹的and内容集合起来
while ((match = regex.exec(str)) !== null) {
if (match[1].includes('and')) {
tempList.push(match[1])
}
}
// 将单引号包裹的and内容用特殊值代替
tempList.forEach((item, index) => {
const regex = new RegExp(item, 'g')
str = str.replace(regex, `it is test keyword${index}`)
})
const noAndList = str.split(' and ')
noAndList.forEach((item, index) => {
// 发现插入的特殊值,获取键值,根据键值替换成原来内容,删除键值
if (item.indexOf('it is test keyword') > -1) {
const regex = /\d+/g
const result1 = item.match(regex)
noAndList[index] = noAndList[index].replace(result1[0], '')
noAndList[index] = noAndList[index].replace('it is test keyword', tempList[result1[0]])
}
})
const newArr = noAndList
newArr.forEach((item, index) => {
if (!arr.some(ite => item.includes(ite))) {
// item = checkFormatByStr(item)
newArr[index] = checkFormatByStr(item)
}
})
str = newArr.join(' and ')
return str
} else {
} else if (result) {
return str
} else if (!result) {
const regex = /^["']|["']$/
// 去除两侧引号,如'1.1.1.1',避免校验时被当作app
if (regex.test(str)) {
@@ -1504,6 +1550,13 @@ export const handleEntityTypeByStr = (str) => {
}
}
return checkFormatByStr(str)
}
}
/**
* 校验字符串格式如ip、domain、app
*/
const checkFormatByStr = (str) => {
// ipv4校验
const regexIPv4 = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
// ipv6校验
@@ -1523,6 +1576,24 @@ export const handleEntityTypeByStr = (str) => {
return `${obj.label} LIKE '%${str}%'`
}
}
export const getEntityTypeByValue = (str) => {
// ipv4校验
const regexIPv4 = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
// ipv6校验
const regexIPv6 = /^(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,7}:|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?:(?::[0-9A-Fa-f]{1,4}){1,6})|:(?:(?::[0-9A-Fa-f]{1,4}){1,7}|:)|fe80:(?::[0-9A-Fa-f]{0,4}){0,4}%\w+|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:2[0-4]|1\d|[1-9])?\d|25[0-5])\.(?:(?:2[0-4]|1\d|[1-9])?\d|25[0-5])\.(?:(?:2[0-4]|1\d|[1-9])?\d|25[0-5])\.(?:(?:2[0-4]|1\d|[1-9])?\d|25[0-5])|(?:[0-9A-Fa-f]{1,4}:){1,4}:192\.88\.99\.(\d{1,3})|(?:[0-9A-Fa-f]{1,4}:){1,4}:192\.0\.2\.(\d{1,3})|(?:[0-9A-Fa-f]{1,4}:){1,4}:(?:[0-9A-Fa-f]{1,4}:){0,1}192\.0\.0\.(\d{1,3})|ff00:(?::[0-9A-Fa-f]{0,4}){0,4}|(?:[0-9A-Fa-f]{1,4}:){1,4}:255\.255\.255\.255)$/
// domain校验
const reg = /^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*$/
if (regexIPv4.test(str) || regexIPv6.test(str)) {
const obj = columnList.find(t => t.label.toLowerCase() === 'ip')
return obj.label
} else if (reg.test(str)) {
const obj = columnList.find(t => t.label.toLowerCase() === 'domain')
return obj.label
} else {
const obj = columnList.find(t => t.label.toLowerCase() === 'app')
return obj.label
}
}
/**
* 将字符串的同属性字段合并在一起
@@ -1620,7 +1691,7 @@ const combineLabel1 = (list) => {
* @param str
*/
const checkStrIncludeAnd = (str) => {
const arr = str.split(' AND ')
const arr = str.split(' and ')
let label = ''
arr.forEach((item, index) => {