123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- <template>
- <div class="flex-row"
- style="height: 100%">
- <div id="leftPanel"
- class="flex-col road"
- v-if="showLeftBar">
- <div class="flex1 flex-col panel"
- style="height:0">
- <b class="panel-header">
- <a-icon type="deployment-unit"/>
- 显示实体类
- </b>
- <a-spin :spinning="loadingTree" style="max-height: 500px;" class="auto-overflow flex1">
- <a-checkbox v-model="checkAllEntcls" @change="onCheckAllChange"> 全选 </a-checkbox>
- <a-tree checkable
- :defaultSelectedKeys="selectTreeNodeIdList"
- v-model="checkedKeys"
- @select="onSelect"
- @check="onCheckEntCls"
- :treeData="treeData"
- :selectedKeys.sync="selectTreeNodeIdList"
- :expandedKeys.sync="expandedKeys"
- :autoExpandParent="autoExpandParent"
- class="entity-class-tree ">
- </a-tree>
- </a-spin>
- </div>
- <div class="flex1 flex-col panel" style="height:0">
- <b class="panel-header">
- <a-icon type="deployment-unit"/>
- 选择显示关系类
- </b>
- <a-spin :spinning="loadingChecked" class="auto-overflow" style="padding: 0 10px; margin: 5px -10px;">
- <a-checkbox-group id="mycheck"
- :options="allRelClsNameList"
- v-model="checkedRelClsNameList"
- @change="onChangeRelClsCheckBox">
- </a-checkbox-group>
- </a-spin>
- </div>
- </div>
- <a-spin :spinning="loadingChecked" class="flex1 panel flex-col" style="height: 100%">
- <chart-comp ref="chart"
- @="getInfoTooltip"
- :isShowContextMenu="true"
- @reloadChart="reloadChart"
- :nodes="nodes"
- :links="links"
- :enable="true"
- :isShowChart="true"></chart-comp>
- </a-spin>
- <entity-cls-details-tooltip class="chart_tooltip"
- :id="tooltip.entClsID"
- :key="tooltip.entClsID"
- v-if="tooltip.entClsID"
- style="position: absolute;z-index: 1;border-radius: 3px"
- :style="{'left': tooltip.x, 'top': tooltip.y}"></entity-cls-details-tooltip>
- <link-details-tooltip class="chart_tooltip"
- :id="tooltip.relClsID"
- :key="tooltip.relClsID"
- :entCls="relClsName"
- v-if="tooltip.relClsID"
- style="position: absolute;z-index: 1;border-radius: 3px"
- :style="{'left': tooltip.x, 'top': tooltip.y}"></link-details-tooltip>
- </div>
- </template>
- <script>
- import chartComp from '@/views/knowledge/common/chart'
- import entityClsDetailsTooltip from '@/views/knowledge/common/entClsDetails.vue'
- import linkDetailsTooltip from '@/views/knowledge/common/linkDetails.vue'
- import { getAllEntityClass } from '@/api/graph/entityClass'
- import { getAllRelationClass } from '@/api/graph/relationClass'
- import { getGraphEntClsTree } from '@/api/graph/statisticalMap'
-
- // 获取路径参数
- function getQueryVariable(variable) {
- let url = window.location.hash
- let index = url.indexOf('?')
- var query = url.substring(index + 1, url.length)
- var vars = query.split('&')
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split('=')
- if (pair[0] == variable) {
- return pair[1]
- }
- }
- return ''
- }
- const gData = [] // 左侧实体类树
- const dataList = []
- // 根据树生成一个列表
- const generateList = (data) => {
- for (let i = 0; i < data.length; i++) {
- const node = data[i]
- const key = node.key
- dataList.push({key, title: node.entClsName, entClsName: node.entClsName})
- if (node.children) {
- generateList(node.children, node.key)
- }
- }
- }
- // 得到需要展开的父节点key
- const getParentKey = (key, tree) => {
- let parentKey
- for (let i = 0; i < tree.length; i++) {
- const node = tree[i]
- if (node.children) {
- if (node.children.some(item => item.key === key)) {
- parentKey = node.key
- } else {
- const tp = getParentKey(key, node.children)
- if (tp) {
- parentKey = tp
- }
- }
- }
- }
- return parentKey
- }
- // 遍历一个树节点 找寻所有的子id
- const getIdsList = (root) => {
- let ids = []
- if (root.entClsID) ids.push(root.entClsID)
- if (root.children && root.children.length) {
- for (let i = 0; i < root.children.length; i++) {
- ids = ids.concat(getIdsList(root.children[i]))
- }
- }
- return ids
- }
- export default {
- components: {chartComp, entityClsDetailsTooltip, linkDetailsTooltip},
- data() {
- return {
- loadingTree: false,
- loadingChecked: false,
- checkAllEntcls: true,
- nodes: null,
- links: null,
- tooltip: {entClsID: false, relClsID: false},
- relClsName: '',
- expandedKeys: [], // 要展开的节点
- searchValue: '', // 搜索的实体类名字
- autoExpandParent: true,
- gData,
- selectTreeNodeIdList: [],
- checkedKeys: [], // 默认全部选中
- relClsList: [], // 关系类列表
- allRelClsNameList: [],// 所有的关系类名列表
- checkedRelClsNameList: [], // 去重的关系类名列表
- allEntClassCache: [], // 初始页面缓存所有的实体类
- allLinksCache: [], // 初始页面缓存所有的路径信息
- filEntClass: undefined, // 选择树处理后的实体类
- filLinks: undefined, // 处理后的路径信息links
- showLeftBar: true //是否显示左侧可选框
- }
- },
- computed: {
- /**
- * 默认初始全部选中的关系类
- **/
- checkedRelCls() {
- var checkedIdList = []
- this.relClsList.forEach((v, i) => {
- if (v.checked === undefined || v.checked === true) {
- checkedIdList.push(v.value)
- }
- })
- return checkedIdList
- },
- /**
- * 实际绑定在树上的变量,根据rootId可能有不同
- **/
- treeData() {
- var returnData = []
- if (this.rootId) {
- // 搜索根节点
- this.$utils.tree.walk(this.gData, (node) => {
- if (node.entClsID === this.rootId) {
- returnData = [node]
- return false
- }
- })
- } else {
- returnData = this.gData
- }
- // 如果有搜索字符串
- var searchStr = this.searchValue
- if (searchStr) {
- // 向上遍历到所有要展开的父节点
- const expandedKeys = dataList.map((item) => {
- if (item.title.indexOf(searchStr) > -1) {
- return getParentKey(item.key, returnData) // 返回要展开的父节点keys
- }
- return null
- }).filter((item, i, self) => item && self.indexOf(item) === i)
- // 设定展开
- Object.assign(this, {
- expandedKeys,
- autoExpandParent: true
- })
- // 遍历整个树
- var showParentNodeList = []
- this.$utils.tree.walk(returnData, (node, index, way) => {
- if (node.entClsName.indexOf(searchStr) > -1) {
- node.style = ''
- showParentNodeList = showParentNodeList.concat(way)
- } else {
- node.style = 'display:none'
- }
- })
- for (var i = 0; i < showParentNodeList.length; i++) {
- showParentNodeList[i].style = ''
- }
- } else {
- // 没有搜索串,遍历清空display:none
- this.$utils.tree.walk(returnData, (node) => {
- node.style = ''
- })
- }
- return returnData
- }
- },
- created() {
- this.showLeftBar = getQueryVariable('showLeftBar') === 'false' ? false : true;
- let clsId = getQueryVariable('clsId')
- this.refreshEntityClassList(clsId)
- /**
- * 请求数据,获取所有实体类的信息,然后根据pid组装出实体类之间的关系
- * */
- this.loadingChecked = true
- Promise.all([getAllEntityClass(true), getAllRelationClass()]).then((resp) => {
- let links = []
- resp[0].data.forEach((v) => {
- v.id = v.entClsID
- v.label = v.entClsName
- if (v.pid !== null) {
- let fromId = v.pid, toId = v.entClsID
- const item = {
- id: fromId + '_' + toId
- }
- item.from = v.pid
- item.to = v.entClsID
- item.classType = 'dashed'
- links.push(item)
- }
- })
- var relClassNameTempMap = {}
- resp[1].data.forEach((v) => {
- const item = {
- label: v.relClsName,
- value: v.relClsID,
- checked: true
- }
- v.from = v.startID
- v.to = v.endID
- v.id = v.relClsID
- v.label = v.relClsName
- this.relClsList.push(item)
- relClassNameTempMap[v.relClsName] = true
- })
- //去掉重复关系类名
- for (let name in relClassNameTempMap) {
- this.allRelClsNameList.push({
- label: name,
- value: name
- })
- this.checkedRelClsNameList.push(name)
- }
- links = links.concat(resp[1].data)
- this.allEntClassCache = resp[0]
- this.filLinks = this.allLinksCache = links
- if (clsId) { // 路径中存在实体类id
- this.onCheckEntCls(this.checkedKeys)
- } else {
- this.drawChart(resp[0].data, links)
- }
- this.loadingChecked = false
- })
- },
- methods: {
- reloadChart(nodes, links) {
- this.drawChart(nodes, links)
- },
- /**
- * 画图
- * @params nodes: 处理好的实体数据, link: 处理好的关系数据
- * */
- drawChart(nodes, links) {
- this.nodes = nodes
- this.links = links
- this.$refs.chart.destroyChart() // 先清空chart实例,再绘图
- this.$refs.chart.reDraw(undefined, nodes, links)
- },
- /**
- * 获取实体或关系的悬浮框
- * @params event:zoomchart返回的event,args:zoomchart返回的变量,包含了当前点击的实体或关系的数据
- * */
- getInfoTooltip(event, args) {
- const vm = this
- this.$set(this.tooltip, 'x', event.pageX + 'px')
- this.$set(this.tooltip, 'y', event.pageY + 'px')
- if (args.clickNode) {
- vm.tooltip.entClsID = args.clickNode.data.entClsID
- vm.tooltip.relClsID = false
- } else if (args.clickLink) {
- vm.tooltip.entClsID = false
- vm.tooltip.relClsID = args.clickLink.data.relClsID
- vm.relClsName = args.clickLink.data.relClsName
- } else {
- vm.tooltip.entClsID = false
- vm.tooltip.relClsID = false
- }
- },
- // 全选
- onCheckAllChange() {
- const allEntCls = []
- this.allEntClassCache.map(v => {
- allEntCls.push(v.entClsID)
- })
- this.onCheckEntCls(this.checkAllEntcls ? allEntCls : [])
- this.checkedKeys = this.checkAllEntcls ? allEntCls : []
- },
- onSelect(keys, node) {
- let entClsID = node.node.dataRef.entClsID
- this.expandedKeys = keys // 选中展开的key
- },
- /**
- * 改变实体类
- */
- onCheckEntCls(checkedKeys) {
- // 过滤缓存中的实体类 得到新的实体类
- let entClass = this.allEntClassCache.filter((v, i) => {
- return checkedKeys.includes(v.entClsID)
- })
- // 过滤缓存中的实体类 保存到data中,用于过滤
- this.filEntClass = entClass
- // 过滤缓存中的路径信息 得到新的路径
- let links = this.allLinksCache.filter((v, i) => {
- if (v.classType === 'dashed') {
- return checkedKeys.includes(v.from) && checkedKeys.includes(v.to)
- } else if (v.relClsID) {
- return checkedKeys.includes(v.from) && checkedKeys.includes(v.to)
- }
- })
- const relClassNameTempMap = {},
- allRelClsNameList = [],
- checkedRelClsNameList = []
- // 重新计算关系类列表 去掉重名计算
- links.forEach((v) => {
- if (v.relClsName) {
- relClassNameTempMap[v.relClsName] = true;
- }
- })
- for (let name in relClassNameTempMap) {
- allRelClsNameList.push({
- label: name,
- value: name
- })
- checkedRelClsNameList.push(name)
- }
- this.allRelClsNameList = allRelClsNameList
- this.checkedRelClsNameList = checkedRelClsNameList
- // 改变关系类checkbox
- // 缓存到data中,方便计算路径信息
- this.filLinks = links
- // 过滤掉,节点不存在的边
- const chatLinks = links.filter((link) => {
- return checkedKeys.includes(link.from) && checkedKeys.includes(link.to)
- })
- // 重画chart
- this.drawChart(JSON.parse(JSON.stringify(entClass)), chatLinks)
- },
- /**
- * 进入页面刷新实体类树
- */
- refreshEntityClassList(clsId) {
- this.loadingTree = true
- getGraphEntClsTree().then((data) => {
- for (let i = 0; i < data.length; i++) {
- data[i]['key'] = data[i]['entClsID']
- data[i]['title'] = data[i]['entClsName']
- data[i]['scopedSlots'] = {title: 'custom'}
- if (!data[i]['pid']) {
- this.checkedKeys.push(data[i]['entClsID'])
- }
- }
- // 此处传固定的option
- const option = {
- idName: 'entClsID',
- pidName: 'pid',
- childName: 'children',
- returnList: []
- }
- let treeData = this.$utils.tree.listToTree(data, option) // 数组转成树
- if (clsId) { // 如果路径中存在实体类id
- for (let z = 0; z < treeData.length; z++) {
- if (treeData[z]['entClsID'] === clsId) {
- this.checkedKeys = getIdsList(treeData[z])
- }
- }
- }
- this.gData = treeData
- generateList(treeData) // 生成个列表
- const vm = this
- // 遍历树找到父节点下面的所有子节点
- this.$utils.tree.walk(treeData, function (node, index, way) {
- var id = clsId // 路由中的id
- var myWay = [] // 需要找到的展开节点key
- if (node.key === id) {
- for (let i = 0; i < way.length; i++) {
- myWay.push(way[i]['key'])
- }
- vm.expandedKeys = myWay
- return false
- }
- })
- this.loadingTree = false
- })
- },
- /**
- *改变关系类checkbox
- */
- onChangeRelClsCheckBox(checkedValues) {
- let entClass, links
- if (this.filEntClass !== undefined) {
- entClass = this.filEntClass
- } else {
- entClass = this.allEntClassCache
- }
- links = this.filLinks.filter((v, i) => {
- if (v.classType === 'dashed') {
- return true
- } else if (v.relClsID) {
- return checkedValues.includes(v.relClsName)
- }
- })
- // 过滤掉,节点不存在的边
- const chartLinks = links.filter((link) => {
- return !!entClass.find(ent => (ent.id === link.from || ent.id === link.to))
- })
- // 重绘echart
- this.drawChart(entClass, chartLinks)
- }
- },
- watch: {},
- mounted() {
- }
- }
- </script>
- <style>
- /*覆盖样式加的id*/
- #mycheck.ant-checkbox-group {
- max-width: none;
- }
- .ant-spin-container {
- height: 100%;
- }
- </style>
|