|
|
@ -191,18 +191,54 @@ |
|
|
</span> |
|
|
</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="selectListInfo" |
|
|
|
|
|
style="z-index: 2000; |
|
|
|
|
|
max-height:35vw; |
|
|
|
|
|
border-radius: 2px; |
|
|
|
|
|
padding: 5px 0; |
|
|
|
|
|
background-color: rgba(76,100,233,0.3) ;position:absolute;left: 5vw;top: 12vw;font-size: 0.9vw;overflow-y: scroll;margin-left: 1vw;margin-right: 1vw;"> |
|
|
|
|
|
<div class="flow-tree" :class="{ 'flow-tree-active': i === currentShowLeve }" v-for="i in currentGroup === 2 ? [1, 2] : [1, 2, 3, 4]" style="padding: 0vw 2vw;" @click="changeLeve(i)"> |
|
|
|
|
|
<span class="custom-tree-node" style="display: flex;flex-direction: row;"> |
|
|
|
|
|
<div class="lineInfo" :class="{ 'lineInfo-active': i === currentShowLeve }" style="width: 0.2vw;height: 0.8vw; box-shadow: #FFFFFF 0px 0px 4px 1px; |
|
|
|
|
|
background: rgb(255, 255, 255);display: inline-block; |
|
|
|
|
|
margin-top: 0.6vw;margin-right: 0.5vw;"></div> |
|
|
|
|
|
|
|
|
|
|
|
<div class="label1" style="color: #ffffff;font-size: 1.1vw;cursor: pointer;line-height: 2vw;">展示层级{{i}}</div> |
|
|
|
|
|
</span> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="graphContent"> |
|
|
<div class="graphContent"> |
|
|
<div :class="full ? 'full-screen' : 'show-box'"> |
|
|
<div :class="full ? 'full-screen' : 'show-box'"> |
|
|
|
|
|
|
|
|
<!-- 节点右键菜单 --> |
|
|
<!-- 节点右键菜单 --> |
|
|
<div style="width: 100%;height: 100%;"> |
|
|
<div style="width: 100%;height: 100%;"> |
|
|
<div class="gContainer"> |
|
|
<div ref="myPage" class="gContainer" @click="isShowNodeMenuPanel = false"> |
|
|
<RelationGraph ref="graphRef" :options="graphOptions" :nodes="graphData.nodes" :links="graphData.links" |
|
|
<RelationGraph ref="graphRef" :options="graphOptions" :nodes="graphData.nodes" :links="graphData.links" |
|
|
:on-node-click="onNodeClick" |
|
|
:on-node-click="onNodeClick" |
|
|
:on-line-click="onLineClick" |
|
|
:on-line-click="onLineClick" |
|
|
:on-node-expand="onNodeExpand" |
|
|
> |
|
|
:on-node-collapse="onNodeCollapse" |
|
|
<template #node="{node}"> |
|
|
/> |
|
|
<div style="height: 100%; " @click="showNodeMenus(node, $event)" |
|
|
|
|
|
@contextmenu.prevent.stop="showNodeMenus(node, $event)"> |
|
|
|
|
|
<div style="width: 80%; position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);font-size: 30px" |
|
|
|
|
|
|
|
|
|
|
|
> |
|
|
|
|
|
{{ node.text }} |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
</template> |
|
|
|
|
|
</RelationGraph> |
|
|
|
|
|
<div v-show="isShowNodeMenuPanel" :style="{left: nodeMenuPanelPosition.x + 'px', top: nodeMenuPanelPosition.y + 'px' }" style="z-index: 999;padding:10px;background-color: #ffffff;border:#eeeeee solid 1px;box-shadow: 0px 0px 8px #cccccc;position: absolute;border-radius: 10px;"> |
|
|
|
|
|
<div style="line-height: 25px;padding-left: 10px;color: #888888;font-size: 12px;">对这个节点进行操作:</div> |
|
|
|
|
|
<div class="c-node-menu-item" @click.stop="toNodeInfo">查看节点</div> |
|
|
|
|
|
<div class="c-node-menu-item" @click.stop="showOrHide">{{currentNode.expanded?'收回':'扩展'}}</div> |
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
@ -261,6 +297,9 @@ export default { |
|
|
}, |
|
|
}, |
|
|
data() { |
|
|
data() { |
|
|
return { |
|
|
return { |
|
|
|
|
|
isShowCodePanel: false, |
|
|
|
|
|
isShowNodeMenuPanel: false, |
|
|
|
|
|
nodeMenuPanelPosition: { x: 0, y: 0 }, |
|
|
currentGroup:1, |
|
|
currentGroup:1, |
|
|
direction: "rtl", |
|
|
direction: "rtl", |
|
|
// visGraph实例对象 |
|
|
// visGraph实例对象 |
|
|
@ -290,12 +329,6 @@ export default { |
|
|
data: [] //提示内部的数据 |
|
|
data: [] //提示内部的数据 |
|
|
}, |
|
|
}, |
|
|
graphOptions: { |
|
|
graphOptions: { |
|
|
// 启用展开/折叠按钮 |
|
|
|
|
|
defaultExpandHolderPosition: 'right', // 按钮显示位置:'left' 或 'right' |
|
|
|
|
|
defaultExpandHolderSize: 16, |
|
|
|
|
|
defaultExpandHolderColor: '#fff', |
|
|
|
|
|
defaultExpandHolderBorder: '1px solid #00d7e0', |
|
|
|
|
|
isMoveByParentNode: true, |
|
|
|
|
|
allowSwitchLineShape: true, |
|
|
allowSwitchLineShape: true, |
|
|
allowSwitchJunctionPoint: true, |
|
|
allowSwitchJunctionPoint: true, |
|
|
defaultLineColor: '#2E74B5', |
|
|
defaultLineColor: '#2E74B5', |
|
|
@ -317,15 +350,8 @@ export default { |
|
|
// 布局核心:使用 center 布局实现环形 |
|
|
// 布局核心:使用 center 布局实现环形 |
|
|
layout: { |
|
|
layout: { |
|
|
layoutName: 'center', // 关键:使用 center 布局 |
|
|
layoutName: 'center', // 关键:使用 center 布局 |
|
|
from: 'center', // 从中心向外扩展 |
|
|
levelDistance: '1000,1000,1000,1000,3000,3000,3000,3000', // 每一层的半径(可动态修改) |
|
|
levelDistance: '700,700,900,900,1000,1000,1000,1000', // 每一层的半径(可动态修改) |
|
|
|
|
|
nodeDistance: 20, // 同一层节点间的最小角度间距(影响密度) |
|
|
|
|
|
min_per_width: 300, // 最小水平间隔(角度相关) |
|
|
|
|
|
max_per_width: 500, |
|
|
|
|
|
clockwise: true, // 是否顺时针排列 |
|
|
|
|
|
startAngle: -Math.PI / 2, // 起始角度(-90°,顶部开始) |
|
|
startAngle: -Math.PI / 2, // 起始角度(-90°,顶部开始) |
|
|
preventOverlap: true, // 防止重叠 |
|
|
|
|
|
distance_coefficient: 5, |
|
|
|
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
currentNode: {}, // 选中的节点对象 |
|
|
currentNode: {}, // 选中的节点对象 |
|
|
@ -401,22 +427,49 @@ export default { |
|
|
level: 'titleLevel', |
|
|
level: 'titleLevel', |
|
|
docLevel: 'docLevel', |
|
|
docLevel: 'docLevel', |
|
|
}, |
|
|
}, |
|
|
heightlightTable:[] |
|
|
heightlightTable:[], |
|
|
|
|
|
currentShowLeve:1, |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
methods: { |
|
|
methods: { |
|
|
changeGroup(groupId){ |
|
|
showNodeMenus(nodeObject, $event) { |
|
|
this.currentGroup = groupId |
|
|
this.currentNode = nodeObject; |
|
|
this.getInfo() |
|
|
const _base_position = this.$refs.myPage.getBoundingClientRect(); |
|
|
|
|
|
this.isShowNodeMenuPanel = true; |
|
|
|
|
|
this.nodeMenuPanelPosition.x = $event.clientX - _base_position.x; |
|
|
|
|
|
this.nodeMenuPanelPosition.y = $event.clientY - _base_position.y; |
|
|
}, |
|
|
}, |
|
|
onNodeCollapse(node, e) { |
|
|
showOrHide(){ |
|
|
this.$refs.graphRef.refresh(); |
|
|
this.currentNode.expanded = !this.currentNode.expanded |
|
|
|
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
|
|
|
graphInstance.doLayout() |
|
|
}, |
|
|
}, |
|
|
|
|
|
toNodeInfo() { |
|
|
|
|
|
let nodeObject = this.currentNode |
|
|
|
|
|
console.log(nodeObject) |
|
|
|
|
|
const data = { |
|
|
|
|
|
'id': nodeObject.data.docId, |
|
|
|
|
|
'docTitle': nodeObject.text, |
|
|
|
|
|
} |
|
|
|
|
|
getDocInfo(data).then((res) => { |
|
|
|
|
|
localStorage.setItem("docUrl", res.data.docUrl) |
|
|
|
|
|
this.$router.push({ |
|
|
|
|
|
name: 'docInfo', |
|
|
|
|
|
query: { |
|
|
|
|
|
title: res.data.docTitle, |
|
|
|
|
|
level: res.data.docLevel, |
|
|
|
|
|
keyword: res.data.docTitle, |
|
|
|
|
|
docId: res.data.id |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 节点展开时触发 |
|
|
this.isShowNodeMenuPanel = false; |
|
|
onNodeExpand(node, e) { |
|
|
}, |
|
|
this.$refs.graphRef.refresh(); |
|
|
changeGroup(groupId){ |
|
|
|
|
|
this.currentGroup = groupId |
|
|
|
|
|
this.getInfo() |
|
|
}, |
|
|
}, |
|
|
handleNodeClick(node) { |
|
|
handleNodeClick(node) { |
|
|
console.log(node); |
|
|
console.log(node); |
|
|
@ -538,8 +591,8 @@ export default { |
|
|
data.g13["docTitle"] = data.g13["name"] |
|
|
data.g13["docTitle"] = data.g13["name"] |
|
|
data.g14["level"] = 1 |
|
|
data.g14["level"] = 1 |
|
|
data.g14["docTitle"] = data.g14["name"] |
|
|
data.g14["docTitle"] = data.g14["name"] |
|
|
// data.g15["level"] = 1 |
|
|
data.g15["level"] = 1 |
|
|
// data.g15["docTitle"] = data.g15["name"] |
|
|
data.g15["docTitle"] = data.g15["name"] |
|
|
data.g21["level"] = 1 |
|
|
data.g21["level"] = 1 |
|
|
data.g21["docTitle"] = data.g21["name"] |
|
|
data.g21["docTitle"] = data.g21["name"] |
|
|
data.g22["level"] = 1 |
|
|
data.g22["level"] = 1 |
|
|
@ -553,7 +606,7 @@ export default { |
|
|
this.data1.push(data.g12) |
|
|
this.data1.push(data.g12) |
|
|
this.data1.push(data.g13) |
|
|
this.data1.push(data.g13) |
|
|
this.data1.push(data.g14) |
|
|
this.data1.push(data.g14) |
|
|
// this.data1.push(data.g15) |
|
|
this.data1.push(data.g15) |
|
|
this.data1.push(data.g21) |
|
|
this.data1.push(data.g21) |
|
|
this.data1.push(data.g22) |
|
|
this.data1.push(data.g22) |
|
|
}) |
|
|
}) |
|
|
@ -661,7 +714,6 @@ export default { |
|
|
return found ? 'nodeclass' : 'nodeclassnormal'; |
|
|
return found ? 'nodeclass' : 'nodeclassnormal'; |
|
|
}, |
|
|
}, |
|
|
getLinesClass(mergedDbIds) { |
|
|
getLinesClass(mergedDbIds) { |
|
|
console.log("44444444444444") |
|
|
|
|
|
const lines = this.heightLight.links; |
|
|
const lines = this.heightLight.links; |
|
|
if (lines == undefined){ |
|
|
if (lines == undefined){ |
|
|
return "" |
|
|
return "" |
|
|
@ -723,9 +775,46 @@ export default { |
|
|
// line.sourceAsMap.data |
|
|
// line.sourceAsMap.data |
|
|
this.drawer = true; |
|
|
this.drawer = true; |
|
|
}, |
|
|
}, |
|
|
//整理图谱数据 |
|
|
getNodeColor(leve){ |
|
|
//整理图谱数据 |
|
|
let color = "" |
|
|
//整理图谱数据 |
|
|
switch (leve) { |
|
|
|
|
|
case "0": |
|
|
|
|
|
color = '#ffd602'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "1": |
|
|
|
|
|
color = 'rgb(64, 158, 255)'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "2": |
|
|
|
|
|
color = '#ff8c00'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "3": |
|
|
|
|
|
color = '#67c23a'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "4": |
|
|
|
|
|
color = 'rgb(248,143,248)'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "5": |
|
|
|
|
|
color = 'rgb(65,154,255)'; |
|
|
|
|
|
break; |
|
|
|
|
|
case "6": |
|
|
|
|
|
color = 'rgb(0,228,255)'; |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
color = 'rgba(255, 255, 255, 0.6)'; |
|
|
|
|
|
} |
|
|
|
|
|
console.log(color) |
|
|
|
|
|
return color; |
|
|
|
|
|
}, |
|
|
|
|
|
getExpanded(leve){ |
|
|
|
|
|
if (leve<this.currentShowLeve){ |
|
|
|
|
|
return true |
|
|
|
|
|
} |
|
|
|
|
|
return false |
|
|
|
|
|
}, |
|
|
|
|
|
changeLeve(leve){ |
|
|
|
|
|
this.currentShowLeve = leve |
|
|
|
|
|
this.getInfo() |
|
|
|
|
|
}, |
|
|
zhengl(data) { |
|
|
zhengl(data) { |
|
|
console.log(data) |
|
|
console.log(data) |
|
|
const nodes = [] |
|
|
const nodes = [] |
|
|
@ -733,12 +822,6 @@ export default { |
|
|
const nodeList = data.nodes; |
|
|
const nodeList = data.nodes; |
|
|
const lineList = data.links; |
|
|
const lineList = data.links; |
|
|
|
|
|
|
|
|
// 创建节点映射表,方便查找 |
|
|
|
|
|
const nodeMap = {}; |
|
|
|
|
|
nodeList.forEach(node => { |
|
|
|
|
|
nodeMap[node.id] = node; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 找出有连接的节点 |
|
|
// 找出有连接的节点 |
|
|
const connectedNodeIds = new Set(); |
|
|
const connectedNodeIds = new Set(); |
|
|
lineList.forEach(line => { |
|
|
lineList.forEach(line => { |
|
|
@ -746,423 +829,74 @@ export default { |
|
|
connectedNodeIds.add(line.target); |
|
|
connectedNodeIds.add(line.target); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 按层级和组别分组孤立节点 |
|
|
|
|
|
const isolatedNodesByGroupAndLevel = {}; |
|
|
// 在遍历前先按 docLeve 分组统计数量 |
|
|
nodeList.forEach(node => { |
|
|
const nodesByLevel = {}; |
|
|
if (!connectedNodeIds.has(node.id)) { |
|
|
for (let i = 0; i < nodeList.length; i++) { |
|
|
const groupId = node.groupId || '1'; |
|
|
const node = nodeList[i]; |
|
|
const level = node.docLeve || '0'; |
|
|
if (node.groupId == this.currentGroup || node.docLeve == "0") { |
|
|
if (!isolatedNodesByGroupAndLevel[groupId]) { |
|
|
// 仅孤立节点判断,超出层级不展示 |
|
|
isolatedNodesByGroupAndLevel[groupId] = {}; |
|
|
if (Number(node.docLeve) > this.currentShowLeve) { |
|
|
|
|
|
if (!connectedNodeIds.has(node.id)) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
if (!isolatedNodesByGroupAndLevel[groupId][level]) { |
|
|
|
|
|
isolatedNodesByGroupAndLevel[groupId][level] = []; |
|
|
const level = Number(node.docLeve); |
|
|
|
|
|
if (!nodesByLevel[level]) { |
|
|
|
|
|
nodesByLevel[level] = []; |
|
|
} |
|
|
} |
|
|
isolatedNodesByGroupAndLevel[groupId][level].push(node); |
|
|
nodesByLevel[level].push(node); |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
// 存储每个层级每个组别的节点位置信息 |
|
|
// 配置参数 |
|
|
const levelGroupPositions = {}; |
|
|
const baseRadius = 1200; // 每层之间的半径差 |
|
|
|
|
|
const centerX = 0, centerY = 0; |
|
|
// 处理有连接的节点 |
|
|
|
|
|
if (nodeList != undefined) { |
|
|
|
|
|
// 按组别分组处理有连接的节点 |
|
|
|
|
|
const groupedNodes = { |
|
|
|
|
|
'0': {levels: {}}, |
|
|
|
|
|
'1': {levels: {}}, |
|
|
|
|
|
'2': {levels: {}} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 按组别和层级分类节点 |
|
|
|
|
|
nodeList.forEach(node => { |
|
|
|
|
|
if (connectedNodeIds.has(node.id)) { |
|
|
|
|
|
const groupId = node.groupId || '1'; |
|
|
|
|
|
const level = node.docLeve || '1'; |
|
|
|
|
|
if (!groupedNodes[groupId]) groupedNodes[groupId] = {levels: {}}; |
|
|
|
|
|
if (!groupedNodes[groupId].levels[level]) groupedNodes[groupId].levels[level] = []; |
|
|
|
|
|
groupedNodes[groupId].levels[level].push(node); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 定义组别的位置偏移 |
|
|
// 遍历每一层进行布局 |
|
|
const groupOffsets = { |
|
|
Object.keys(nodesByLevel).forEach(levelStr => { |
|
|
'0': -10200, // 左侧区域 |
|
|
const level = Number(levelStr); |
|
|
'1': 0, // 中间区域 |
|
|
const levelNodes = nodesByLevel[level]; |
|
|
'2': 10200 // 右侧区域 |
|
|
const total = levelNodes.length; |
|
|
}; |
|
|
const radius = level === 0 ? 0 : level * baseRadius; // level 0 放中心 |
|
|
|
|
|
|
|
|
// 处理每个组别的节点 |
|
|
levelNodes.forEach((node, index) => { |
|
|
Object.keys(groupedNodes).forEach(groupId => { |
|
|
let x, y; |
|
|
const groupData = groupedNodes[groupId]; |
|
|
|
|
|
const groupOffsetX = groupOffsets[groupId] || 0; |
|
|
|
|
|
|
|
|
|
|
|
// 处理每个层级的节点 |
|
|
|
|
|
Object.keys(groupData.levels).sort().forEach(level => { |
|
|
|
|
|
const levelNodes = groupData.levels[level].sort((a, b) => a.docId - b.docId); |
|
|
|
|
|
const levelNum = parseInt(level); |
|
|
|
|
|
|
|
|
|
|
|
// 计算该层级节点的起始X位置(考虑组别偏移) |
|
|
|
|
|
const startX = groupOffsetX - (levelNodes.length * 200) / 2; |
|
|
|
|
|
|
|
|
|
|
|
// 初始化该层级该组别的位置信息 |
|
|
|
|
|
const levelGroupKey = `${levelNum}_${groupId}`; |
|
|
|
|
|
if (!levelGroupPositions[levelGroupKey]) { |
|
|
|
|
|
levelGroupPositions[levelGroupKey] = { |
|
|
|
|
|
minX: startX, |
|
|
|
|
|
maxX: startX + levelNodes.length * 200, |
|
|
|
|
|
leftAvailableX: startX - 200, // 左侧可用位置 |
|
|
|
|
|
rightAvailableX: startX + 200, // 右侧可用位置 |
|
|
|
|
|
hasConnectedNodes: levelNodes.length > 0 |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
levelNodes.forEach((node, index) => { |
|
|
if (level === 0) { |
|
|
if (levelNum === 0) this.rootId = node.id; |
|
|
// 中心节点放在原点 |
|
|
|
|
|
x = 0; |
|
|
// 根据层级设置节点样式 |
|
|
y = 0; |
|
|
let color, fontSize, fontColor; |
|
|
} else { |
|
|
switch (levelNum) { |
|
|
// 计算极角 |
|
|
case 0: |
|
|
const angle = (2 * Math.PI / total) * index; // 均匀分布 |
|
|
color = 'rgb(227,203,0)'; |
|
|
x = centerX + radius * Math.cos(angle); |
|
|
fontSize = '30px'; |
|
|
y = centerY + radius * Math.sin(angle); |
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
} |
|
|
break; |
|
|
|
|
|
case 1: |
|
|
nodes.push({ |
|
|
color = 'rgb(47,47,230)'; |
|
|
id: node.id, |
|
|
fontSize = '30px'; |
|
|
text: node.name, |
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
data: { |
|
|
break; |
|
|
docId: node.docId, |
|
|
case 2: |
|
|
group: node.groupId |
|
|
color = 'rgb(255,138,0)'; |
|
|
}, |
|
|
fontSize = '30px'; |
|
|
level: node.docLeve, |
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
x: x, |
|
|
break; |
|
|
y: y, |
|
|
case 3: |
|
|
fixed: true, // 锁定位置 |
|
|
color = 'rgb(30,255,0)'; |
|
|
width: 250, |
|
|
fontSize = '30px'; |
|
|
height: 250, |
|
|
fontColor = 'rgb(0,0,0)'; |
|
|
color: this.getNodeColor(node.docLeve), |
|
|
break; |
|
|
expandHolderPosition: 'right', |
|
|
case 4: |
|
|
expanded: this.getExpanded(node.docLeve), |
|
|
color = 'rgb(248,143,248)'; |
|
|
styleClass: this.getNodeClass(node.name), |
|
|
fontSize = '30px'; |
|
|
|
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
break; |
|
|
|
|
|
case 5: |
|
|
|
|
|
color = 'rgb(65,154,255)'; |
|
|
|
|
|
fontSize = '30px'; |
|
|
|
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
break; |
|
|
|
|
|
case 6: |
|
|
|
|
|
color = 'rgb(0,228,255)'; |
|
|
|
|
|
fontSize = '30px'; |
|
|
|
|
|
fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
|
|
|
color = 'rgb(200,200,200)'; |
|
|
|
|
|
fontSize = '30px'; |
|
|
|
|
|
fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const x = startX + index * 200; |
|
|
|
|
|
// 修改点:当 groupId 为 '1' 时,Y 值反向 |
|
|
|
|
|
const y = groupId === '1' ? levelNum * -1400 : levelNum * 1400; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (node.groupId==this.currentGroup || node.docLeve=="0"){ |
|
|
|
|
|
// 添加节点 |
|
|
|
|
|
nodes.push({ |
|
|
|
|
|
fontSize:100, |
|
|
|
|
|
id: node.id, |
|
|
|
|
|
text: node.name, |
|
|
|
|
|
data: { |
|
|
|
|
|
docId: node.docId, |
|
|
|
|
|
group: node.groupId |
|
|
|
|
|
}, |
|
|
|
|
|
level: levelNum, |
|
|
|
|
|
// x: x, |
|
|
|
|
|
// y: y, |
|
|
|
|
|
// fixed: true, |
|
|
|
|
|
width: 220, |
|
|
|
|
|
height: 220, |
|
|
|
|
|
color: color, |
|
|
|
|
|
font: `normal ${fontSize} Arial`, |
|
|
|
|
|
// html:"<div><span>"+node.name+"</span></div>", |
|
|
|
|
|
fontColor: fontColor, |
|
|
|
|
|
expandHolderPosition: 'right', |
|
|
|
|
|
expanded: true, |
|
|
|
|
|
styleClass:this.getNodeClass(node.name), |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理孤立节点 - 放置在有连线节点的两侧 |
|
|
|
|
|
// Object.keys(isolatedNodesByGroupAndLevel).sort().forEach(groupId => { |
|
|
|
|
|
// const groupData = isolatedNodesByGroupAndLevel[groupId]; |
|
|
|
|
|
// const groupOffsetX = groupId === '0' ? -10200 : groupId === '1' ? 0 : 10200; |
|
|
|
|
|
// |
|
|
|
|
|
// Object.keys(groupData).sort().forEach(level => { |
|
|
|
|
|
// const levelNodes = groupData[level]; |
|
|
|
|
|
// const levelNum = parseInt(level); |
|
|
|
|
|
// |
|
|
|
|
|
// // 确定孤立节点的Y坐标(与有连接节点保持一致) |
|
|
|
|
|
// const y = groupId === '1' ? levelNum * -1400 : levelNum * 1400; |
|
|
|
|
|
// |
|
|
|
|
|
// // 获取或创建该层级该组别的位置信息 |
|
|
|
|
|
// const levelGroupKey = `${levelNum}_${groupId}`; |
|
|
|
|
|
// |
|
|
|
|
|
// // 先按docId排序孤立节点 |
|
|
|
|
|
// const sortedIsolatedNodes = levelNodes.sort((a, b) => a.docId - b.docId); |
|
|
|
|
|
// |
|
|
|
|
|
// if (!levelGroupPositions[levelGroupKey] || !levelGroupPositions[levelGroupKey].hasConnectedNodes) { |
|
|
|
|
|
// // 如果没有有连接的节点,居中展示孤立节点 |
|
|
|
|
|
// const totalWidth = sortedIsolatedNodes.length * 200; |
|
|
|
|
|
// const startX = groupOffsetX - totalWidth / 2; |
|
|
|
|
|
// |
|
|
|
|
|
// // 放置孤立节点(居中排列) |
|
|
|
|
|
// sortedIsolatedNodes.forEach((node, index) => { |
|
|
|
|
|
// // 根据层级设置节点样式 |
|
|
|
|
|
// let color, fontSize, fontColor; |
|
|
|
|
|
// switch (levelNum) { |
|
|
|
|
|
// case 0: |
|
|
|
|
|
// color = 'rgb(227,203,0)'; |
|
|
|
|
|
// fontSize = '70px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 1: |
|
|
|
|
|
// color = 'rgb(47,47,230)'; |
|
|
|
|
|
// fontSize = '68px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 2: |
|
|
|
|
|
// color = 'rgb(255,138,0)'; |
|
|
|
|
|
// fontSize = '50px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 3: |
|
|
|
|
|
// color = 'rgb(30,255,0)'; |
|
|
|
|
|
// fontSize = '40px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 4: |
|
|
|
|
|
// color = 'rgb(248,143,248)'; |
|
|
|
|
|
// fontSize = '32px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 5: |
|
|
|
|
|
// color = 'rgb(65,154,255)'; |
|
|
|
|
|
// fontSize = '30px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 6: |
|
|
|
|
|
// color = 'rgb(0,228,255)'; |
|
|
|
|
|
// fontSize = '28px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// default: |
|
|
|
|
|
// color = 'rgb(200,200,200)'; |
|
|
|
|
|
// fontSize = '24px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// const x = startX + index * 200; |
|
|
|
|
|
// |
|
|
|
|
|
// if (node.groupId==this.currentGroup || node.docLeve=="0"){ |
|
|
|
|
|
// // 添加节点 |
|
|
|
|
|
// nodes.push({ |
|
|
|
|
|
// id: node.id, |
|
|
|
|
|
// text: node.name, |
|
|
|
|
|
// data: { |
|
|
|
|
|
// docId: node.docId, |
|
|
|
|
|
// group: node.groupId |
|
|
|
|
|
// }, |
|
|
|
|
|
// level: levelNum, |
|
|
|
|
|
// // x: x, |
|
|
|
|
|
// // y: y, |
|
|
|
|
|
// // fixed: true, |
|
|
|
|
|
// width: 150, |
|
|
|
|
|
// height: 150, |
|
|
|
|
|
// color: color, |
|
|
|
|
|
// font: `normal ${fontSize} Arial`, |
|
|
|
|
|
// fontColor: fontColor, |
|
|
|
|
|
// expandHolderPosition: 'right', |
|
|
|
|
|
// expanded: true, |
|
|
|
|
|
// styleClass:this.getNodeClass(node.name), |
|
|
|
|
|
// }); |
|
|
|
|
|
// } |
|
|
|
|
|
// }); |
|
|
|
|
|
// } else { |
|
|
|
|
|
// // 如果有有连接的节点,在两侧放置孤立节点 |
|
|
|
|
|
// const positionInfo = levelGroupPositions[levelGroupKey]; |
|
|
|
|
|
// |
|
|
|
|
|
// // 将孤立节点分成两组:左侧和右侧 |
|
|
|
|
|
// const leftNodes = []; |
|
|
|
|
|
// const rightNodes = []; |
|
|
|
|
|
// |
|
|
|
|
|
// sortedIsolatedNodes.forEach((node, index) => { |
|
|
|
|
|
// if (index % 2 === 0) { |
|
|
|
|
|
// leftNodes.push(node); // 偶数索引放左侧 |
|
|
|
|
|
// } else { |
|
|
|
|
|
// rightNodes.push(node); // 奇数索引放右侧 |
|
|
|
|
|
// } |
|
|
|
|
|
// }); |
|
|
|
|
|
// |
|
|
|
|
|
// // 放置左侧孤立节点(从右往左排列) |
|
|
|
|
|
// let currentLeftX = positionInfo.leftAvailableX; |
|
|
|
|
|
// for (let i = leftNodes.length - 1; i >= 0; i--) { |
|
|
|
|
|
// const node = leftNodes[i]; |
|
|
|
|
|
// |
|
|
|
|
|
// // 根据层级设置节点样式 |
|
|
|
|
|
// let color, fontSize, fontColor; |
|
|
|
|
|
// switch (levelNum) { |
|
|
|
|
|
// case 0: |
|
|
|
|
|
// color = 'rgb(227,203,0)'; |
|
|
|
|
|
// fontSize = '70px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 1: |
|
|
|
|
|
// color = 'rgb(47,47,230)'; |
|
|
|
|
|
// fontSize = '68px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 2: |
|
|
|
|
|
// color = 'rgb(255,138,0)'; |
|
|
|
|
|
// fontSize = '50px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 3: |
|
|
|
|
|
// color = 'rgb(30,255,0)'; |
|
|
|
|
|
// fontSize = '40px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 4: |
|
|
|
|
|
// color = 'rgb(248,143,248)'; |
|
|
|
|
|
// fontSize = '32px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 5: |
|
|
|
|
|
// color = 'rgb(65,154,255)'; |
|
|
|
|
|
// fontSize = '30px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 6: |
|
|
|
|
|
// color = 'rgb(0,228,255)'; |
|
|
|
|
|
// fontSize = '28px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// default: |
|
|
|
|
|
// color = 'rgb(200,200,200)'; |
|
|
|
|
|
// fontSize = '24px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// if (node.groupId==this.currentGroup || node.docLeve=="0"){ |
|
|
|
|
|
// // 添加节点 |
|
|
|
|
|
// nodes.push({ |
|
|
|
|
|
// id: node.id, |
|
|
|
|
|
// text: node.name, |
|
|
|
|
|
// data: { |
|
|
|
|
|
// docId: node.docId, |
|
|
|
|
|
// group: node.groupId |
|
|
|
|
|
// }, |
|
|
|
|
|
// level: levelNum, |
|
|
|
|
|
// // x: x, |
|
|
|
|
|
// // y: y, |
|
|
|
|
|
// // fixed: true, |
|
|
|
|
|
// width: 150, |
|
|
|
|
|
// height: 150, |
|
|
|
|
|
// color: color, |
|
|
|
|
|
// font: `normal ${fontSize} Arial`, |
|
|
|
|
|
// fontColor: fontColor, |
|
|
|
|
|
// expandHolderPosition: 'right', |
|
|
|
|
|
// expanded: true, |
|
|
|
|
|
// styleClass:this.getNodeClass(node.name), |
|
|
|
|
|
// }); |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// currentLeftX -= 200; |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// // 放置右侧孤立节点(从左往右排列) |
|
|
|
|
|
// let currentRightX = positionInfo.rightAvailableX; |
|
|
|
|
|
// rightNodes.forEach(node => { |
|
|
|
|
|
// // 根据层级设置节点样式 |
|
|
|
|
|
// let color, fontSize, fontColor; |
|
|
|
|
|
// switch (levelNum) { |
|
|
|
|
|
// case 0: |
|
|
|
|
|
// color = 'rgb(227,203,0)'; |
|
|
|
|
|
// fontSize = '70px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 1: |
|
|
|
|
|
// color = 'rgb(47,47,230)'; |
|
|
|
|
|
// fontSize = '68px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 2: |
|
|
|
|
|
// color = 'rgb(255,138,0)'; |
|
|
|
|
|
// fontSize = '50px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 3: |
|
|
|
|
|
// color = 'rgb(30,255,0)'; |
|
|
|
|
|
// fontSize = '40px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 4: |
|
|
|
|
|
// color = 'rgb(248,143,248)'; |
|
|
|
|
|
// fontSize = '32px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 5: |
|
|
|
|
|
// color = 'rgb(65,154,255)'; |
|
|
|
|
|
// fontSize = '30px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// case 6: |
|
|
|
|
|
// color = 'rgb(0,228,255)'; |
|
|
|
|
|
// fontSize = '28px'; |
|
|
|
|
|
// fontColor = 'rgb(0,0,0)'; |
|
|
|
|
|
// break; |
|
|
|
|
|
// default: |
|
|
|
|
|
// color = 'rgb(200,200,200)'; |
|
|
|
|
|
// fontSize = '24px'; |
|
|
|
|
|
// fontColor = 'rgb(255,255,255)'; |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// if (node.groupId==this.currentGroup || node.docLeve=="0"){ |
|
|
|
|
|
// // 添加节点 |
|
|
|
|
|
// nodes.push({ |
|
|
|
|
|
// id: node.id, |
|
|
|
|
|
// text: node.name, |
|
|
|
|
|
// data: { |
|
|
|
|
|
// docId: node.docId, |
|
|
|
|
|
// group: node.groupId |
|
|
|
|
|
// }, |
|
|
|
|
|
// level: levelNum, |
|
|
|
|
|
// // x: x, |
|
|
|
|
|
// // y: y, |
|
|
|
|
|
// // fixed: true, |
|
|
|
|
|
// width: 150, |
|
|
|
|
|
// height: 150, |
|
|
|
|
|
// color: color, |
|
|
|
|
|
// font: `normal ${fontSize} Arial`, |
|
|
|
|
|
// fontColor: fontColor, |
|
|
|
|
|
// expandHolderPosition: 'right', |
|
|
|
|
|
// expanded: true, |
|
|
|
|
|
// styleClass:this.getNodeClass(node.name), |
|
|
|
|
|
// }); |
|
|
|
|
|
// } |
|
|
|
|
|
// |
|
|
|
|
|
// currentRightX += 200; |
|
|
|
|
|
// }); |
|
|
|
|
|
// } |
|
|
|
|
|
// }); |
|
|
|
|
|
// }); |
|
|
|
|
|
|
|
|
|
|
|
// 处理连线 |
|
|
// 处理连线 |
|
|
lineList.forEach(line => { |
|
|
lineList.forEach(line => { |
|
|
@ -1172,15 +906,18 @@ export default { |
|
|
style=this.getLinesClass(line.DbId) |
|
|
style=this.getLinesClass(line.DbId) |
|
|
num=10 |
|
|
num=10 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 查询父节点是否是展示状态 |
|
|
|
|
|
|
|
|
links.push({ |
|
|
links.push({ |
|
|
id:line.DbId, |
|
|
id:line.DbId, |
|
|
from: line.source, |
|
|
from: line.source, |
|
|
to: line.target, |
|
|
to: line.target, |
|
|
text: line.relate || '相关', |
|
|
text: line.relate || '相关', |
|
|
color: |
|
|
color: |
|
|
line.num <= 5 ? '#fff' : // 白色 |
|
|
line.num <= 5 ? 'rgb(255, 255, 255)' : // 白色 |
|
|
line.num <= 10 ? '#0f0' : // 绿色 |
|
|
line.num <= 10 ? 'rgb(0, 255, 0)' : // 绿色 |
|
|
line.num <= 15 ? '#ff0' : // 黄色 |
|
|
line.num <= 15 ? 'rgb(255, 255, 0)' : // 黄色 |
|
|
'rgb(178,246,255)', // 红色(包含line.num <= 20和超过20的情况) |
|
|
'rgb(178,246,255)', // 红色(包含line.num <= 20和超过20的情况) |
|
|
lineWidth:num, |
|
|
lineWidth:num, |
|
|
lineShape: 1, |
|
|
lineShape: 1, |
|
|
@ -1213,23 +950,18 @@ export default { |
|
|
}) |
|
|
}) |
|
|
}, |
|
|
}, |
|
|
onNodeClick(nodeObject, $event) { |
|
|
onNodeClick(nodeObject, $event) { |
|
|
console.log(nodeObject) |
|
|
console.log(nodeObject.id) |
|
|
const data = { |
|
|
const graphInstance = this.$refs.graphRef.getInstance(); |
|
|
'id': nodeObject.data.docId, |
|
|
let node = graphInstance.getNodeById(nodeObject.id) |
|
|
'docTitle': nodeObject.text, |
|
|
let relinks = graphInstance.getLinesByNode(node); |
|
|
|
|
|
|
|
|
|
|
|
for (let i=0;i<relinks.length;i++){ |
|
|
|
|
|
if (graphInstance.getLinesByNode(node)[i].lineWidth == 10){ |
|
|
|
|
|
graphInstance.getLinesByNode(node)[i].lineWidth = 1 |
|
|
|
|
|
}else{ |
|
|
|
|
|
graphInstance.getLinesByNode(node)[i].lineWidth = 10 |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
getDocInfo(data).then((res) => { |
|
|
|
|
|
localStorage.setItem("docUrl", res.data.docUrl) |
|
|
|
|
|
this.$router.push({ |
|
|
|
|
|
name: 'docInfo', |
|
|
|
|
|
query: { |
|
|
|
|
|
title: res.data.docTitle, |
|
|
|
|
|
level: res.data.docLevel, |
|
|
|
|
|
keyword: res.data.docTitle, |
|
|
|
|
|
docId: res.data.id |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
created() { |
|
|
created() { |
|
|
@ -1849,7 +1581,7 @@ tr { |
|
|
stroke: white !important; |
|
|
stroke: white !important; |
|
|
stroke-width: 3 !important; |
|
|
stroke-width: 3 !important; |
|
|
stroke-opacity: 1 !important; |
|
|
stroke-opacity: 1 !important; |
|
|
|
|
|
font-size: 20px !important; |
|
|
/* 多层光晕:内层青色,外层白色 */ |
|
|
/* 多层光晕:内层青色,外层白色 */ |
|
|
filter: |
|
|
filter: |
|
|
drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */ |
|
|
drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */ |
|
|
@ -1861,7 +1593,7 @@ tr { |
|
|
paint-order: stroke fill !important; |
|
|
paint-order: stroke fill !important; |
|
|
} |
|
|
} |
|
|
.nodeclassnormal{ |
|
|
.nodeclassnormal{ |
|
|
font-size: 30px !important; |
|
|
font-size: 20px !important; |
|
|
} |
|
|
} |
|
|
.el-table .warning-row { |
|
|
.el-table .warning-row { |
|
|
background: oldlace; |
|
|
background: oldlace; |
|
|
@ -1909,7 +1641,4 @@ tr { |
|
|
.flow-tree:hover { |
|
|
.flow-tree:hover { |
|
|
background-color: rgba(255, 255, 255, 0.1); |
|
|
background-color: rgba(255, 255, 255, 0.1); |
|
|
} |
|
|
} |
|
|
.c-node-text{ |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
</style> |
|
|
</style> |