relation view has been optimised

This commit is contained in:
pycook 2019-12-03 19:10:54 +08:00
parent 8ee7c6daf8
commit 92dd4c5dfe
13 changed files with 241 additions and 83 deletions

View File

@ -67,7 +67,7 @@ def init_cache():
ci_relations = CIRelation.get_by(to_dict=False) ci_relations = CIRelation.get_by(to_dict=False)
relations = dict() relations = dict()
for cr in ci_relations: for cr in ci_relations:
relations.setdefault(cr.first_ci_id, []).append(cr.second_ci_id) relations.setdefault(cr.first_ci_id, {}).update({cr.second_ci_id: cr.second_ci.type_id})
for i in relations: for i in relations:
relations[i] = json.dumps(relations[i]) relations[i] = json.dumps(relations[i])
if relations: if relations:

View File

@ -566,4 +566,4 @@ class CIRelationManager(object):
ci_relation_delete.apply_async(args=(first_ci_id, second_ci_id), queue=CMDB_QUEUE) ci_relation_delete.apply_async(args=(first_ci_id, second_ci_id), queue=CMDB_QUEUE)
return cls.delete(cr.cr_id) return cls.delete(cr.id)

View File

@ -13,6 +13,7 @@ from api.lib.cmdb.cache import AttributeCache
from api.lib.cmdb.cache import CITypeAttributeCache from api.lib.cmdb.cache import CITypeAttributeCache
from api.lib.cmdb.cache import CITypeCache from api.lib.cmdb.cache import CITypeCache
from api.models.cmdb import CITypeAttribute from api.models.cmdb import CITypeAttribute
from api.models.cmdb import CITypeRelation
from api.models.cmdb import PreferenceRelationView from api.models.cmdb import PreferenceRelationView
from api.models.cmdb import PreferenceShowAttributes from api.models.cmdb import PreferenceShowAttributes
from api.models.cmdb import PreferenceTreeView from api.models.cmdb import PreferenceTreeView
@ -124,17 +125,28 @@ class PreferenceManager(object):
for i in result[view_name]: for i in result[view_name]:
id2type[i['parent_id']] = None id2type[i['parent_id']] = None
id2type[i['child_id']] = None id2type[i['child_id']] = None
topo = {i['child_id']: {i['parent_id']} for i in result[view_name]}
leaf = list(set(toposort.toposort_flatten(topo)) - set([j for i in topo.values() for j in i]))
result[view_name] = toposort.toposort_flatten( leaf2show_types = {i: [t['child_id'] for t in CITypeRelation.get_by(parent_id=i)] for i in leaf}
{i['child_id']: {i['parent_id']} for i in result[view_name]})
result[view_name] = dict(topo=list(map(list, toposort.toposort(topo))),
topo_flatten=list(toposort.toposort_flatten(topo)),
leaf=leaf,
leaf2show_types=leaf2show_types,
show_types=[CITypeCache.get(j).to_dict()
for i in leaf2show_types.values() for j in i])
for type_id in id2type: for type_id in id2type:
id2type[type_id] = CITypeCache.get(type_id).to_dict() id2type[type_id] = CITypeCache.get(type_id).to_dict()
print(result)
return result, id2type, sorted(name2id, key=lambda x: x[1]) return result, id2type, sorted(name2id, key=lambda x: x[1])
@classmethod @classmethod
def create_or_update_relation_view(cls, name, cr_ids): def create_or_update_relation_view(cls, name, cr_ids):
if not cr_ids:
return abort(400, "Node must be selected")
existed = PreferenceRelationView.get_by(name=name, to_dict=False, first=True) existed = PreferenceRelationView.get_by(name=name, to_dict=False, first=True)
if existed is None: if existed is None:
PreferenceRelationView.create(name=name, cr_ids=json.dumps(cr_ids)) PreferenceRelationView.create(name=name, cr_ids=json.dumps(cr_ids))
@ -145,4 +157,5 @@ class PreferenceManager(object):
def delete_relation_view(name): def delete_relation_view(name):
for existed in PreferenceRelationView.get_by(name=name, to_dict=False): for existed in PreferenceRelationView.get_by(name=name, to_dict=False):
existed.soft_delete() existed.soft_delete()
return name return name

