mirror of https://github.com/veops/cmdb.git
Merge pull request #531 from veops/dev_ui_240606
feat: update topology view
This commit is contained in:
commit
28c57cacd9
|
@ -1,317 +1,319 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div id="search-form-bar" class="search-form-bar">
|
<div id="search-form-bar" class="search-form-bar">
|
||||||
<div :style="{ display: 'inline-flex', alignItems: 'center' }">
|
<div :style="{ display: 'inline-flex', alignItems: 'center' }">
|
||||||
<a-space>
|
<a-space>
|
||||||
<treeselect
|
<treeselect
|
||||||
v-if="type === 'resourceSearch'"
|
v-if="type === 'resourceSearch'"
|
||||||
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
class="custom-treeselect custom-treeselect-bgcAndBorder"
|
||||||
:style="{
|
:style="{
|
||||||
width: '200px',
|
width: '200px',
|
||||||
marginRight: '10px',
|
marginRight: '10px',
|
||||||
'--custom-height': '32px',
|
'--custom-height': '32px',
|
||||||
'--custom-bg-color': '#fff',
|
'--custom-bg-color': '#fff',
|
||||||
'--custom-border': '1px solid #d9d9d9',
|
'--custom-border': '1px solid #d9d9d9',
|
||||||
'--custom-multiple-lineHeight': '16px',
|
'--custom-multiple-lineHeight': '16px',
|
||||||
}"
|
}"
|
||||||
v-model="currenCiType"
|
v-model="currenCiType"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:clearable="true"
|
:clearable="true"
|
||||||
searchable
|
searchable
|
||||||
:options="ciTypeGroup"
|
:options="ciTypeGroup"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:limitText="(count) => `+ ${count}`"
|
:limitText="(count) => `+ ${count}`"
|
||||||
value-consists-of="LEAF_PRIORITY"
|
value-consists-of="LEAF_PRIORITY"
|
||||||
:placeholder="$t('cmdb.ciType.ciType')"
|
:placeholder="$t('cmdb.ciType.ciType')"
|
||||||
@close="closeCiTypeGroup"
|
@close="closeCiTypeGroup"
|
||||||
@open="openCiTypeGroup"
|
@open="openCiTypeGroup"
|
||||||
@input="inputCiTypeGroup"
|
@input="inputCiTypeGroup"
|
||||||
:normalizer="
|
:normalizer="
|
||||||
(node) => {
|
(node) => {
|
||||||
return {
|
return {
|
||||||
id: node.id || -1,
|
id: node.id || -1,
|
||||||
label: node.alias || node.name || $t('other'),
|
label: node.alias || node.name || $t('other'),
|
||||||
title: node.alias || node.name || $t('other'),
|
title: node.alias || node.name || $t('other'),
|
||||||
children: node.ci_types,
|
children: node.ci_types,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
:title="node.label"
|
:title="node.label"
|
||||||
slot="option-label"
|
slot="option-label"
|
||||||
slot-scope="{ node }"
|
slot-scope="{ node }"
|
||||||
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
:style="{ width: '100%', whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }"
|
||||||
>
|
>
|
||||||
{{ node.label }}
|
{{ node.label }}
|
||||||
</div>
|
</div>
|
||||||
</treeselect>
|
</treeselect>
|
||||||
<a-input
|
<a-input
|
||||||
v-model="fuzzySearch"
|
v-model="fuzzySearch"
|
||||||
:style="{ display: 'inline-block', width: '200px' }"
|
:style="{ display: 'inline-block', width: '200px' }"
|
||||||
:placeholder="$t('cmdb.components.pleaseSearch')"
|
:placeholder="$t('cmdb.components.pleaseSearch')"
|
||||||
@pressEnter="emitRefresh"
|
@pressEnter="emitRefresh"
|
||||||
>
|
>
|
||||||
<a-icon
|
<a-icon
|
||||||
type="search"
|
type="search"
|
||||||
slot="suffix"
|
slot="suffix"
|
||||||
:style="{ color: fuzzySearch ? '#2f54eb' : '#d9d9d9', cursor: 'pointer' }"
|
:style="{ color: fuzzySearch ? '#2f54eb' : '#d9d9d9', cursor: 'pointer' }"
|
||||||
@click="emitRefresh"
|
@click="emitRefresh"
|
||||||
/>
|
/>
|
||||||
<a-tooltip slot="prefix" placement="bottom" :overlayStyle="{ maxWidth: '550px', whiteSpace: 'pre-line' }">
|
<a-tooltip slot="prefix" placement="bottom" :overlayStyle="{ maxWidth: '550px', whiteSpace: 'pre-line' }">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
{{ $t('cmdb.components.ciSearchTips') }}
|
{{ $t('cmdb.components.ciSearchTips') }}
|
||||||
</template>
|
</template>
|
||||||
<a><a-icon type="question-circle"/></a>
|
<a><a-icon type="question-circle"/></a>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-tooltip :title="$t('reset')">
|
<a-tooltip :title="$t('reset')">
|
||||||
<a-button @click="reset">{{ $t('reset') }}</a-button>
|
<a-button @click="reset">{{ $t('reset') }}</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<FilterComp
|
<FilterComp
|
||||||
ref="filterComp"
|
ref="filterComp"
|
||||||
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
|
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
|
||||||
@setExpFromFilter="setExpFromFilter"
|
@setExpFromFilter="setExpFromFilter"
|
||||||
:expression="expression"
|
:expression="expression"
|
||||||
placement="bottomLeft"
|
placement="bottomLeft"
|
||||||
>
|
>
|
||||||
<div slot="popover_item" class="search-form-bar-filter">
|
<div slot="popover_item" class="search-form-bar-filter">
|
||||||
<a-icon class="search-form-bar-filter-icon" type="filter" />
|
<a-icon class="search-form-bar-filter-icon" type="filter" />
|
||||||
{{ $t('cmdb.components.conditionFilter') }}
|
{{ $t('cmdb.components.conditionFilter') }}
|
||||||
<a-icon class="search-form-bar-filter-icon" type="down" :style="{ color: '#d9d9d9' }" />
|
<a-icon class="search-form-bar-filter-icon" type="down" :style="{ color: '#d9d9d9' }" />
|
||||||
</div>
|
</div>
|
||||||
</FilterComp>
|
</FilterComp>
|
||||||
<a-input
|
<a-input
|
||||||
v-if="isShowExpression"
|
v-if="isShowExpression"
|
||||||
v-model="expression"
|
v-model="expression"
|
||||||
v-show="!selectedRowKeys.length"
|
v-show="!selectedRowKeys.length"
|
||||||
@focus="
|
@focus="
|
||||||
() => {
|
() => {
|
||||||
isFocusExpression = true
|
isFocusExpression = true
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
@blur="
|
@blur="
|
||||||
() => {
|
() => {
|
||||||
isFocusExpression = false
|
isFocusExpression = false
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
:class="{ 'ci-searchform-expression': true, 'ci-searchform-expression-has-value': expression }"
|
:class="{ 'ci-searchform-expression': true, 'ci-searchform-expression-has-value': expression }"
|
||||||
:style="{ width }"
|
:style="{ width }"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@keyup.enter="emitRefresh"
|
@keyup.enter="emitRefresh"
|
||||||
>
|
>
|
||||||
<a-icon slot="suffix" type="check-circle" @click="handleCopyExpression" />
|
<a-icon slot="suffix" type="check-circle" @click="handleCopyExpression" />
|
||||||
</a-input>
|
</a-input>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<a-space>
|
<a-space>
|
||||||
<slot name="extraContent"></slot>
|
<slot name="extraContent"></slot>
|
||||||
<a-tooltip :title="$t('cmdb.components.attributeDesc')" v-if="type === 'relationView'">
|
<a-tooltip :title="$t('cmdb.components.attributeDesc')" v-if="type === 'relationView'">
|
||||||
<a
|
<a
|
||||||
@click="
|
@click="
|
||||||
() => {
|
() => {
|
||||||
$refs.metadataDrawer.open(typeId)
|
$refs.metadataDrawer.open(typeId)
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
><a-icon
|
><a-icon
|
||||||
v-if="type === 'relationView'"
|
v-if="type === 'relationView'"
|
||||||
type="question-circle"
|
type="question-circle"
|
||||||
/></a>
|
/></a>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
<MetadataDrawer ref="metadataDrawer" />
|
<MetadataDrawer ref="metadataDrawer" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import Treeselect from '@riophae/vue-treeselect'
|
import Treeselect from '@riophae/vue-treeselect'
|
||||||
import MetadataDrawer from '../../views/ci/modules/MetadataDrawer.vue'
|
import MetadataDrawer from '../../views/ci/modules/MetadataDrawer.vue'
|
||||||
import FilterComp from '@/components/CMDBFilterComp'
|
import FilterComp from '@/components/CMDBFilterComp'
|
||||||
import { getCITypeGroups } from '../../api/ciTypeGroup'
|
import { getCITypeGroups } from '../../api/ciTypeGroup'
|
||||||
export default {
|
export default {
|
||||||
name: 'SearchForm',
|
name: 'SearchForm',
|
||||||
components: { MetadataDrawer, FilterComp, Treeselect },
|
components: { MetadataDrawer, FilterComp, Treeselect },
|
||||||
props: {
|
props: {
|
||||||
preferenceAttrList: {
|
preferenceAttrList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
isShowExpression: {
|
isShowExpression: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
typeId: {
|
typeId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
selectedRowKeys: {
|
selectedRowKeys: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// Advanced Search Expand/Close
|
// Advanced Search Expand/Close
|
||||||
advanced: false,
|
advanced: false,
|
||||||
queryParam: {},
|
queryParam: {},
|
||||||
isFocusExpression: false,
|
isFocusExpression: false,
|
||||||
expression: '',
|
expression: '',
|
||||||
fuzzySearch: '',
|
fuzzySearch: '',
|
||||||
currenCiType: [],
|
currenCiType: [],
|
||||||
ciTypeGroup: [],
|
ciTypeGroup: [],
|
||||||
lastCiType: [],
|
lastCiType: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
placeholder() {
|
placeholder() {
|
||||||
return this.isFocusExpression ? this.$t('cmdb.components.ciSearchTips2') : this.$t('cmdb.ciType.expr')
|
return this.isFocusExpression ? this.$t('cmdb.components.ciSearchTips2') : this.$t('cmdb.ciType.expr')
|
||||||
},
|
},
|
||||||
width() {
|
width() {
|
||||||
return '200px'
|
return '200px'
|
||||||
},
|
},
|
||||||
canSearchPreferenceAttrList() {
|
canSearchPreferenceAttrList() {
|
||||||
return this.preferenceAttrList.filter((item) => item.value_type !== '6')
|
return this.preferenceAttrList.filter((item) => item.value_type !== '6')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route.path': function(newValue, oldValue) {
|
'$route.path': function(newValue, oldValue) {
|
||||||
this.queryParam = {}
|
this.queryParam = {}
|
||||||
this.expression = ''
|
this.expression = ''
|
||||||
this.fuzzySearch = ''
|
this.fuzzySearch = ''
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inject: {
|
inject: {
|
||||||
setPreferenceSearchCurrent: {
|
setPreferenceSearchCurrent: {
|
||||||
from: 'setPreferenceSearchCurrent',
|
from: 'setPreferenceSearchCurrent',
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.type === 'resourceSearch') {
|
if (this.type === 'resourceSearch') {
|
||||||
this.getCITypeGroups()
|
this.getCITypeGroups()
|
||||||
}
|
}
|
||||||
if (this.typeId) {
|
if (this.typeId) {
|
||||||
this.currenCiType = [this.typeId]
|
this.currenCiType = [this.typeId]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// toggleAdvanced() {
|
// toggleAdvanced() {
|
||||||
// this.advanced = !this.advanced
|
// this.advanced = !this.advanced
|
||||||
// },
|
// },
|
||||||
getCITypeGroups() {
|
getCITypeGroups() {
|
||||||
getCITypeGroups({ need_other: true }).then((res) => {
|
getCITypeGroups({ need_other: true }).then((res) => {
|
||||||
this.ciTypeGroup = res
|
this.ciTypeGroup = res
|
||||||
.filter((item) => item.ci_types && item.ci_types.length)
|
.filter((item) => item.ci_types && item.ci_types.length)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
item.id = `parent_${item.id || -1}`
|
item.id = `parent_${item.id || -1}`
|
||||||
return { ..._.cloneDeep(item) }
|
return { ..._.cloneDeep(item) }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
this.queryParam = {}
|
this.queryParam = {}
|
||||||
this.expression = ''
|
this.expression = ''
|
||||||
this.fuzzySearch = ''
|
this.fuzzySearch = ''
|
||||||
this.currenCiType = []
|
if (this.type !== 'resourceView') {
|
||||||
this.emitRefresh()
|
this.currenCiType = []
|
||||||
},
|
}
|
||||||
setExpFromFilter(filterExp) {
|
this.emitRefresh()
|
||||||
const regSort = /(?<=sort=).+/g
|
},
|
||||||
const expSort = this.expression.match(regSort) ? this.expression.match(regSort)[0] : undefined
|
setExpFromFilter(filterExp) {
|
||||||
let expression = ''
|
const regSort = /(?<=sort=).+/g
|
||||||
if (filterExp) {
|
const expSort = this.expression.match(regSort) ? this.expression.match(regSort)[0] : undefined
|
||||||
expression = `q=${filterExp}`
|
let expression = ''
|
||||||
}
|
if (filterExp) {
|
||||||
if (expSort) {
|
expression = `q=${filterExp}`
|
||||||
expression += `&sort=${expSort}`
|
}
|
||||||
}
|
if (expSort) {
|
||||||
this.expression = expression
|
expression += `&sort=${expSort}`
|
||||||
this.emitRefresh()
|
}
|
||||||
},
|
this.expression = expression
|
||||||
handleSubmit() {
|
this.emitRefresh()
|
||||||
this.$refs.filterComp.handleSubmit()
|
},
|
||||||
},
|
handleSubmit() {
|
||||||
openCiTypeGroup() {
|
this.$refs.filterComp.handleSubmit()
|
||||||
this.lastCiType = _.cloneDeep(this.currenCiType)
|
},
|
||||||
},
|
openCiTypeGroup() {
|
||||||
closeCiTypeGroup(value) {
|
this.lastCiType = _.cloneDeep(this.currenCiType)
|
||||||
if (!_.isEqual(value, this.lastCiType)) {
|
},
|
||||||
this.$emit('updateAllAttributesList', value)
|
closeCiTypeGroup(value) {
|
||||||
}
|
if (!_.isEqual(value, this.lastCiType)) {
|
||||||
},
|
this.$emit('updateAllAttributesList', value)
|
||||||
inputCiTypeGroup(value) {
|
}
|
||||||
if (!value || !value.length) {
|
},
|
||||||
this.$emit('updateAllAttributesList', value)
|
inputCiTypeGroup(value) {
|
||||||
}
|
if (!value || !value.length) {
|
||||||
},
|
this.$emit('updateAllAttributesList', value)
|
||||||
emitRefresh() {
|
}
|
||||||
if (this.setPreferenceSearchCurrent) {
|
},
|
||||||
this.setPreferenceSearchCurrent(null)
|
emitRefresh() {
|
||||||
}
|
if (this.setPreferenceSearchCurrent) {
|
||||||
this.$nextTick(() => {
|
this.setPreferenceSearchCurrent(null)
|
||||||
this.$emit('refresh', true)
|
}
|
||||||
})
|
this.$nextTick(() => {
|
||||||
},
|
this.$emit('refresh', true)
|
||||||
handleCopyExpression() {
|
})
|
||||||
this.$emit('copyExpression')
|
},
|
||||||
},
|
handleCopyExpression() {
|
||||||
},
|
this.$emit('copyExpression')
|
||||||
}
|
},
|
||||||
</script>
|
},
|
||||||
<style lang="less">
|
}
|
||||||
@import '../../views/index.less';
|
</script>
|
||||||
.ci-searchform-expression {
|
<style lang="less">
|
||||||
> input {
|
@import '../../views/index.less';
|
||||||
border-bottom: 2px solid #d9d9d9;
|
.ci-searchform-expression {
|
||||||
border-top: none;
|
> input {
|
||||||
border-left: none;
|
border-bottom: 2px solid #d9d9d9;
|
||||||
border-right: none;
|
border-top: none;
|
||||||
&:hover,
|
border-left: none;
|
||||||
&:focus {
|
border-right: none;
|
||||||
border-bottom: 2px solid @primary-color;
|
&:hover,
|
||||||
}
|
&:focus {
|
||||||
&:focus {
|
border-bottom: 2px solid @primary-color;
|
||||||
box-shadow: 0 2px 2px -2px #1f78d133;
|
}
|
||||||
}
|
&:focus {
|
||||||
}
|
box-shadow: 0 2px 2px -2px #1f78d133;
|
||||||
.ant-input-suffix {
|
}
|
||||||
color: #d9d9d9;
|
}
|
||||||
cursor: pointer;
|
.ant-input-suffix {
|
||||||
}
|
color: #d9d9d9;
|
||||||
}
|
cursor: pointer;
|
||||||
.ci-searchform-expression-has-value .ant-input-suffix {
|
}
|
||||||
color: @func-color_3;
|
}
|
||||||
}
|
.ci-searchform-expression-has-value .ant-input-suffix {
|
||||||
.cmdb-search-form {
|
color: @func-color_3;
|
||||||
.ant-form-item-label {
|
}
|
||||||
overflow: hidden;
|
.cmdb-search-form {
|
||||||
text-overflow: ellipsis;
|
.ant-form-item-label {
|
||||||
white-space: nowrap;
|
overflow: hidden;
|
||||||
}
|
text-overflow: ellipsis;
|
||||||
}
|
white-space: nowrap;
|
||||||
</style>
|
}
|
||||||
|
}
|
||||||
<style lang="less" scoped>
|
</style>
|
||||||
.search-form-bar {
|
|
||||||
margin-bottom: 20px;
|
<style lang="less" scoped>
|
||||||
display: flex;
|
.search-form-bar {
|
||||||
justify-content: space-between;
|
margin-bottom: 20px;
|
||||||
align-items: center;
|
display: flex;
|
||||||
height: 32px;
|
justify-content: space-between;
|
||||||
.search-form-bar-filter {
|
align-items: center;
|
||||||
.ops_display_wrapper(transparent);
|
height: 32px;
|
||||||
.search-form-bar-filter-icon {
|
.search-form-bar-filter {
|
||||||
color: @primary-color;
|
.ops_display_wrapper(transparent);
|
||||||
font-size: 12px;
|
.search-form-bar-filter-icon {
|
||||||
}
|
color: @primary-color;
|
||||||
}
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -589,6 +589,7 @@ if __name__ == "__main__":
|
||||||
confirmDeleteView: 'Are you sure you want to delete this view ?',
|
confirmDeleteView: 'Are you sure you want to delete this view ?',
|
||||||
noInstancePerm: 'You do not have read permissions for this instance',
|
noInstancePerm: 'You do not have read permissions for this instance',
|
||||||
noPreferenceAttributes: 'This instance has no subscription attributes or no default displayed attributes',
|
noPreferenceAttributes: 'This instance has no subscription attributes or no default displayed attributes',
|
||||||
|
topoViewSearchPlaceholder: 'Please enter the node name.'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
export default cmdb_en
|
export default cmdb_en
|
||||||
|
|
|
@ -589,6 +589,7 @@ if __name__ == "__main__":
|
||||||
confirmDeleteView: '您确定要删除该视图吗?',
|
confirmDeleteView: '您确定要删除该视图吗?',
|
||||||
noInstancePerm: '您没有该实例的查看权限',
|
noInstancePerm: '您没有该实例的查看权限',
|
||||||
noPreferenceAttributes: '该实例没有订阅属性或者没有默认展示的属性',
|
noPreferenceAttributes: '该实例没有订阅属性或者没有默认展示的属性',
|
||||||
|
topoViewSearchPlaceholder: '请输入节点名字'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
export default cmdb_zh
|
export default cmdb_zh
|
||||||
|
|
|
@ -140,12 +140,33 @@
|
||||||
<div :style="{ height: `${windowHeight - 80}px` }" ref="rightTopoView">
|
<div :style="{ height: `${windowHeight - 80}px` }" ref="rightTopoView">
|
||||||
<RelationGraph ref="showTopoView" :options="graphOptions2" :on-node-click="showNodeTips">
|
<RelationGraph ref="showTopoView" :options="graphOptions2" :on-node-click="showNodeTips">
|
||||||
<template #node="{node}">
|
<template #node="{node}">
|
||||||
<div :style="{ lineHeight: '20px' }">
|
<div
|
||||||
<ops-icon type="caise-wuliji" />
|
:style="{ borderColor: node.data.btnType === 'more' ? '#A4B5E1' : nodeStyle[Math.abs(node.lot.level)] ? nodeStyle[Math.abs(node.lot.level)].backgroundColor : '#A4B5E1' }"
|
||||||
<span :style="{ marginLeft: '5px', textOverflow: 'ellipsis' }">{{ node.text }}aaa</span>
|
class="relation-graph-node"
|
||||||
|
>
|
||||||
|
<template v-if="node.data.icon">
|
||||||
|
<img
|
||||||
|
v-if="node.data.icon.split('$$')[2]"
|
||||||
|
:src="`/api/common-setting/v1/file/${node.data.icon.split('$$')[3]}`"
|
||||||
|
class="relation-graph-node-image"
|
||||||
|
/>
|
||||||
|
<ops-icon
|
||||||
|
v-else
|
||||||
|
:style="{ color: node.data.icon.split('$$')[1] }"
|
||||||
|
:type="node.data.icon ? node.data.icon.split('$$')[0] : ''"
|
||||||
|
class="relation-graph-node-icon"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span class="relation-graph-node-text">{{ node.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #graph-plug>
|
<template #graph-plug>
|
||||||
|
<a-input-search
|
||||||
|
class="relation-graph-search"
|
||||||
|
v-model="topoViewSearchValue"
|
||||||
|
:placeholder="$t('cmdb.topo.topoViewSearchPlaceholder')"
|
||||||
|
@search="handleSearchTopoView"
|
||||||
|
/>
|
||||||
<div v-if="(isShowNodeTipsPanel && currentNodeValues && currentNodeAttributes.length) || errorMessageShow" :style="nodeTipsPosition" class="node-tips">
|
<div v-if="(isShowNodeTipsPanel && currentNodeValues && currentNodeAttributes.length) || errorMessageShow" :style="nodeTipsPosition" class="node-tips">
|
||||||
<a-descriptions
|
<a-descriptions
|
||||||
v-if="currentNodeValues"
|
v-if="currentNodeValues"
|
||||||
|
@ -236,12 +257,12 @@
|
||||||
</SeeksRelationGraph>
|
</SeeksRelationGraph>
|
||||||
</div>
|
</div>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item :style="{ display: 'none' }" :label="$t('cmdb.topo.aggregationCount')" prop="aggregation_count" :help="$t('cmdb.topo.aggreationCountTip')">
|
<a-form-item :label="$t('cmdb.topo.aggregationCount')" prop="aggregation_count" :help="$t('cmdb.topo.aggreationCountTip')">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
:style="{ width: '100%' }"
|
:style="{ width: '100%' }"
|
||||||
|
:min="0"
|
||||||
v-decorator="['aggregation_count']"
|
v-decorator="['aggregation_count']"
|
||||||
>
|
>
|
||||||
<a @click="handleOpenCmdb" slot="suffix"><a-icon type="menu"/></a>
|
|
||||||
</a-input-number>
|
</a-input-number>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<div :class="{ 'chart-left-preview': true, 'chart-left-preview-empty': !isShowPreview }">
|
<div :class="{ 'chart-left-preview': true, 'chart-left-preview-empty': !isShowPreview }">
|
||||||
|
@ -253,9 +274,27 @@
|
||||||
>
|
>
|
||||||
<template v-if="isShowPreview">
|
<template v-if="isShowPreview">
|
||||||
<RelationGraph ref="previewTopoView" :options="graphOptionsPrivew">
|
<RelationGraph ref="previewTopoView" :options="graphOptionsPrivew">
|
||||||
<div slot="node" slot-scope="{ node }" :style="{ lineHeight: '20px' }">
|
<template #node="{node}">
|
||||||
<span :style="{ marginLeft: '5px' }">{{ node.text }}</span>
|
<div
|
||||||
</div>
|
:style="{ borderColor: nodeStyle[node.lot.level] ? nodeStyle[node.lot.level].backgroundColor : '#7F97FA' }"
|
||||||
|
class="relation-graph-node"
|
||||||
|
>
|
||||||
|
<template v-if="node.data.icon">
|
||||||
|
<img
|
||||||
|
v-if="node.data.icon.split('$$')[2]"
|
||||||
|
:src="`/api/common-setting/v1/file/${node.data.icon.split('$$')[3]}`"
|
||||||
|
class="relation-graph-node-image"
|
||||||
|
/>
|
||||||
|
<ops-icon
|
||||||
|
v-else
|
||||||
|
:style="{ color: node.data.icon.split('$$')[1] }"
|
||||||
|
:type="node.data.icon ? node.data.icon.split('$$')[0] : ''"
|
||||||
|
class="relation-graph-node-icon"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span class="relation-graph-node-text">{{ node.text }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</RelationGraph>
|
</RelationGraph>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -290,6 +329,7 @@ import { getSubscribeAttributes } from '@/modules/cmdb/api/preference'
|
||||||
import { searchCI } from '@/modules/cmdb/api/ci'
|
import { searchCI } from '@/modules/cmdb/api/ci'
|
||||||
import { getTopoGroups, postTopoGroup, putTopoGroupByGId, putTopoGroupsOrder, deleteTopoGroup, getTopoView, addTopoView, updateTopoView, deleteTopoView, getRelationsByTypeId, previewTopoView, showTopoView } from '@/modules/cmdb/api/topology'
|
import { getTopoGroups, postTopoGroup, putTopoGroupByGId, putTopoGroupsOrder, deleteTopoGroup, getTopoView, addTopoView, updateTopoView, deleteTopoView, getRelationsByTypeId, previewTopoView, showTopoView } from '@/modules/cmdb/api/topology'
|
||||||
import CMDBExprDrawer from '@/components/CMDBExprDrawer'
|
import CMDBExprDrawer from '@/components/CMDBExprDrawer'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
|
||||||
const currentTopoKey = 'ops_cmdb_topo_currentId'
|
const currentTopoKey = 'ops_cmdb_topo_currentId'
|
||||||
export default {
|
export default {
|
||||||
|
@ -326,6 +366,7 @@ export default {
|
||||||
const graphOptions2 = {
|
const graphOptions2 = {
|
||||||
// ...defaultOptions,
|
// ...defaultOptions,
|
||||||
backgrounImageNoRepeat: true,
|
backgrounImageNoRepeat: true,
|
||||||
|
ovUseNodeSlot: true,
|
||||||
placeOtherGroup: true,
|
placeOtherGroup: true,
|
||||||
moveToCenterWhenRefresh: true,
|
moveToCenterWhenRefresh: true,
|
||||||
zoomToFitWhenRefresh: true,
|
zoomToFitWhenRefresh: true,
|
||||||
|
@ -339,10 +380,11 @@ export default {
|
||||||
max_per_width: 200,
|
max_per_width: 200,
|
||||||
min_per_height: 40,
|
min_per_height: 40,
|
||||||
max_per_height: undefined,
|
max_per_height: undefined,
|
||||||
defaultLineColor: '#CACDD9',
|
backgroundColor: '#FFFFFF',
|
||||||
defaultNodeColor: '#29AAE1',
|
// defaultLineColor: '#CACDD9',
|
||||||
defaultNodeFontColor: '#ffffff',
|
// defaultNodeColor: '#29AAE1',
|
||||||
defaultNodeBorderColor: '#b1c9ff',
|
// defaultNodeFontColor: '#ffffff',
|
||||||
|
// defaultNodeBorderColor: '#b1c9ff',
|
||||||
defaultExpandHolderPosition: 'right',
|
defaultExpandHolderPosition: 'right',
|
||||||
defaultJunctionPoint: 'lr',
|
defaultJunctionPoint: 'lr',
|
||||||
layouts: [
|
layouts: [
|
||||||
|
@ -350,7 +392,7 @@ export default {
|
||||||
layoutName: 'tree',
|
layoutName: 'tree',
|
||||||
from: 'left',
|
from: 'left',
|
||||||
layoutClassName: 'seeks-layout-center',
|
layoutClassName: 'seeks-layout-center',
|
||||||
defaultExpandHolderPosition: 'hide',
|
defaultExpandHolderPosition: 'right',
|
||||||
defaultJunctionPoint: 'border',
|
defaultJunctionPoint: 'border',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -411,6 +453,29 @@ export default {
|
||||||
|
|
||||||
errorMessageShow: false,
|
errorMessageShow: false,
|
||||||
errorMessage: '',
|
errorMessage: '',
|
||||||
|
nodeStyle: {
|
||||||
|
'0': {
|
||||||
|
backgroundColor: '#2F54EB'
|
||||||
|
},
|
||||||
|
'1': {
|
||||||
|
backgroundColor: '#29AAE1'
|
||||||
|
},
|
||||||
|
'2': {
|
||||||
|
backgroundColor: '#7F97FA'
|
||||||
|
},
|
||||||
|
'3': {
|
||||||
|
backgroundColor: '##75C5CA'
|
||||||
|
},
|
||||||
|
'4': {
|
||||||
|
backgroundColor: '#A699F6'
|
||||||
|
},
|
||||||
|
'5': {
|
||||||
|
backgroundColor: '#A4B5E1'
|
||||||
|
}
|
||||||
|
}, // 拓扑图节点分级别样式
|
||||||
|
topoViewJsonData: {}, // 拓扑图 JSON 数据
|
||||||
|
topoViewOption: {}, // 拓扑图配置数据 子节点分页
|
||||||
|
topoViewSearchValue: '', // 拓扑图搜索
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
|
@ -485,6 +550,30 @@ export default {
|
||||||
: {}
|
: {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
'$i18n.locale': {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
this.changeTopoViewToolbarLang(newVal)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isShowPreview: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.changeTopoViewToolbarLang(this.$i18n.locale)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
drawerVisible: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
this.changeTopoViewToolbarLang(this.$i18n.locale)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeNodeTips(e) {
|
closeNodeTips(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
@ -578,7 +667,7 @@ export default {
|
||||||
payload.view_ids = g.views.map(i => i.id)
|
payload.view_ids = g.views.map(i => i.id)
|
||||||
}
|
}
|
||||||
if (groupId) {
|
if (groupId) {
|
||||||
putTopoGroupByGId(groupId, { view_ids: g.views.map((i) => i.id) })
|
putTopoGroupByGId(groupId, { view_ids: payload.view_ids })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$message.success(that.$t('saveSuccess'))
|
this.$message.success(that.$t('saveSuccess'))
|
||||||
})
|
})
|
||||||
|
@ -729,12 +818,21 @@ export default {
|
||||||
disableDefaultClickEffect: true,
|
disableDefaultClickEffect: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
const type2meta = res?.type2meta
|
||||||
res.nodes.forEach(item => {
|
res.nodes.forEach(item => {
|
||||||
|
const icon = type2meta?.[item?.type_id] || ''
|
||||||
nodes.push({
|
nodes.push({
|
||||||
id: `${item.id}`,
|
id: `${item.id}`,
|
||||||
text: item.name,
|
text: item.name,
|
||||||
nodeShape: 1,
|
nodeShape: 1,
|
||||||
borderWidth: -1,
|
borderWidth: -1,
|
||||||
|
color: 'transparent',
|
||||||
|
styleClass: {
|
||||||
|
padding: '0px'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
icon
|
||||||
|
},
|
||||||
disableDefaultClickEffect: true,
|
disableDefaultClickEffect: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -752,11 +850,15 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showTopoView(viewId) {
|
async showTopoView(viewId) {
|
||||||
if (viewId === 'null' || !viewId) {
|
if (viewId === 'null' || !viewId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
showTopoView(viewId).then(res => {
|
const topoViewRes = await getTopoView(viewId)
|
||||||
|
if (topoViewRes?.option) {
|
||||||
|
this.topoViewOption = topoViewRes.option
|
||||||
|
}
|
||||||
|
showTopoView(viewId).then(async res => {
|
||||||
const nodes = []
|
const nodes = []
|
||||||
const links = []
|
const links = []
|
||||||
this.currentNodes = res.nodes
|
this.currentNodes = res.nodes
|
||||||
|
@ -768,11 +870,21 @@ export default {
|
||||||
disableDefaultClickEffect: false,
|
disableDefaultClickEffect: false,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
const type2meta = res?.type2meta
|
||||||
res.nodes.forEach(item => {
|
res.nodes.forEach(item => {
|
||||||
|
const icon = type2meta?.[item?.type_id] || ''
|
||||||
nodes.push({
|
nodes.push({
|
||||||
id: `${item.id}`,
|
id: `${item.id}`,
|
||||||
text: item.name,
|
text: item.name,
|
||||||
data: {},
|
color: 'transparent',
|
||||||
|
styleClass: {
|
||||||
|
padding: '0px'
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
icon
|
||||||
|
},
|
||||||
|
isHide: false,
|
||||||
|
opacity: 1,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const _graphJsonData = {
|
const _graphJsonData = {
|
||||||
|
@ -783,11 +895,132 @@ export default {
|
||||||
this.$message.error(this.$t('cmdb.topo.noData'))
|
this.$message.error(this.$t('cmdb.topo.noData'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// this.$nextTick(() => {
|
this.$refs.showTopoView.setJsonData(_.cloneDeep(_graphJsonData), async () => {
|
||||||
this.$refs.showTopoView.setJsonData(_graphJsonData)
|
this.topoViewSearchValue = ''
|
||||||
// })
|
|
||||||
|
// map 结构存储 节点
|
||||||
|
const nodeMap = _graphJsonData.nodes.reduce((map, node) => {
|
||||||
|
map.set(node.id, node)
|
||||||
|
return map
|
||||||
|
}, new Map())
|
||||||
|
_graphJsonData.nodes = nodeMap
|
||||||
|
|
||||||
|
if (this?.topoViewOption?.aggregation_count) {
|
||||||
|
const instance = this.$refs.showTopoView.getInstance()
|
||||||
|
const nodes = instance.getNodes()
|
||||||
|
const rootNodes = nodes.filter((node) => node.lot.level === 0)
|
||||||
|
rootNodes.forEach((node) => {
|
||||||
|
this.initMoreNodesData(node, _graphJsonData)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$refs.showTopoView.setJsonData(_.cloneDeep({
|
||||||
|
nodes: _graphJsonData.nodes.values(),
|
||||||
|
links: _graphJsonData.links
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
this.topoViewJsonData = _graphJsonData
|
||||||
|
this.changeTopoViewToolbarLang(this.$i18n.locale)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化子节点分页数据
|
||||||
|
*/
|
||||||
|
initMoreNodesData(node, jsonData) {
|
||||||
|
const childs = node.lot.childs
|
||||||
|
// 没有子节点 终止遍历
|
||||||
|
if (!childs?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子节点分页数量
|
||||||
|
const aggregation_count = this?.topoViewOption?.aggregation_count || 1
|
||||||
|
// 展示节点数量
|
||||||
|
let showNodeCount = 0
|
||||||
|
|
||||||
|
childs.forEach((childNode, index) => {
|
||||||
|
if (childNode?.data?.btnType !== 'more') {
|
||||||
|
if (showNodeCount >= aggregation_count) {
|
||||||
|
const originNode = jsonData?.nodes?.get(childNode.id)
|
||||||
|
if (originNode) {
|
||||||
|
originNode.isHide = true
|
||||||
|
}
|
||||||
|
} else if (!childNode.isHide) {
|
||||||
|
showNodeCount++
|
||||||
|
}
|
||||||
|
this.initMoreNodesData(childNode, jsonData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (childs.length - showNodeCount > 0) {
|
||||||
|
const id = uuidv4()
|
||||||
|
jsonData.nodes.set(id, {
|
||||||
|
id,
|
||||||
|
text: `展示更多(${childs.length - showNodeCount})`,
|
||||||
|
data: {
|
||||||
|
btnType: 'more'
|
||||||
|
},
|
||||||
|
color: 'transparent',
|
||||||
|
styleClass: {
|
||||||
|
padding: '0px'
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
jsonData.links.push({
|
||||||
|
from: node.id,
|
||||||
|
to: id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async clickMoreBtn(node) {
|
||||||
|
const childs = node?.lot?.parent?.lot?.childs
|
||||||
|
if (childs?.length) {
|
||||||
|
const topoViewJsonData = this.topoViewJsonData
|
||||||
|
let moreBtnNode = null
|
||||||
|
let showNodeCount = 0
|
||||||
|
let toggleNodeCount = 0
|
||||||
|
const aggregation_count = this?.topoViewOption?.aggregation_count || 1
|
||||||
|
|
||||||
|
childs.forEach((child) => {
|
||||||
|
if (!child.isHide) {
|
||||||
|
showNodeCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toggleNodeCount < aggregation_count && child.isHide) {
|
||||||
|
const childNode = topoViewJsonData?.nodes?.get(child.id)
|
||||||
|
if (childNode) {
|
||||||
|
childNode.isHide = false
|
||||||
|
toggleNodeCount++
|
||||||
|
showNodeCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.data.btnType === 'more') {
|
||||||
|
moreBtnNode = topoViewJsonData?.nodes?.get(child.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (moreBtnNode) {
|
||||||
|
if (showNodeCount === childs.length) {
|
||||||
|
moreBtnNode.isHide = true
|
||||||
|
} else {
|
||||||
|
moreBtnNode.text = `展示更多(${childs.length - showNodeCount})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = this.$refs.showTopoView.getInstance()
|
||||||
|
instance.setJsonData(
|
||||||
|
{
|
||||||
|
links: topoViewJsonData.links,
|
||||||
|
nodes: topoViewJsonData.nodes.values()
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
this.topoViewJsonData = topoViewJsonData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handleOpenCmdb() {
|
handleOpenCmdb() {
|
||||||
this.$refs.cmdbDrawer.open()
|
this.$refs.cmdbDrawer.open()
|
||||||
},
|
},
|
||||||
|
@ -921,9 +1154,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async showNodeTips(nodeObject, $event) {
|
async showNodeTips(nodeObject, $event) {
|
||||||
console.log('node click')
|
console.log('node click', nodeObject)
|
||||||
$event.preventDefault()
|
$event.preventDefault()
|
||||||
$event.stopPropagation()
|
$event.stopPropagation()
|
||||||
|
|
||||||
|
const btnType = nodeObject?.data?.btnType
|
||||||
|
if (btnType === 'more') {
|
||||||
|
this.clickMoreBtn(nodeObject)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const _base_position = this.$refs.showTopoView.getInstance().options.fullscreen ? { x: 0, y: 0 } : this.$refs.rightTopoView.getBoundingClientRect()
|
const _base_position = this.$refs.showTopoView.getInstance().options.fullscreen ? { x: 0, y: 0 } : this.$refs.rightTopoView.getBoundingClientRect()
|
||||||
if (this.currentNode !== nodeObject) {
|
if (this.currentNode !== nodeObject) {
|
||||||
this.currentNodeValues = null
|
this.currentNodeValues = null
|
||||||
|
@ -934,25 +1174,16 @@ export default {
|
||||||
const [ attributes ] = await Promise.all([getSubscribeAttributes(rawNode.type_id)])
|
const [ attributes ] = await Promise.all([getSubscribeAttributes(rawNode.type_id)])
|
||||||
this.currentNodeAttributes = attributes?.attributes || []
|
this.currentNodeAttributes = attributes?.attributes || []
|
||||||
if (!this.currentNodeAttributes.length) {
|
if (!this.currentNodeAttributes.length) {
|
||||||
this.errorMessage = this.$t('cmdb.topo.noPreferenceAttributes')
|
this.handleNullNodeTips(this.$t('cmdb.topo.noPreferenceAttributes'))
|
||||||
this.errorMessageShow = true
|
|
||||||
this.currentNodeValues = null
|
|
||||||
this.isShowNodeTipsPanel = false
|
|
||||||
}
|
}
|
||||||
await searchCI({ q: `_id:${rawNode.id}` }, false).then(res => {
|
await searchCI({ q: `_id:${rawNode.id}` }, false).then(res => {
|
||||||
if (!res.result.length) {
|
if (!res.result.length) {
|
||||||
this.errorMessage = this.$t('cmdb.topo.noInstancePerm')
|
this.handleNullNodeTips(this.$t('cmdb.topo.noInstancePerm'))
|
||||||
this.errorMessageShow = true
|
|
||||||
this.currentNodeValues = null
|
|
||||||
this.isShowNodeTipsPanel = false
|
|
||||||
} else {
|
} else {
|
||||||
this.currentNodeValues = res.result[0]
|
this.currentNodeValues = res.result[0]
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.errorMessage = ((error.response || {}).data || {}).message
|
this.handleNullNodeTips(((error.response || {}).data || {}).message)
|
||||||
this.errorMessageShow = true
|
|
||||||
this.currentNodeValues = null
|
|
||||||
this.isShowNodeTipsPanel = false
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -971,9 +1202,71 @@ export default {
|
||||||
this.isShowNodeTipsPanel = true
|
this.isShowNodeTipsPanel = true
|
||||||
console.log(this.nodeTipsPosition)
|
console.log(this.nodeTipsPosition)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleNullNodeTips(errorMessage) {
|
||||||
|
this.errorMessage = errorMessage
|
||||||
|
this.errorMessageShow = true
|
||||||
|
this.currentNodeValues = null
|
||||||
|
this.isShowNodeTipsPanel = false
|
||||||
|
this.currentNode = {}
|
||||||
|
},
|
||||||
|
|
||||||
hideNodeTips(nodeObject, $event) {
|
hideNodeTips(nodeObject, $event) {
|
||||||
this.isShowNodeTipsPanel = false
|
this.isShowNodeTipsPanel = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleSearchTopoView(v) {
|
||||||
|
const topoViewJsonData = this.topoViewJsonData
|
||||||
|
topoViewJsonData.nodes.keys().forEach((key) => {
|
||||||
|
const node = topoViewJsonData?.nodes?.get(key)
|
||||||
|
if (node?.data?.btnType !== 'more') {
|
||||||
|
node.opacity = node?.text?.indexOf(v) !== -1 ? 1 : 0.1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const instance = this.$refs.showTopoView.getInstance()
|
||||||
|
instance.setJsonData(
|
||||||
|
{
|
||||||
|
links: topoViewJsonData.links,
|
||||||
|
nodes: topoViewJsonData.nodes.values()
|
||||||
|
},
|
||||||
|
false
|
||||||
|
)
|
||||||
|
this.topoViewJsonData = topoViewJsonData
|
||||||
|
},
|
||||||
|
|
||||||
|
changeTopoViewToolbarLang(lang) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const toolbarElements = document.getElementsByClassName('rel-toolbar')
|
||||||
|
const zhlangMap = {
|
||||||
|
'全屏/退出全屏': 'Full Screen/Exit Full Screen',
|
||||||
|
'放大': 'zoom in',
|
||||||
|
'缩小': 'zoom out',
|
||||||
|
'刷新': 'refresh ',
|
||||||
|
'下载图片': 'download image'
|
||||||
|
}
|
||||||
|
const enlangMap = {
|
||||||
|
'Full Screen/Exit Full Screen': '全屏/退出全屏',
|
||||||
|
'zoom in': '放大',
|
||||||
|
'zoom out': '缩小',
|
||||||
|
'refresh': '刷新 ',
|
||||||
|
'download image': '下载图片'
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarElements.forEach((toolbarElement) => {
|
||||||
|
if (toolbarElement?.children?.length) {
|
||||||
|
toolbarElement.children.forEach((node) => {
|
||||||
|
const oldTitle = node?.getAttribute('title')
|
||||||
|
if (oldTitle) {
|
||||||
|
const newTitle = lang === 'en' ? zhlangMap[oldTitle] : enlangMap[oldTitle]
|
||||||
|
if (newTitle) {
|
||||||
|
node.setAttribute('title', newTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 300)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1098,6 +1391,14 @@ export default {
|
||||||
top: 40%;
|
top: 40%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.relation-graph-search {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.topo-left,
|
.topo-left,
|
||||||
.topo-right {
|
.topo-right {
|
||||||
|
@ -1133,6 +1434,54 @@ export default {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.relation-graph-node {
|
||||||
|
padding: 6px 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
background-color: transparent;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-text {
|
||||||
|
color: #000000;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-left: 6px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-image {
|
||||||
|
max-height: 20px;
|
||||||
|
max-width: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .relation-graph {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
|
||||||
|
.rel-node {
|
||||||
|
padding: 0px;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
.rel-node-checked {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.c-expanded {
|
||||||
|
background-color: rgb(64, 158, 255) !important;
|
||||||
|
}
|
||||||
|
.c-collapsed {
|
||||||
|
background-color: rgb(64, 158, 255) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
|
Loading…
Reference in New Issue