NEZ-1514 feat: 全局搜索功能开发(50%)

This commit is contained in:
zhangyu
2022-01-14 18:04:34 +08:00
parent 3622b68c60
commit 678b45583a
8 changed files with 514 additions and 10 deletions

View File

@@ -2493,6 +2493,14 @@
}
}
},
"clone-regexp": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
"integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
"requires": {
"is-regexp": "^2.0.0"
}
},
"clone-response": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
@@ -4497,6 +4505,11 @@
"integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
"dev": true
},
"diacritics": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz",
"integrity": "sha1-PvqHMj67hj5mls67AILUj/PW96E="
},
"diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -7425,6 +7438,11 @@
"has": "^1.0.1"
}
},
"is-regexp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
"integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA=="
},
"is-resolvable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
@@ -14674,6 +14692,15 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vue-text-highlight": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/vue-text-highlight/-/vue-text-highlight-2.0.10.tgz",
"integrity": "sha512-6WMWqr3OYonmK257o87shm7efMaFTyevEo8u5fN15gceyy2463fITFj9Wuh+W5lqLUm4n6cAZUS+y6xfzYB2aA==",
"requires": {
"clone-regexp": "^2.1.0",
"diacritics": "^1.3.0"
}
},
"vuedraggable": {
"version": "2.23.2",
"resolved": "https://registry.npm.taobao.org/vuedraggable/download/vuedraggable-2.23.2.tgz",

View File

@@ -41,11 +41,11 @@
"vue-countupjs": "^1.0.0",
"vue-draggable-resizable": "^2.3.0",
"vue-grid-layout": "^2.3.12",
"vue-highlight-text": "^1.6.2",
"vue-i18n": "^8.15.1",
"vue-quill-editor": "^3.0.6",
"vue-resource": "^1.5.1",
"vue-router": "^3.0.1",
"vue-text-highlight": "^2.0.10",
"vuedraggable": "^2.23.2",
"vuex": "^3.1.2",
"xlsx": "^0.15.6",
@@ -69,7 +69,6 @@
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-promise": "^4.3.1",
"eslint-plugin-vue": "^7.7.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",

View File

@@ -21,6 +21,7 @@
background: rgba(0,0,0,0);
width: 80%;
max-width: 1040px;
min-width: 894px;
height: auto;
display: flex;
flex-direction: column;
@@ -76,6 +77,9 @@
box-sizing: border-box;
height: 100%;
}
.global-search-content-left {
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14);
}
.list{
height: 100%;
width: 100%;

View File

@@ -0,0 +1,75 @@
.search-item-box{
width: 100%;
height: 100%;
overflow: hidden;
background: $--background-color-2;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
padding: 60px 75px 0 75px;
.search-item-title-icon{
.nz-icon{
font-size: 32px;
}
}
.search-item-path{
margin: 16px 0;
font-size: 14px;
span:first-child{
color: $--color-text-secondary;
}
span:nth-of-type(2){
color: $--color-text-secondary;
margin: 0 5px;
}
span:nth-of-type(2){
color: $--color-text-primary;
}
}
.search-item-name{
font-size: 20px;
font-weight: 600;
max-width: 100%;
//overflow: hidden;
word-break: break-all;
word-wrap: break-word;
color: $--color-text-primary;
margin-bottom: 30px;
}
.search-item-info{
width: 100%;
border-bottom: 1px solid $--border-color-light;
display: flex;
height: 47px;
.search-item-key{
width: 100px;
font-size: 14px;
line-height: 47px;
color:$--color-text-regular;
letter-spacing: 0;
font-weight: 400;
}
.search-item-value-box{
line-height: 47px;
width: calc(100% - 100px);
display: flex;
.nz-icon{
line-height: 47px;
margin-right: 10px;
}
.search-item-value{
width: calc(100% - 30px);
font-size: 14px;
color: $--color-text-primary;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
line-height: 47px;
}
}
}
.search-item-info:last-child{
border-bottom: none;
}
}

View File

@@ -54,6 +54,7 @@
@import './common/table/settings/switchTab.scss';
@import './common/table/special/endpointQuery.scss';
@import './common/globalSearch/globalSearch';
@import './common/globalSearch/searchItemInfo';
@import './common/browserWindowZoom.scss';
@import './common/chartUnit.scss';
@import './common/elementSet.scss';

View File

@@ -111,7 +111,8 @@
<div class="alert-label-title">{{$t('overall.module')}}</div>
<div class="alert-label-value">
<i style="cursor: pointer" class="nz-icon nz-icon-overview-module monitorColor"/>&nbsp;
<span>{{alertLabelData && alertLabelData.module && alertLabelData.module.name ? alertLabelData.module.name : '--'}}</span></div>
<span>{{alertLabelData && alertLabelData.moduleNum ? alertLabelData.moduleNum : '--'}}</span>
</div>
</div>
<div class="alert-label-box">
<div class="alert-label-title">Endpoint</div>

View File

@@ -28,7 +28,7 @@
>
<div class="list-item-content">
<i class="nz-icon" :class="selectIcon(item)" />
<HighlightText :keyword="searchStr" :overWriteStyle="{color: '#FA901C'}" style="vertical-align: middle" :title="item.name">{{item.name}}</HighlightText>
<HighlightText ref="searchStr" :queries="searchStr" :highlightClass="'list-item-highlight'" style="vertical-align: middle" :title="item.name">{{item.name}}</HighlightText>
</div>
<div class="list-item-sub" v-if="item.sub">
{{ item.sub }}
@@ -39,7 +39,7 @@
</ul>
</div>
<div class="global-search-content-right">
<searchItemInfo v-if="tableData[selectIndex]" :obj="tableData[selectIndex]" :severityData="severityData"></searchItemInfo>
</div>
</div>
<div v-else class="global-search-content" style="justify-content: center">
@@ -81,12 +81,14 @@
</template>
<script>
import HighlightText from 'vue-highlight-text'
import HighlightText from 'vue-text-highlight'
import searchItemInfo from './searchItemInfo'
export default {
name: 'globalSearch',
components: {
HighlightText
HighlightText,
searchItemInfo
},
computed: {
globalShow () {
@@ -114,6 +116,7 @@ export default {
total: 50
},
obj: {},
severityData: {},
// scope: ['asset', 'datacenter', 'project', 'module', 'endpoint', 'alertrule'],
scope: [
{
@@ -164,6 +167,9 @@ export default {
this.pageObj.pageNo = 1
this.tableData = []
this.$store.commit('setGlobalShow', false)
this.scope.forEach((item) => {
item.isSelect = true
})
this.unbindEvent()
},
selectIcon (item) {
@@ -180,10 +186,12 @@ export default {
},
bindEvent () {
window.addEventListener('keydown', this.keyDown)
window.addEventListener('keyup', this.keyup)
},
unbindEvent () {
this.selectIndex = ''
window.removeEventListener('keydown', this.keyDown)
window.removeEventListener('keyup', this.keyup)
},
scroll () {
// const ulBox = this.$refs.list
@@ -236,13 +244,15 @@ export default {
if (e.keyCode === 27) {
this.close()
}
},
keyup () {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
this.isKeyDown = false
}, 200)
}, 300)
},
jumpTo () {
@@ -268,13 +278,25 @@ export default {
this.nextLoading = true
this.getData()
},
scopeChange (item) {
scopeChange (scope) {
if (this.scopeChangeTimer) {
clearInterval(this.scopeChangeTimer)
this.scopeChangeTimer = null
}
this.loading = true
item.isSelect = !item.isSelect
const isSelectArr = this.scope.filter(item => item.isSelect)
if (isSelectArr.length === this.scope.length) {
this.scope.forEach(item => {
item.isSelect = false
})
scope.isSelect = !scope.isSelect
} else if (isSelectArr.length === 1 && isSelectArr[0].type === scope.type) {
this.scope.forEach(item => {
item.isSelect = true
})
} else {
scope.isSelect = !scope.isSelect
}
this.scopeChangeTimer = setTimeout(() => {
this.pageObj.pageNo = 1
this.tableData = []
@@ -307,6 +329,13 @@ export default {
}
this.loading = false
})
},
getSeverityData () {
this.$get('alert/severity', { pageNo: 1, pageSize: -1 }).then(response => {
if (response.code == 200) {
this.severityData = response.data.list
}
})
}
},
destroyed () {

View File

@@ -0,0 +1,368 @@
<template>
<div v-loading="loading" class="search-item-box">
<div class="search-item-title-icon">
<i class="nz-icon monitorColor" :class="selectIcon(obj)"/>
</div>
<div class="search-item-path" v-html="searchItemPath(obj)"></div>
<div class="search-item-name">{{obj.name}}</div>
<div v-for="item in dataKey[obj.type]" :key="item.key" class="search-item-info">
<div class="search-item-key">
{{item.label}}
</div>
<div class="search-item-value-box" v-if="obj.type === 'endpoint'&&item.key==='state'">
<span style="width: auto">
<span class="endpoint-cell-left"><i class="nz-icon nz-icon-Metrics active" /> {{$t('project.endpoint.metrics')}} </span>
<span v-if="alertLabelData && alertLabelData.configs[0].state === 0">
<span class="active-icon red-bg inline-block"></span>
</span>
<span v-else-if="alertLabelData && alertLabelData.configs[0].state === 1">
<span class="active-icon green-bg inline-block"></span>
</span>
<span v-else-if="alertLabelData && alertLabelData.configs[0].state">
<span class="active-icon gray-bg inline-block"></span>
</span>
</span>
<span style="width: auto">
<span class="endpoint-cell-left" style="margin-left: 10px"><i class="nz-icon nz-icon-logs active" /> {{$t('project.endpoint.logs')}} </span>
<span v-if="alertLabelData && alertLabelData.configs[1].state === 0">
<span class="active-icon red-bg inline-block"></span>
</span>
<span v-else-if="alertLabelData && alertLabelData.configs[1].state === 1">
<span class="active-icon green-bg inline-block"></span>
</span>
<span v-else-if="alertLabelData && alertLabelData.configs[1].state">
<span class="active-icon gray-bg inline-block"></span>
</span>
</span>
</div>
<div class="search-item-value-box" v-else-if="obj.type === 'datacenter'&&item.key==='state'">
<div v-if="alertLabelData" :class="{'green-bg': alertLabelData && alertLabelData.state === 'ON','red-bg': alertLabelData && alertLabelData.state === 'OFF'}" class="active-icon" style="margin-top: 20px;"></div>
<span v-if="alertLabelData && alertLabelData.state === 'ON'">{{ $t('overall.enabled') }}</span>
<span v-if="alertLabelData && alertLabelData.state === 'OFF'">{{ $t('overall.disabled') }}</span>
</div>
<div class="search-item-value-box" v-else>
<i v-if="item.icon" class="nz-icon" :class="searchItemClass(item)"/>
<span class="search-item-value">
{{getPathContent(item.key)}}
</span>
</div>
</div>
</div>
</template>
<script>
import lodash from 'lodash'
export default {
name: 'searchItemInfo',
props: {
obj: {},
severityData: {}
},
watch: {
obj: {
immediate: true,
deep: true,
handler (n) {
if (n.id) {
this.loading = true
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
this.getInfo(n)
}, 500)
}
}
}
},
data () {
return {
timer: null,
dataKey: {
asset: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('overall.name')
}, {
key: 'manageIp',
label: this.$t('overall.manageIp')
}, {
key: 'type.name',
label: this.$t('overall.type')
}, {
key: 'state.name',
label: this.$t('overall.state')
}, {
key: 'pingInfo.rtt',
icon: 'active-icon',
label: 'Ping'
}, {
key: 'dc.name',
label: this.$t('overall.dc')
}, {
key: 'cabinet.name',
label: this.$t('overall.cabinet')
}, {
key: 'brand.name',
label: this.$t('overall.brand')
}, {
key: 'model.name',
label: this.$t('overall.model')
}, {
key: 'alertNum',
icon: 'nz-icon-overview-alert',
label: this.$t('overall.alert')
}
],
datacenter: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('overall.name')
}, {
key: 'location',
label: this.$t('overall.location')
}, {
key: 'cabinetNum',
icon: 'nz-icon-cabinet monitorColor',
label: this.$t('overall.cabinet')
}, {
key: 'assetNum',
icon: 'nz-icon-overview-project monitorColor',
label: this.$t('overall.asset')
}, {
key: 'alertNum',
icon: 'nz-icon-overview-alert',
label: this.$t('overall.alert')
}, {
key: 'state',
label: this.$t('overall.state')
}
],
project: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('overall.name')
}, {
key: 'moduleNum',
icon: 'nz-icon-overview-module monitorColor',
label: this.$t('overall.module')
}, {
key: 'endpointNum',
icon: 'nz-icon-overview-endpoint monitorColor',
label: 'Endpoint'
}, {
key: 'assetNum',
icon: 'nz-icon-overview-project monitorColor color23BF9A',
label: this.$t('overall.asset')
}, {
key: 'alertNum',
icon: 'nz-icon-overview-alert',
label: this.$t('overall.alert')
}, {
key: 'remark',
label: this.$t('overall.remark')
}
],
module: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('overall.name')
}, {
key: 'project.name',
label: this.$t('overall.project')
}, {
key: 'endpointNum',
icon: 'nz-icon nz-icon-overview-endpoint monitorColor',
label: 'Endpoint'
}, {
key: 'assetNum',
icon: 'nz-icon nz-icon-overview-project monitorColor',
label: this.$t('overall.asset')
}, {
key: 'alertNum',
icon: 'nz-icon-overview-alert',
label: this.$t('overall.alert')
}, {
key: 'remark',
label: this.$t('overall.remark')
}
],
endpoint: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('overall.name')
}, {
key: 'project.name',
label: this.$t('overall.project')
}, {
key: 'module.name',
label: this.$t('overall.module')
}, {
key: 'asset.name',
icon: 'nz-icon-overview-project monitorColor',
label: this.$t('overall.asset')
}, {
key: 'alertNum',
icon: 'nz-icon-overview-alert',
label: this.$t('overall.alert')
}, {
key: 'state',
label: this.$t('overall.state')
}
],
alertrule: [
{
key: 'id',
label: 'Id'
}, {
key: 'name',
label: this.$t('alert.name')
}, {
key: 'type',
label: this.$t('alert.type')
}
]
},
alertLabelData: {},
loading: true
}
},
methods: {
// lodash,
init (type) {
this.loading = true
if (type === 'asset') {
this.$get('asset/asset/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
if (type === 'project') {
this.$get('monitor/project/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
if (type === 'module') {
this.$get('monitor/module/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
if (type === 'endpoint') {
this.$get('monitor/endpoint/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
if (type === 'datacenter') {
this.$get('dc/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
if (type === 'alertrule') {
this.$get('/alert/rule/' + this.obj.id).then((res) => {
if (res.msg === 'success') {
this.loading = false
this.severityData.forEach(item => {
this.severityColor = item.color
})
this.alertLabelData = res.data
} else {
this.$message.error(res.msg)
}
})
}
},
getInfo () {
this.init(this.obj.type)
},
searchItemClass (item) {
let str = ''
if (item.icon) {
str += item.icon + ' '
}
if (item.key === 'alertNum') {
str += this.alertLabelData[item.key] ? 'red' : 'green'
}
if (item.key === 'pingInfo.rtt') {
str += this.alertLabelData.pingInfo.status ? 'red-bg' : 'green-bg'
}
return str
},
getPathContent (key) {
let str = lodash.get(this.alertLabelData, key, '--')
str += ''
if (key === 'pingInfo.rtt' && str) {
str += ' ms'
}
return str || '--'
},
selectIcon (item) {
// console.log(item)
switch (item.type) {
case 'asset' : return 'nz-icon-overview-project'
case 'datacenter' : return 'nz-icon-model'
case 'project' : return 'nz-icon-project'
case 'module' : return 'nz-icon-overview-module'
case 'endpoint' : return 'nz-icon-overview-endpoint'
case 'alertrule' : return 'nz-icon-Alertrule'
}
return 'nz-icon-module5'
},
searchItemPath (item) {
let str = ''
switch (item.type) {
case 'asset' : str += '<span>Asset</span> <span>/</span> <span>Asset</span>'; break
case 'datacenter' : str += '<span>Setting</span> <span>/</span> <span>Data center</span>'; break
case 'project' : str += '<span>Monitor</span> <span>/</span> <span>Project</span>'; break
case 'module' :str += '<span>Monitor</span> <span>/</span> <span>Module</span>'; break
case 'endpoint' : str += '<span>Monitor</span> <span>/</span> <span>Endpoint</span>'; break
case 'alertrule' : str += '<span>Alert</span> <span>/</span> <span>Alert rule</span>'; break
}
return str
}
}
}
</script>
<style scoped>
</style>