View File

@ -73,6 +73,10 @@ class Search(object):
def _in_query_handle(self, attr, v): def _in_query_handle(self, attr, v):
terms = v[1:-1].split(";") terms = v[1:-1].split(";")
operator = "|" operator = "|"
if attr in ('_type', 'ci_type', 'type_id') and terms and terms[0].isdigit():
attr = "type_id"
terms = map(int, terms)
current_app.logger.warning(terms)
for term in terms: for term in terms:
self._operator2query(operator).append({ self._operator2query(operator).append({
"term": { "term": {
@ -164,6 +168,7 @@ class Search(object):
def _query_build_raw(self): def _query_build_raw(self):
queries = handle_arg_list(self.orig_query) queries = handle_arg_list(self.orig_query)
current_app.logger.debug(queries) current_app.logger.debug(queries)
self.__query_build_by_field(queries) self.__query_build_by_field(queries)

View File

@ -15,7 +15,14 @@ from api.models.cmdb import CI
class Search(object): class Search(object):
def __init__(self, root_id, level=1, query=None, fl=None, facet_field=None, page=1, count=None, sort=None): def __init__(self, root_id,
level=1,
query=None,
fl=None,
facet_field=None,
page=1,
count=None,
sort=None):
self.orig_query = query self.orig_query = query
self.fl = fl self.fl = fl
self.facet_field = facet_field self.facet_field = facet_field
@ -24,22 +31,36 @@ class Search(object):
self.sort = sort or ("ci_id" if current_app.config.get("USE_ES") else None) self.sort = sort or ("ci_id" if current_app.config.get("USE_ES") else None)
self.root_id = root_id self.root_id = root_id
self.level = int(level) self.level = level
def search(self): def search(self):
ci = CI.get_by_id(self.root_id) or abort(404, "CI <{0}> does not exist".format(self.root_id))
ids = [self.root_id] if not isinstance(self.root_id, list) else self.root_id ids = [self.root_id] if not isinstance(self.root_id, list) else self.root_id
for _ in range(0, self.level): cis = [CI.get_by_id(_id) or abort(404, "CI <{0}> does not exist".format(_id)) for _id in ids]
print(rd.get(ids, REDIS_PREFIX_CI_RELATION))
_tmp = list(map(json.loads, filter(lambda x: x is not None, rd.get(ids, REDIS_PREFIX_CI_RELATION) or []))) merge_ids = []
ids = [j for i in _tmp for j in i] for level in self.level:
ids = [self.root_id] if not isinstance(self.root_id, list) else self.root_id
for _ in range(0, level):
_tmp = list(map(lambda x: list(json.loads(x).keys()),
filter(lambda x: x is not None, rd.get(ids, REDIS_PREFIX_CI_RELATION) or [])))
ids = [j for i in _tmp for j in i]
merge_ids.extend(ids)
if not self.orig_query or ("_type:" not in self.orig_query if not self.orig_query or ("_type:" not in self.orig_query
and "type_id:" not in self.orig_query and "type_id:" not in self.orig_query
and "ci_type:" not in self.orig_query): and "ci_type:" not in self.orig_query):
type_ids = CITypeRelationManager.get_child_type_ids(ci.type_id, self.level) type_ids = []
self.orig_query = "_type:({0}),{1}".format(";".join(list(map(str, type_ids))), self.orig_query) for level in self.level:
for ci in cis:
type_ids.extend(CITypeRelationManager.get_child_type_ids(ci.type_id, level))
type_ids = list(set(type_ids))
if self.orig_query:
self.orig_query = "_type:({0}),{1}".format(";".join(list(map(str, type_ids))), self.orig_query)
else:
self.orig_query = "_type:({0})".format(";".join(list(map(str, type_ids))))
if not ids: if not merge_ids:
# cis, counter, total, self.page, numfound, facet_ # cis, counter, total, self.page, numfound, facet_
return [], {}, 0, self.page, 0, {} return [], {}, 0, self.page, 0, {}
@ -50,7 +71,7 @@ class Search(object):
page=self.page, page=self.page,
count=self.count, count=self.count,
sort=self.sort, sort=self.sort,
ci_ids=ids).search() ci_ids=merge_ids).search()
else: else:
return SearchFromDB(self.orig_query, return SearchFromDB(self.orig_query,
fl=self.fl, fl=self.fl,
@ -58,18 +79,28 @@ class Search(object):
page=self.page, page=self.page,
count=self.count, count=self.count,
sort=self.sort, sort=self.sort,
ci_ids=ids).search() ci_ids=merge_ids).search()
def statistics(self): def statistics(self, type_ids):
ids = [self.root_id] if not isinstance(self.root_id, list) else self.root_id ids = [self.root_id] if not isinstance(self.root_id, list) else self.root_id
for l in range(0, self.level): for l in range(0, int(self.level)):
if l == 0: if l == 0:
_tmp = list(map(json.loads, [i or '[]' for i in rd.get(ids, REDIS_PREFIX_CI_RELATION) or []])) _tmp = list(map(lambda x: list(json.loads(x).keys()),
[i or '{}' for i in rd.get(ids, REDIS_PREFIX_CI_RELATION) or []]))
else: else:
for idx, i in enumerate(_tmp): for idx, i in enumerate(_tmp):
if i: if i:
__tmp = list(map(json.loads, filter(lambda x: x is not None, if type_ids and l == self.level - 1:
rd.get(i, REDIS_PREFIX_CI_RELATION) or []))) __tmp = list(
map(lambda x: list({_id: 1 for _id, type_id in json.loads(x).items()
if type_id in type_ids}.keys()),
filter(lambda x: x is not None,
rd.get(i, REDIS_PREFIX_CI_RELATION) or [])))
else:
__tmp = list(map(lambda x: list(json.loads(x).keys()),
filter(lambda x: x is not None,
rd.get(i, REDIS_PREFIX_CI_RELATION) or [])))
_tmp[idx] = [j for i in __tmp for j in i] _tmp[idx] = [j for i in __tmp for j in i]
else: else:
_tmp[idx] = [] _tmp[idx] = []

View File

@ -90,7 +90,7 @@ class RoleRelationCRUD(object):
@staticmethod @staticmethod
def delete2(parent_id, child_id): def delete2(parent_id, child_id):
existed = RoleRelation.get_by(parent_id=parent_id, child_id=child_id) existed = RoleRelation.get_by(parent_id=parent_id, child_id=child_id, first=True, to_dict=False)
existed or abort(400, "RoleRelation < {0} -> {1} > does not exist".format(parent_id, child_id)) existed or abort(400, "RoleRelation < {0} -> {1} > does not exist".format(parent_id, child_id))
existed.soft_delete() existed.soft_delete()

View File

@ -14,6 +14,7 @@ from api.extensions import rd
from api.lib.cmdb.const import CMDB_QUEUE from api.lib.cmdb.const import CMDB_QUEUE
from api.lib.cmdb.const import REDIS_PREFIX_CI from api.lib.cmdb.const import REDIS_PREFIX_CI
from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION from api.lib.cmdb.const import REDIS_PREFIX_CI_RELATION
from api.models.cmdb import CIRelation
@celery.task(name="cmdb.ci_cache", queue=CMDB_QUEUE) @celery.task(name="cmdb.ci_cache", queue=CMDB_QUEUE)
@ -46,10 +47,13 @@ def ci_delete(ci_id):
@celery.task(name="cmdb.ci_relation_cache", queue=CMDB_QUEUE) @celery.task(name="cmdb.ci_relation_cache", queue=CMDB_QUEUE)
def ci_relation_cache(parent_id, child_id): def ci_relation_cache(parent_id, child_id):
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0] children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
children = json.loads(children) if children is not None else [] children = json.loads(children) if children is not None else {}
children.append(child_id)
rd.create_or_update({parent_id: json.dumps(list(set(children)))}, REDIS_PREFIX_CI_RELATION) cr = CIRelation.get_by(first_ci_id=parent_id, second_ci_id=child_id, first=True, to_dict=False)
if child_id not in children:
children[child_id] = cr.second_ci.type_id
rd.create_or_update({parent_id: json.dumps(children)}, REDIS_PREFIX_CI_RELATION)
current_app.logger.info("ADD ci relation cache: {0} -> {1}".format(parent_id, child_id)) current_app.logger.info("ADD ci relation cache: {0} -> {1}".format(parent_id, child_id))
@ -57,10 +61,11 @@ def ci_relation_cache(parent_id, child_id):
@celery.task(name="cmdb.ci_relation_delete", queue=CMDB_QUEUE) @celery.task(name="cmdb.ci_relation_delete", queue=CMDB_QUEUE)
def ci_relation_delete(parent_id, child_id): def ci_relation_delete(parent_id, child_id):
children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0] children = rd.get([parent_id], REDIS_PREFIX_CI_RELATION)[0]
children = json.loads(children) if children is not None else [] children = json.loads(children) if children is not None else {}
if child_id in children:
children.remove(child_id)
rd.create_or_update({parent_id: json.dumps(list(set(children)))}, REDIS_PREFIX_CI_RELATION) if child_id in children:
children.pop(child_id)
rd.create_or_update({parent_id: json.dumps(children)}, REDIS_PREFIX_CI_RELATION)
current_app.logger.info("DELETE ci relation cache: {0} -> {1}".format(parent_id, child_id)) current_app.logger.info("DELETE ci relation cache: {0} -> {1}".format(parent_id, child_id))

View File

@ -34,7 +34,7 @@ class CIRelationSearchView(APIView):
count = get_page_size(request.values.get("count") or request.values.get("page_size")) count = get_page_size(request.values.get("count") or request.values.get("page_size"))
root_id = request.values.get('root_id') root_id = request.values.get('root_id')
level = request.values.get('level', 1) level = list(map(int, handle_arg_list(request.values.get('level', '1'))))
query = request.values.get('q', "") query = request.values.get('q', "")
fl = handle_arg_list(request.values.get('fl', "")) fl = handle_arg_list(request.values.get('fl', ""))
@ -64,11 +64,12 @@ class CIRelationStatisticsView(APIView):
def get(self): def get(self):
root_ids = list(map(int, handle_arg_list(request.values.get('root_ids')))) root_ids = list(map(int, handle_arg_list(request.values.get('root_ids'))))
level = request.values.get('level', 1) level = request.values.get('level', 1)
type_ids = set(map(int, handle_arg_list(request.values.get('type_ids', []))))
start = time.time() start = time.time()
s = Search(root_ids, level) s = Search(root_ids, level)
try: try:
result = s.statistics() result = s.statistics(type_ids)
except SearchError as e: except SearchError as e:
return abort(400, str(e)) return abort(400, str(e))
current_app.logger.debug("search time is :{0}".format(time.time() - start)) current_app.logger.debug("search time is :{0}".format(time.time() - start))

View File

@ -77,6 +77,7 @@ class PreferenceRelationApiView(APIView):
@role_required(RoleEnum.CONFIG) @role_required(RoleEnum.CONFIG)
@args_required("name") @args_required("name")
@args_required("cr_ids")
def post(self): def post(self):
name = request.values.get("name") name = request.values.get("name")
cr_ids = request.values.get("cr_ids") cr_ids = request.values.get("cr_ids")

View File

@ -68,7 +68,7 @@
</a-col> </a-col>
</template> </template>
<a-col :lg="!advanced && 6 || 24" :md="!advanced && 8 || 24" :sm="24" style="float: right"> <a-col :lg="!advanced && 6 || 24" :md="!advanced && 8 || 24" :sm="24" style="float: right; padding-left: 0">
<span <span
class="table-page-search-submitButtons" class="table-page-search-submitButtons"
:style="advanced && { float: 'right', overflow: 'hidden' } || {} " :style="advanced && { float: 'right', overflow: 'hidden' } || {} "

View File

@ -1,7 +1,13 @@
<template> <template>
<div> <div>
<a-card :bordered="true" title="关系视图定义面板"> <a-card :bordered="true" title="关系视图定义面板">
<a-card-meta description="点击右键可选择节点"></a-card-meta> <a-card-meta description="先打开右上角的开关,便可选择树的节点"></a-card-meta>
<a-switch
slot="extra"
@change="toggleSelect"
checkedChildren="on"
unCheckedChildren="off"
/>
<div <div
id="visualization" id="visualization"
style="height:400px" style="height:400px"
@ -9,7 +15,7 @@
@mouseup="mouseUp" @mouseup="mouseUp"
@mousemove="mouseMove"> @mousemove="mouseMove">
</div> </div>
<relation-view-form ref="relationViewForm"></relation-view-form> <relation-view-form @refresh="reload" ref="relationViewForm"></relation-view-form>
</a-card> </a-card>
<a-row :gutter="0"> <a-row :gutter="0">
@ -23,7 +29,7 @@
v-for="view in Object.keys(relationViews.views)"> v-for="view in Object.keys(relationViews.views)">
<a-card :bordered="true" :title="view"> <a-card :bordered="true" :title="view">
<a slot="extra"><a-icon type="close" @click="deleteView(view)"></a-icon></a> <a slot="extra"><a-icon type="close" @click="deleteView(view)"></a-icon></a>
<div :id="&quot;view-&quot; + (relationViews.views[view] || []).join(&quot;&quot;)" style="height:200px"></div> <div :id="&quot;view-&quot; + (relationViews.views[view].topo_flatten || []).join(&quot;&quot;)" style="height:200px"></div>
</a-card> </a-card>
</a-col> </a-col>
</a-row> </a-row>
@ -32,7 +38,6 @@
</template> </template>
<script> <script>
// 按需引入
import { DataSet, Network } from 'vis-network' import { DataSet, Network } from 'vis-network'
import { getCITypeRelations } from '@/api/cmdb/CITypeRelation' import { getCITypeRelations } from '@/api/cmdb/CITypeRelation'
import { getRelationView, deleteRelationView } from '@/api/cmdb/preference' import { getRelationView, deleteRelationView } from '@/api/cmdb/preference'
@ -48,12 +53,15 @@ export default {
relationViews: { views: {} }, relationViews: { views: {} },
relations: [], relations: [],
network: null, network: null,
options: {},
viewData: {},
container: null, container: null,
nodes: null, nodes: null,
edges: null, edges: null,
canvas: null, canvas: null,
ctx: null, ctx: null,
drag: false, drag: false,
canSelect: false,
rect: {}, rect: {},
drawingSurfaceImageData: null drawingSurfaceImageData: null
} }
@ -61,6 +69,7 @@ export default {
created () { created () {
this.create() this.create()
}, },
inject: ['reload'],
methods: { methods: {
create () { create () {
getRelationView().then(res => { getRelationView().then(res => {
@ -145,30 +154,54 @@ export default {
// initialize your network! // initialize your network!
this.container.oncontextmenu = () => { return false } this.container.oncontextmenu = () => { return false }
this.options = options
this.viewData = data
this.network = new Network(this.container, data, options) this.network = new Network(this.container, data, options)
this.canvas = this.network.canvas.frame.canvas this.canvas = this.network.canvas.frame.canvas
this.ctx = this.canvas.getContext('2d') this.ctx = this.canvas.getContext('2d')
}) })
}, },
toggleSelect (checked) {
if (checked) {
this.canSelect = true
this.options.autoResize = false
this.options.interaction.hover = false
this.options.interaction.dragView = false
this.options.interaction.dragNodes = false
this.network = new Network(this.container, this.viewData, this.options)
this.canvas = this.network.canvas.frame.canvas
this.ctx = this.canvas.getContext('2d')
} else {
this.canSelect = false
this.options.autoResize = true
this.options.interaction.hover = true
this.options.interaction.dragView = true
this.options.interaction.dragNodes = true
this.network = new Network(this.container, this.viewData, this.options)
this.canvas = this.network.canvas.frame.canvas
this.ctx = this.canvas.getContext('2d')
}
},
createRelationViews () { createRelationViews () {
Object.keys(this.relationViews.views).forEach(viewName => { Object.keys(this.relationViews.views).forEach(viewName => {
const nodes = [] const nodes = []
const edges = [] const edges = []
const len = this.relationViews.views[viewName].length const len = this.relationViews.views[viewName].topo_flatten.length
this.relationViews.views[viewName].slice(0, len - 1).forEach((fromId, idx) => { this.relationViews.views[viewName].topo_flatten.slice(0, len - 1).forEach((fromId, idx) => {
nodes.push({ nodes.push({
id: fromId, id: fromId,
label: this.relationViews.id2type[fromId].alias label: this.relationViews.id2type[fromId].alias
}) })
edges.push({ edges.push({
from: fromId, from: fromId,
to: this.relationViews.views[viewName][idx + 1] to: this.relationViews.views[viewName].topo_flatten[idx + 1]
}) })
}) })
nodes.push({ nodes.push({
id: this.relationViews.views[viewName][len - 1], id: this.relationViews.views[viewName].topo_flatten[len - 1],
label: this.relationViews.id2type[this.relationViews.views[viewName][len - 1]].alias label: this.relationViews.id2type[this.relationViews.views[viewName].topo_flatten[len - 1]].alias
}) })
const _nodes = new DataSet(nodes) const _nodes = new DataSet(nodes)
const _edges = new DataSet(edges) const _edges = new DataSet(edges)
@ -208,9 +241,9 @@ export default {
} }
} }
setTimeout(() => { setTimeout(() => {
const container = document.querySelector('#view-' + this.relationViews.views[viewName].join('')) const container = document.querySelector('#view-' + this.relationViews.views[viewName].topo_flatten.join(''))
const n = new Network(container, data, options) const n = new Network(container, data, options)
console.log(n) console.log(n) // TODO
}, 100) }, 100)
}) })
}, },
@ -274,7 +307,7 @@ export default {
}, },
mouseDown () { mouseDown () {
if (event.button === 2) { if (event.button === 0 && this.canSelect) {
this.saveDrawingSurface() this.saveDrawingSurface()
this.rect.startX = event.offsetX this.rect.startX = event.offsetX
this.rect.startY = event.offsetY this.rect.startY = event.offsetY
@ -284,7 +317,7 @@ export default {
}, },
mouseUp () { mouseUp () {
if (event.button === 2) { if (event.button === 0 && this.canSelect) {
this.restoreDrawingSurface() this.restoreDrawingSurface()
this.drag = false this.drag = false

View File

@ -119,6 +119,7 @@ export default {
.then(res => { .then(res => {
this.$message.success(`添加成功`) this.$message.success(`添加成功`)
this.onClose() this.onClose()
this.$emit('refresh')
}) })
.catch(err => this.requestFailed(err)) .catch(err => this.requestFailed(err))
}, },

View File

@ -1,6 +1,6 @@
<template> <template>
<a-card :bordered="false"> <a-card :bordered="false" class="relation-card">
<a-menu v-model="current" mode="horizontal" v-if="relationViews.name2id && relationViews.name2id.length"> <a-menu v-model="currentView" mode="horizontal" v-if="relationViews.name2id && relationViews.name2id.length">
<a-menu-item :key="item[1]" v-for="item in relationViews.name2id"> <a-menu-item :key="item[1]" v-for="item in relationViews.name2id">
<router-link <router-link
:to="{name: 'cmdb_relation_views_item', params: { viewId: item[1]} }" :to="{name: 'cmdb_relation_views_item', params: { viewId: item[1]} }"
@ -15,9 +15,14 @@
<a-tree showLine :loadData="onLoadData" @select="onSelect" :treeData="treeData"></a-tree> <a-tree showLine :loadData="onLoadData" @select="onSelect" :treeData="treeData"></a-tree>
</a-col> </a-col>
<a-col :span="19"> <a-col :span="19">
<search-form ref="search" @refresh="refreshTable" :preferenceAttrList="preferenceAttrList" /> <a-menu v-model="currentTypeId" mode="horizontal" v-if="showTypeIds && showTypeIds.length > 1">
<a-menu-item :key="item.id" v-for="item in showTypes">
<a @click="changeCIType(item.id)">{{ item.alias || item.name }}</a>
</a-menu-item>
</a-menu>
<search-form style="margin-top: 10px" ref="search" @refresh="refreshTable" :preferenceAttrList="preferenceAttrList" />
<s-table <s-table
v-if="levels.length > 1" v-if="levels.length"
bordered bordered
ref="table" ref="table"
size="middle" size="middle"
@ -49,16 +54,22 @@ export default {
}, },
data () { data () {
return { return {
parameter: {},
treeData: [], treeData: [],
triggerSelect: false, triggerSelect: false,
treeNode: null, treeNode: null,
ciTypes: [], ciTypes: [],
relationViews: {}, relationViews: {},
levels: [], levels: [],
showTypeIds: [],
showTypes: [],
leaf2showTypes: {},
leaf: [],
typeId: null, typeId: null,
viewId: null, viewId: null,
viewName: null, viewName: null,
current: [], currentView: [],
currentTypeId: [],
instanceList: [], instanceList: [],
treeKeys: [], treeKeys: [],
columns: [], columns: [],
@ -70,8 +81,9 @@ export default {
loadInstances: parameter => { loadInstances: parameter => {
console.log(parameter, 'load instances') console.log(parameter, 'load instances')
this.parameter = parameter
const params = Object.assign(parameter || {}, this.$refs.search.queryParam) const params = Object.assign(parameter || {}, this.$refs.search.queryParam)
let q = `q=_type:${this.levels[this.levels.length - 1]}` let q = `q=_type:${this.currentTypeId[0]}`
Object.keys(params).forEach(key => { Object.keys(params).forEach(key => {
if (!['pageNo', 'pageSize', 'sortField', 'sortOrder'].includes(key) && params[key] + '' !== '') { if (!['pageNo', 'pageSize', 'sortField', 'sortOrder'].includes(key) && params[key] + '' !== '') {
if (typeof params[key] === 'object' && params[key].length > 1) { if (typeof params[key] === 'object' && params[key].length > 1) {
@ -109,15 +121,36 @@ export default {
if (res.numfound !== 0) { if (res.numfound !== 0) {
setTimeout(() => { setTimeout(() => {
this.setColumnWidth() this.setColumnWidth()
}, 200) console.log('set column')
}, 300)
} }
this.loadRoot() this.loadRoot()
return result return result
}) })
} }
q += `&root_id=${this.treeKeys[this.treeKeys.length - 1]}` q += `&root_id=${this.treeKeys[this.treeKeys.length - 1].split('_')[0]}`
q += `&level=${this.levels.length - this.treeKeys.length}` const typeId = parseInt(this.treeKeys[this.treeKeys.length - 1].split('_')[1])
let level = []
if (!this.leaf.includes(typeId)) {
let startIdx = 0
this.levels.forEach((item, idx) => {
if (item.includes(typeId)) {
startIdx = idx
}
})
this.leaf.forEach(leafId => {
this.levels.forEach((item, levelIdx) => {
if (item.includes(leafId) && levelIdx - startIdx + 1 > 0) {
level.push(levelIdx - startIdx + 1)
}
})
})
} else {
level = [1]
}
q += `&level=${level.join(',')}`
if (q[0] === '&') { if (q[0] === '&') {
q = q.slice(1) q = q.slice(1)
} }
@ -133,10 +166,10 @@ export default {
if (res.numfound !== 0) { if (res.numfound !== 0) {
setTimeout(() => { setTimeout(() => {
this.setColumnWidth() this.setColumnWidth()
}, 200) console.log('set column')
this.loadNoRoot(this.treeKeys[this.treeKeys.length - 1], this.levels.length - this.treeKeys.length - 1) }, 300)
this.loadNoRoot(this.treeKeys[this.treeKeys.length - 1], level)
} }
return result return result
}) })
} }
@ -161,40 +194,63 @@ export default {
this.$refs.table.refresh(bool) this.$refs.table.refresh(bool)
}, },
loadRoot () { changeCIType (typeId) {
searchCI(`q=_type:${this.levels[0]}&count=10000`).then(res => { this.currentTypeId = [typeId]
this.loadColumns(typeId)
this.$refs.table.renderClear()
setTimeout(() => {
this.refreshTable(true)
}, 100)
},
async loadRoot () {
searchCI(`q=_type:(${this.levels[0].join(';')})&count=10000`).then(async res => {
const facet = [] const facet = []
const ciIds = [] const ciIds = []
res.result.forEach(item => { res.result.forEach(item => {
facet.push([item[item.unique], 0, item.ci_id]) facet.push([item[item.unique], 0, item.ci_id, item.type_id])
ciIds.push(item.ci_id) ciIds.push(item.ci_id)
}) })
statisticsCIRelation({ root_ids: ciIds.join(','), level: this.levels.length - 1 }).then(num => { const promises = this.leaf.map(leafId => {
facet.forEach((item, idx) => { let level = 0
item[1] = num[ciIds[idx] + ''] this.levels.forEach((item, idx) => {
if (item.includes(leafId)) {
level = idx + 1
}
})
return statisticsCIRelation({ root_ids: ciIds.join(','), level: level }).then(num => {
facet.forEach((item, idx) => {
item[1] += num[ciIds[idx] + '']
})
}) })
this.wrapTreeData(facet)
}) })
await Promise.all(promises)
this.wrapTreeData(facet)
}) })
}, },
loadNoRoot (rootId, level) { async loadNoRoot (rootIdAndTypeId, level) {
if (level === 0) { const rootId = rootIdAndTypeId.split('_')[0]
return
} searchCIRelation(`root_id=${rootId}&level=1&count=10000`).then(async res => {
searchCIRelation(`root_id=${rootId}&level=1&count=10000`).then(res => {
const facet = [] const facet = []
const ciIds = [] const ciIds = []
res.result.forEach(item => { res.result.forEach(item => {
facet.push([item[item.unique], 0, item.ci_id]) facet.push([item[item.unique], 0, item.ci_id, item.type_id])
ciIds.push(item.ci_id) ciIds.push(item.ci_id)
}) })
statisticsCIRelation({ root_ids: ciIds.join(','), level: level }).then(num => {
facet.forEach((item, idx) => { const promises = level.map(_level => {
item[1] = num[ciIds[idx] + ''] if (_level > 1) {
}) return statisticsCIRelation({ root_ids: ciIds.join(','), level: _level - 1 }).then(num => {
this.wrapTreeData(facet) facet.forEach((item, idx) => {
item[1] += num[ciIds[idx] + '']
})
})
}
}) })
await Promise.all(promises)
this.wrapTreeData(facet)
}) })
}, },
@ -214,8 +270,8 @@ export default {
facet.forEach(item => { facet.forEach(item => {
treeData.push({ treeData.push({
title: `${item[0]} (${item[1]})`, title: `${item[0]} (${item[1]})`,
key: this.treeKeys.join('-') + '-' + item[2], key: this.treeKeys.join('-') + '-' + item[2] + '_' + item[3],
isLeaf: this.levels.length - 2 === this.treeKeys.length isLeaf: this.leaf.includes(item[3])
}) })
}) })
if (this.treeNode === null) { if (this.treeNode === null) {
@ -269,16 +325,25 @@ export default {
this.viewName = item[0] this.viewName = item[0]
} }
}) })
this.levels = this.relationViews.views[this.viewName] this.levels = this.relationViews.views[this.viewName].topo
this.current = [this.viewId] this.showTypes = this.relationViews.views[this.viewName].show_types
this.typeId = this.levels[0] const showTypeIds = []
this.showTypes.forEach(item => {
showTypeIds.push(item.id)
})
this.showTypeIds = showTypeIds
this.leaf2showTypes = this.relationViews.views[this.viewName].leaf2show_types
this.leaf = this.relationViews.views[this.viewName].leaf
this.currentView = [this.viewId]
this.currentTypeId = [this.showTypeIds[0]]
this.typeId = this.levels[0][0]
this.loadColumns() this.loadColumns()
this.$refs.table && this.$refs.table.refresh(true) this.$refs.table && this.$refs.table.refresh(true)
} }
}) })
}, },
loadColumns () { loadColumns () {
getSubscribeAttributes(this.levels[this.levels.length - 1]).then(res => { getSubscribeAttributes(this.currentTypeId[0]).then(res => {
const prefAttrList = res.attributes const prefAttrList = res.attributes
this.preferenceAttrList = prefAttrList this.preferenceAttrList = prefAttrList
@ -309,11 +374,14 @@ export default {
} }
</script> </script>
<style scoped> <style lang='less'>
.ant-menu-horizontal { .ant-menu-horizontal {
border-bottom: 1px solid #ebedf0 !important; border-bottom: 1px solid #ebedf0 !important;
} }
.ant-menu-horizontal { .ant-menu-horizontal {
border-bottom: 1px solid #ebedf0 !important; border-bottom: 1px solid #ebedf0 !important;
} }
.relation-card > .ant-card-body {
padding-top: 0 !important;
}
</style> </style>