fix: 修复实体搜索框如下问题:1.模糊搜索与精准搜索并列时报错,以及搜索value包含and导致搜索异常;2.tag模式清除搜索条件后,转text模式又恢复;3.tag模式下has右括号是全角;4.点击左侧tag条件时,搜索语句应是has;5.tag模式下,多个条件且其中一个为全文检索时,全文检索在请求参数中丢失。
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span v-if="!meta.column.isEditing && meta.operator.value !== 'has'" @click="columnClick(meta)">{{meta.column.label}}</span>
|
<span v-if="!meta.column.isEditing && meta.operator.value !== 'has'" @click="columnClick(meta)">{{meta.column.label}}</span>
|
||||||
<!--操作符是has时,has需前置-->
|
<!--操作符是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>
|
||||||
<!-- 已选操作符显示 -->
|
<!-- 已选操作符显示 -->
|
||||||
<div class="condition__operator" @click="operatorClick(meta)" v-if="meta.operator.show && meta.operator.value !== 'has'">{{meta.operator.value}}</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>
|
</div>
|
||||||
<span v-else @click="valueClick(meta)">{{meta.value.label}}</span>
|
<span v-else @click="valueClick(meta)">{{meta.value.label}}</span>
|
||||||
</div>
|
</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">
|
<div class="condition__operation-select" v-if="meta.operator.show && meta.operator.isEditing">
|
||||||
@@ -446,6 +446,9 @@ export default {
|
|||||||
},
|
},
|
||||||
cleanMetaList () {
|
cleanMetaList () {
|
||||||
this.metaList = []
|
this.metaList = []
|
||||||
|
const routeQuery = this.$route.query
|
||||||
|
delete routeQuery.q
|
||||||
|
this.reloadUrl(routeQuery, 'cleanOldParams')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Token, { types } from './token'
|
|||||||
import ParserError, { errorTypes, errorDesc } from '@/components/advancedSearch/meta/error'
|
import ParserError, { errorTypes, errorDesc } from '@/components/advancedSearch/meta/error'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { columnList } from '@/utils/static-data'
|
import { columnList } from '@/utils/static-data'
|
||||||
|
import { getEntityTypeByValue } from '@/utils/tools'
|
||||||
|
|
||||||
const strReg = {
|
const strReg = {
|
||||||
all: /^[\da-zA-Z\s.'><!=-_(),%]$/,
|
all: /^[\da-zA-Z\s.'><!=-_(),%]$/,
|
||||||
@@ -789,6 +790,16 @@ export function handleOperatorSpace (operator) {
|
|||||||
* @returns {string|*}
|
* @returns {string|*}
|
||||||
*/
|
*/
|
||||||
export function handleMetaListToStr (metaList) {
|
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
|
// 长度为1时,即模糊搜索,例如搜索框值为1.1.1.1,则直接返回1.1.1.1
|
||||||
// 如果为IP='1.1.1.1'的情况,则从metaList拼接成IP='1.1.1.1'返回出去
|
// 如果为IP='1.1.1.1'的情况,则从metaList拼接成IP='1.1.1.1'返回出去
|
||||||
if (metaList && metaList.length === 1) {
|
if (metaList && metaList.length === 1) {
|
||||||
|
|||||||
@@ -1411,6 +1411,7 @@ export function comparedEntityKey (str) {
|
|||||||
// 判断是否包含=或者in
|
// 判断是否包含=或者in
|
||||||
const keyEqual = item.substring(0, item.indexOf('='))
|
const keyEqual = item.substring(0, item.indexOf('='))
|
||||||
const keyIn = item.substring(0, item.indexOf(' IN '))
|
const keyIn = item.substring(0, item.indexOf(' IN '))
|
||||||
|
const keyLike = item.substring(0, item.indexOf(' LIKE '))
|
||||||
|
|
||||||
let keyHas // 目前只有Tag操作符为has函数,避免以后会增加其他实体使用has,故不单独将has作为tag使用
|
let keyHas // 目前只有Tag操作符为has函数,避免以后会增加其他实体使用has,故不单独将has作为tag使用
|
||||||
let objHas
|
let objHas
|
||||||
@@ -1421,10 +1422,13 @@ export function comparedEntityKey (str) {
|
|||||||
|
|
||||||
const objEqual = columnList.find(t => t.label.toLowerCase() === keyEqual.toLowerCase())
|
const objEqual = columnList.find(t => t.label.toLowerCase() === keyEqual.toLowerCase())
|
||||||
const objIn = columnList.find(t => t.label.toLowerCase() === keyIn.toLowerCase())
|
const objIn = columnList.find(t => t.label.toLowerCase() === keyIn.toLowerCase())
|
||||||
|
const objLike = columnList.find(t => t.label.toLowerCase() === keyLike.toLowerCase())
|
||||||
if (objEqual) {
|
if (objEqual) {
|
||||||
newQ += objEqual.label + item.substring(item.indexOf('='), item.length) + ' AND '
|
newQ += objEqual.label + item.substring(item.indexOf('='), item.length) + ' AND '
|
||||||
} else if (objIn) {
|
} else if (objIn) {
|
||||||
newQ += objIn.label + item.substring(item.indexOf(' IN '), item.length) + ' AND '
|
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) {
|
} else if (objHas) {
|
||||||
newQ += item.substring(item.indexOf(' has'), item.length) + ' AND '
|
newQ += item.substring(item.indexOf(' has'), item.length) + ' AND '
|
||||||
} else {
|
} else {
|
||||||
@@ -1494,9 +1498,51 @@ export const handleEntityTypeByStr = (str) => {
|
|||||||
}
|
}
|
||||||
// 检查str字段在arr中是否出现,true为出现过
|
// 检查str字段在arr中是否出现,true为出现过
|
||||||
const result = arr.some(item => newStr.includes(item))
|
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
|
return str
|
||||||
} else {
|
} else if (result) {
|
||||||
|
return str
|
||||||
|
} else if (!result) {
|
||||||
const regex = /^["']|["']$/
|
const regex = /^["']|["']$/
|
||||||
// 去除两侧引号,如'1.1.1.1',避免校验时被当作app
|
// 去除两侧引号,如'1.1.1.1',避免校验时被当作app
|
||||||
if (regex.test(str)) {
|
if (regex.test(str)) {
|
||||||
@@ -1504,24 +1550,49 @@ export const handleEntityTypeByStr = (str) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipv4校验
|
return checkFormatByStr(str)
|
||||||
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校验
|
* 校验字符串格式,如ip、domain、app
|
||||||
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+)*$/
|
*/
|
||||||
|
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校验
|
||||||
|
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)) {
|
if (regexIPv4.test(str) || regexIPv6.test(str)) {
|
||||||
const obj = columnList.find(t => t.label.toLowerCase() === 'ip')
|
const obj = columnList.find(t => t.label.toLowerCase() === 'ip')
|
||||||
return `${obj.label}='${str}'`
|
return `${obj.label}='${str}'`
|
||||||
} else if (reg.test(str)) {
|
} else if (reg.test(str)) {
|
||||||
// 只写作domain即可,schema字段更改几次,避免后续再更改,直接拿columnList的label进行替换
|
// 只写作domain即可,schema字段更改几次,避免后续再更改,直接拿columnList的label进行替换
|
||||||
const obj = columnList.find(t => t.label.toLowerCase() === 'domain')
|
const obj = columnList.find(t => t.label.toLowerCase() === 'domain')
|
||||||
return `${obj.label} LIKE '%${str}'`
|
return `${obj.label} LIKE '%${str}'`
|
||||||
} else {
|
} else {
|
||||||
const obj = columnList.find(t => t.label.toLowerCase() === 'app')
|
const obj = columnList.find(t => t.label.toLowerCase() === 'app')
|
||||||
return `${obj.label} LIKE '%${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
|
* @param str
|
||||||
*/
|
*/
|
||||||
const checkStrIncludeAnd = (str) => {
|
const checkStrIncludeAnd = (str) => {
|
||||||
const arr = str.split(' AND ')
|
const arr = str.split(' and ')
|
||||||
let label = ''
|
let label = ''
|
||||||
|
|
||||||
arr.forEach((item, index) => {
|
arr.forEach((item, index) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user