diff --git a/src/components/advancedSearch/Index.vue b/src/components/advancedSearch/Index.vue index b72b2720..0b166ff5 100644 --- a/src/components/advancedSearch/Index.vue +++ b/src/components/advancedSearch/Index.vue @@ -115,11 +115,11 @@ export default { }, setup (props) { // 默认为文本模式 - let searchMode = ref('text') + const searchMode = ref('text') if (props.defaultMode) { switch (props.defaultMode) { case 'tag': { - searchMode = 'tag' + searchMode.value = 'tag' break } } diff --git a/src/components/advancedSearch/TagMode.vue b/src/components/advancedSearch/TagMode.vue index 534bd662..94e15c1e 100644 --- a/src/components/advancedSearch/TagMode.vue +++ b/src/components/advancedSearch/TagMode.vue @@ -93,6 +93,7 @@ import Meta, { connection, condition, columnType } from './meta/meta' import _ from 'lodash' import { handleErrorTip } from '@/components/advancedSearch/meta/error' import Parser, { stringInQuot } from '@/components/advancedSearch/meta/parser' +import { overwriteUrl, urlParamsHandler } from '@/utils/tools' export default { name: 'TagMode', props: { @@ -320,8 +321,10 @@ export default { const parser = new Parser(this.columnList) const errorList = parser.validateMeta(this.metaList) if (_.isEmpty(errorList)) { + this.reloadUrl({ mode: 'text' }) this.$emit('changeMode', 'text', parser.parseMeta(this.metaList)) } else { + this.reloadUrl({ mode: 'text' }) this.$emit('changeMode', 'text', { metaList: [], str: '' }) } }, @@ -397,10 +400,28 @@ export default { this.metaList.splice(metaIndex, 2) } }) + }, + /** + * 向地址栏添加/删除参数 + */ + reloadUrl (newParam, clean) { + const { query } = this.$route + let newUrl = urlParamsHandler(window.location.href, query, newParam) + if (clean) { + newUrl = urlParamsHandler(window.location.href, query, newParam, clean) + } + overwriteUrl(newUrl) } }, mounted () { const vm = this + // 如果地址栏包含参数q,则匹配出metaList到搜索栏回显使用 + const { q } = this.$route.query + if (q) { + const parser = new Parser(this.columnList) + this.metaList = parser.parseStr(q).metaList + } + this.emitter.on('advanced-search', function () { vm.search() }) diff --git a/src/components/advancedSearch/TextMode.vue b/src/components/advancedSearch/TextMode.vue index 1a98deb9..700fd165 100644 --- a/src/components/advancedSearch/TextMode.vue +++ b/src/components/advancedSearch/TextMode.vue @@ -28,6 +28,7 @@ import { toRaw } from 'vue' import _ from 'lodash' import { columnType } from '@/components/advancedSearch/meta/meta' import { handleErrorTip } from '@/components/advancedSearch/meta/error' +import { overwriteUrl, urlParamsHandler } from '@/utils/tools' export default { name: 'TextMode', @@ -81,11 +82,14 @@ export default { const errorList = parser.validateStr(str) if (_.isEmpty(errorList)) { const metaList = parser.parseStr(str) + this.reloadUrl({ mode: 'tag' }) this.$emit('changeMode', 'tag', metaList) } else { + this.reloadUrl({ mode: 'tag' }) this.$emit('changeMode', 'tag', { metaList: [], str: '' }) } } else { + this.reloadUrl({ mode: 'tag' }) this.$emit('changeMode', 'tag', { str: '', metaList: [] }) } }, @@ -135,6 +139,17 @@ export default { current = current.replace(oldSqlPiece, newSqlPiece) }) toRaw(this.codeMirror).setValue(current.trim()) + }, + /** + * 向地址栏添加/删除参数 + */ + reloadUrl (newParam, clean) { + const { query } = this.$route + let newUrl = urlParamsHandler(window.location.href, query, newParam) + if (clean) { + newUrl = urlParamsHandler(window.location.href, query, newParam, clean) + } + overwriteUrl(newUrl) } }, watch: { @@ -150,7 +165,13 @@ export default { } }, mounted () { + // 如果地址栏包含参数q,则将参数q回显到搜索栏内 + const { q } = this.$route.query this.initCodeMirror() + if (q) { + toRaw(this.codeMirror).setValue(q) + } + const vm = this this.emitter.on('advanced-search', function () { vm.search() diff --git a/src/utils/static-data.js b/src/utils/static-data.js index 83b779d1..a390ecc2 100644 --- a/src/utils/static-data.js +++ b/src/utils/static-data.js @@ -270,3 +270,191 @@ export const dataForNpmNetworkQuantity = { { name: 'overall.packetRetrans' } ] } +export const columnList = [ + { + name: 'entity_type', + type: 'string', + label: 'Entity type' + }, + { + name: 'ip_addr', + type: 'string', + label: 'IP.Address' + }, + { + name: 'ip_location_country', + type: 'string', + label: 'IP.Country' + }, + { + name: 'ip_location_province', + type: 'string', + label: 'IP.Province' + }, + { + name: 'ip_location_city', + type: 'string', + label: 'IP.City' + }, + { + name: 'ip_asn', + type: 'string', + label: 'IP.ASN' + }, + { + name: 'dns_server_role', + type: 'string', + label: 'IP.DNS server role' + }, + { + name: 'dns_server_org', + type: 'string', + label: 'IP.DNS server organization' + }, + { + name: 'dns_server_os', + type: 'string', + label: 'IP.Operating system' + }, + { + name: 'dns_server_software', + type: 'string', + label: 'IP.DNS server software' + }, + { + name: 'domain_name', + type: 'string', + label: 'Domain.Name' + }, + { + name: 'domain_category', + type: 'string', + label: 'Domain.Category' + }, + { + name: 'domain_category_group', + type: 'string', + label: 'Domain.Category group' + }, + { + name: 'domain_reputation_level', + type: 'string', + label: 'Domain.Reputation' + }, + { + name: 'domain_whois_email', + type: 'string', + label: 'Domain.Whois email' + }, + { + name: 'domain_whois_name_servers', + type: 'string', + label: 'Domain.Whois nameserver' + }, + { + name: 'domain_whois_registrar', + type: 'string', + label: 'Domain.Whois registrar' + }, + { + name: 'domain_whois_org', + type: 'string', + label: 'Domain.Whois organization' + }, + { + name: 'domain_whois_address', + type: 'string', + label: 'Domain.Whois address' + }, + { + name: 'domain_whois_city', + type: 'string', + label: 'Domain.Whois city' + }, + { + name: 'domain_whois_state', + type: 'string', + label: 'Domain.Whois state' + }, + { + name: 'domain_whois_country', + type: 'string', + label: 'Domain.Whois country' + }, + { + name: 'domain_icp_owner', + type: 'string', + label: 'Domain.ICP owner' + }, + { + name: 'domain_icp_company_name', + type: 'string', + label: 'Domain.ICP company' + }, + { + name: 'domain_icp_company_type', + type: 'string', + label: 'Domain.ICP company type' + }, + { + name: 'domain_icp_site_license', + type: 'string', + label: 'Domain.ICP site license' + }, + { + name: 'domain_icp_site_name', + type: 'string', + label: 'Domain.ICP site' + }, + { + name: 'app_name', + type: 'string', + label: 'APP.Name' + }, + { + name: 'app_id', + type: 'string', + label: 'APP.ID' + }, + { + name: 'app_category', + type: 'string', + label: 'APP.Category' + }, + { + name: 'app_subcategory', + type: 'string', + label: 'APP.Subcategory' + }, + { + name: 'app_risk', + type: 'string', + label: 'APP.Risk' + }, + { + name: 'app_description', + type: 'string', + label: 'APP.Description' + }, + { + name: 'app_longname', + type: 'string', + label: 'APP.Long name' + }, + { + name: 'app_technology', + type: 'string', + label: 'APP.Technology' + } +] +export const operatorList = ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE'] +export const connectionList = [ + { + value: 'AND', + label: 'AND' + }, + { + value: 'OR', + label: 'OR' + } +] diff --git a/src/views/entityExplorer/EntityExplorer.vue b/src/views/entityExplorer/EntityExplorer.vue index b83bdd68..8eda8dec 100644 --- a/src/views/entityExplorer/EntityExplorer.vue +++ b/src/views/entityExplorer/EntityExplorer.vue @@ -18,8 +18,8 @@ - - + + @@ -161,6 +161,11 @@ import { getNowTime, getSecond } from '@/utils/date-util' import { ref } from 'vue' import _ from 'lodash' import Loading from '@/components/common/Loading' +import { overwriteUrl, urlParamsHandler } from '@/utils/tools' +import Parser from '@/components/advancedSearch/meta/parser' +import { handleErrorTip } from '@/components/advancedSearch/meta/error' +import { columnList } from '@/utils/static-data' +import { useRoute } from 'vue-router' export default { name: 'entity-explorer', @@ -428,8 +433,32 @@ export default { this.metaList = [] } + // 在非列表模式下选择tag模式,在地址栏输入内容时将mode添加到地址栏 + const mode = this.$route.query.mode || 'text' + + this.reloadUrl({ + listMode: this.listMode, + q: q, + mode: mode, + startTime: getSecond(this.timeFilter.startTime), + endTime: getSecond(this.timeFilter.endTime) + }) + if (!this.showList) { + // 首页进入搜索时重载页面,视觉上进入列表页面 + this.$router.push({ + path: '/entityExplorer', + query: { + listMode: this.listMode, + q: q, + mode: mode, + startTime: getSecond(this.timeFilter.startTime), + endTime: getSecond(this.timeFilter.endTime) + } + }) this.showList = true + // 跳转页面,则不执行搜索功能 + return true } if (this.pageObj.resetPageNo) { this.pageObj.pageNo = 1 @@ -725,20 +754,80 @@ export default { d.value = 0 }) this.filterData[index].totalCount = 0 + }, + setListMode (mode) { + this.listMode = mode + const newParam = { + listMode: mode + } + this.reloadUrl(newParam) + }, + /** + * 向地址栏添加/删除参数 + */ + reloadUrl (newParam, clean) { + const { query } = this.$route + let newUrl = urlParamsHandler(window.location.href, query, newParam) + if (clean) { + newUrl = urlParamsHandler(window.location.href, query, newParam, clean) + } + overwriteUrl(newUrl) + }, + /** + * 初始化搜索,分享url或者刷新界面,保留本次搜索结果 + * @param q + */ + initSearch (q) { + const str = q + // 此处的mode不做text和tag区分,是因为text和tag构造搜索参数过程不一样,但结果的参数一致 + // 故采用text的参数形式进行搜索,tag形式在tagMode.vue的mounted里根据地址栏的参数q构造metaList + if (str) { + const parser = new Parser(columnList) + const errorList = parser.validateStr(str) + if (_.isEmpty(errorList)) { + this.search(parser.parseStr(str)) + } else { + this.$message.error(handleErrorTip(errorList[0])) + } + } else { + this.search({ q: '', str: '', metaList: [] }) + } } }, mounted () { this.getEntityIndexData() + const { q, listMode } = this.$route.query + + // 如果地址栏有listMode,即列表页,并非首页,则开始搜索 + if (listMode) { + this.showList = true + this.initSearch(q) + this.listMode = listMode + } }, watch: { - timeFilter (n) { + timeFilter () { this.search({ metaList: this.metaList, q: this.q }) } }, setup () { - const dateRangeValue = 60 - const { startTime, endTime } = getNowTime(dateRangeValue) - const timeFilter = ref({ startTime, endTime, dateRangeValue }) + const { query } = useRoute() + // 获取url携带的range、startTime、endTime + const rangeParam = query.range + const startTimeParam = query.startTime + const endTimeParam = query.endTime + // 若url携带了,使用携带的值,否则使用默认值。 + const dateRangeValue = rangeParam ? parseInt(query.range) : 60 + const timeFilter = ref({ dateRangeValue }) + if (!startTimeParam || !endTimeParam) { + const { startTime, endTime } = getNowTime(60) + timeFilter.value.startTime = startTime + timeFilter.value.endTime = endTime + } else { + timeFilter.value.startTime = parseInt(startTimeParam) + timeFilter.value.endTime = parseInt(endTimeParam) + } + timeFilter.value.dateRangeValue = 60 return { timeFilter } diff --git a/src/views/entityExplorer/search/ExplorerSearch.vue b/src/views/entityExplorer/search/ExplorerSearch.vue index df2aa6b9..b9d2a583 100644 --- a/src/views/entityExplorer/search/ExplorerSearch.vue +++ b/src/views/entityExplorer/search/ExplorerSearch.vue @@ -10,6 +10,7 @@ :column-list="columnList" :operator-list="operatorList" :connection-list="connectionList" + :default-mode="defaultMode" :full-text="true" :class="{'advanced-search--show-list': showList}" @search="search" @@ -51,6 +52,9 @@ import AdvancedSearch from '@/components/advancedSearch/Index' import _ from 'lodash' import { storageKey } from '@/utils/constants' +import { useRoute } from 'vue-router' +import { ref } from 'vue' +import { columnList } from '@/utils/static-data' export default { name: 'CnSearch', components: { @@ -64,183 +68,7 @@ export default { }, data () { return { - columnList: [ - { - name: 'entity_type', - type: 'string', - label: 'Entity type' - }, - { - name: 'ip_addr', - type: 'string', - label: 'IP.Address' - }, - { - name: 'ip_location_country', - type: 'string', - label: 'IP.Country' - }, - { - name: 'ip_location_province', - type: 'string', - label: 'IP.Province' - }, - { - name: 'ip_location_city', - type: 'string', - label: 'IP.City' - }, - { - name: 'ip_asn', - type: 'string', - label: 'IP.ASN' - }, - { - name: 'dns_server_role', - type: 'string', - label: 'IP.DNS server role' - }, - { - name: 'dns_server_org', - type: 'string', - label: 'IP.DNS server organization' - }, - { - name: 'dns_server_os', - type: 'string', - label: 'IP.Operating system' - }, - { - name: 'dns_server_software', - type: 'string', - label: 'IP.DNS server software' - }, - { - name: 'domain_name', - type: 'string', - label: 'Domain.Name' - }, - { - name: 'domain_category', - type: 'string', - label: 'Domain.Category' - }, - { - name: 'domain_category_group', - type: 'string', - label: 'Domain.Category group' - }, - { - name: 'domain_reputation_level', - type: 'string', - label: 'Domain.Reputation' - }, - { - name: 'domain_whois_email', - type: 'string', - label: 'Domain.Whois email' - }, - { - name: 'domain_whois_name_servers', - type: 'string', - label: 'Domain.Whois nameserver' - }, - { - name: 'domain_whois_registrar', - type: 'string', - label: 'Domain.Whois registrar' - }, - { - name: 'domain_whois_org', - type: 'string', - label: 'Domain.Whois organization' - }, - { - name: 'domain_whois_address', - type: 'string', - label: 'Domain.Whois address' - }, - { - name: 'domain_whois_city', - type: 'string', - label: 'Domain.Whois city' - }, - { - name: 'domain_whois_state', - type: 'string', - label: 'Domain.Whois state' - }, - { - name: 'domain_whois_country', - type: 'string', - label: 'Domain.Whois country' - }, - { - name: 'domain_icp_owner', - type: 'string', - label: 'Domain.ICP owner' - }, - { - name: 'domain_icp_company_name', - type: 'string', - label: 'Domain.ICP company' - }, - { - name: 'domain_icp_company_type', - type: 'string', - label: 'Domain.ICP company type' - }, - { - name: 'domain_icp_site_license', - type: 'string', - label: 'Domain.ICP site license' - }, - { - name: 'domain_icp_site_name', - type: 'string', - label: 'Domain.ICP site' - }, - { - name: 'app_name', - type: 'string', - label: 'APP.Name' - }, - { - name: 'app_id', - type: 'string', - label: 'APP.ID' - }, - { - name: 'app_category', - type: 'string', - label: 'APP.Category' - }, - { - name: 'app_subcategory', - type: 'string', - label: 'APP.Subcategory' - }, - { - name: 'app_risk', - type: 'string', - label: 'APP.Risk' - }, - { - name: 'app_description', - type: 'string', - label: 'APP.Description' - }, - { - name: 'app_longname', - type: 'string', - label: 'APP.Long name' - }, - { - name: 'app_technology', - type: 'string', - label: 'APP.Technology' - } - ], + columnList: columnList, operatorList: ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE'], connectionList: [ { @@ -256,6 +84,14 @@ export default { history: [] } }, + setup () { + // 根据地址栏添加mode,即text和tag模式,默认text + const { query } = useRoute() + const defaultMode = ref(query.mode || 'text') + return { + defaultMode + } + }, methods: { search ({ str, q, metaList }) { if (str) {