You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1696 lines
49 KiB

<template>
<div class="about">
<HeaderInfo style="height: 5.65vw;float: left;"></HeaderInfo>
<leftInfo @show="isZhe" style="width: 5vw;position: absolute;top: 5.35vw;position: absolute;z-index:100;"
:leftNum="0" :zhedie="zhedie" v-if="zhedie == 0"></leftInfo>
<div v-if="zhedie == 0" @click="this.zhedie = 1"
style="position: absolute;height: 3vw;width: 3vw;font-size: 2vw;border-radius: 0 50% 50% 0;z-index: 1000;bottom:45%;left:5vw;cursor: pointer">
<img src="../assets/img2/close3.png" style="width: 60%;object-fit: contain;">
</div>
<div v-if="zhedie == 1" @click="this.zhedie = 0"
style="position: absolute;height: 3vw;width: 3vw;font-size: 2vw;border-radius: 0 50% 50% 0;z-index: 1000;bottom:49%;left:0vw;cursor: pointer">
<img src="../assets/img2/open3.png" style="width: 60%;object-fit: contain;margin-top: 1.8vw;">
</div>
<div class="rightBox">
<div class="graphGround">
<div class="graphHeader" v-if="zhedie == 0">
<div class="gjz">
<div class="gjzText">关键词:</div>
<input class="gjzInput" placeholder="请输入关键词" v-model="keywords"/>
<div @click="getInfo2"
style="width: 4vw;height: 1.5vw;background-color: #0AB7FD;float: right;font-size: 1vw;line-height:1.5vw; height: 1.5vw;text-align: center;border-radius:2vw;margin-top: 0.25vw;cursor: pointer;">
查询
</div>
</div>
<div class="jiedianInfo">
<img src="../assets/img2/dingwei.png"
style="width: 2vw;object-fit: contain;position: absolute;z-index: 2000;top: 1vw;right: 2vw;cursor: pointer;"
@click="opending">
<div class="selectListInfo" v-if="isDing"
style="z-index: 2000;
max-height:35vw;
border-radius: 1vw;
background-color: rgba(76,100,233,0.71) ;position:absolute;right: 4vw;top: 2vw;font-size: 0.9vw;overflow-y: scroll;margin-left: 1vw;margin-right: 1vw;">
<div
style="font-size: 1.1vw;color: #ffffff;width:130%;background-color: rgba(32,51,162,0.71) ;
text-align: center;height: 2.2vw;line-height: 2vw;margin-left: -13%;padding-top: 2%;letter-spacing: 3px;">
图谱快速定位
</div>
<el-tree :data="this.data1" :props="defaultProps1" class="flow-tree" accordion @node-click="goCenter"
style="padding: 1.2vw 0;" node-key="id" ref="tree" highlight-current>
<template #default="{ node }">
<span class="custom-tree-node" style="display: flex;flex-direction: row;" v-if="node.level == 1">
<div class="lineInfo" 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="label" style="font-size: 1.1vw;cursor: pointer;line-height: 2vw;">{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 2" style="border-top: none !important;">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 1vw;cursor: pointer;margin-left: 0.5vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 3">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.9vw;cursor: pointer;margin-left: 1vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 4">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.8vw;cursor: pointer;margin-left: 1.5vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 5">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.7vw;cursor: pointer;margin-left: 2vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 6">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label" style="font-size: 0.6vw;cursor: pointer;margin-left: 2.5vw;line-height: 2vw;">{{
node.label }}</div>
</span>
</template>
</el-tree>
</div>
</div>
</div>
<div class="graphHeader1" v-if="zhedie == 1">
<div class="gjz">
<div class="gjzText">关键词:</div>
<input class="gjzInput" placeholder="请输入关键词" v-model="keywords" @blur="getInfo2"/>
<div @click="getInfo2"
style="width: 4vw;height: 1.5vw;background-color: #0AB7FD;float: right;font-size: 1vw;line-height:1.5vw; height: 1.5vw;text-align: center;border-radius:2vw;margin-top: 0.25vw;cursor: pointer;">
查询
</div>
</div>
<div class="jiedianInfo">
<img src="../assets/img2/dingwei.png"
style="width: 2vw;object-fit: contain;position: absolute;z-index: 2000;top: 1vw;right: 2vw;cursor: pointer;"
@click="opending">
<div class="selectListInfo" v-if="isDing"
style="z-index: 2000;
max-height:35vw;
border-radius: 1vw;
background-color: rgba(76,100,233,0.71) ;position:absolute;right: 4vw;top: 2vw;font-size: 0.9vw;overflow-y: scroll;margin-left: 1vw;margin-right: 1vw;">
<div
style="font-size: 1.1vw;color: #ffffff;width:130%;background-color: rgba(32,51,162,0.71) ;
text-align: center;height: 2.2vw;line-height: 2vw;margin-left: -13%;padding-top: 2%;letter-spacing: 3px;">
图谱快速定位
</div>
<el-tree :data="this.data1" :props="defaultProps" class="flow-tree" accordion @node-click="goCenter"
style="padding: 1.2vw 0;" node-key="id" ref="tree" highlight-current>
<template #default="{ node }">
<span class="custom-tree-node" style="display: flex;flex-direction: row;" v-if="node.level == 1">
<div class="lineInfo" 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="label" style="font-size: 1.1vw;cursor: pointer;line-height: 2vw;">{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 2" style="border-top: none !important;">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 1vw;cursor: pointer;margin-left: 0.5vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 3">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.9vw;cursor: pointer;margin-left: 1vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 4">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.8vw;cursor: pointer;margin-left: 1.5vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 5">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; background: rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label"
style="font-size: 0.7vw;cursor: pointer;margin-left: 2vw;color: rgb(236,236,236);line-height: 2vw;">
{{ node.label }}</div>
</span>
<span class="custom-tree-node" v-if="node.level == 6">
<div class="lineInfo"
style="width: 0.15vw;height: 2vw; rgba(255,255,255,0.26);display: inline-block;margin-right: 0.8vw;margin-left: 0.2vw;">
</div>
<div class="label" style="font-size: 0.6vw;cursor: pointer;margin-left: 2.5vw;line-height: 2vw;">{{
node.label
}}</div>
</span>
</template>
</el-tree>
</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: 4vw;font-size: 0.9vw;overflow-y: scroll;margin-left: 1vw;margin-right: 1vw;">
<div class="flow-tree" :class="{ 'flow-tree-active': i === currentGroup }" v-for="i in [0,1,2]" style="padding: 0vw 2vw;" @click="changeGroup(i)">
<span class="custom-tree-node" style="display: flex;flex-direction: row;">
<div class="lineInfo" :class="{ 'lineInfo-active': i === currentGroup }" 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;">
<span v-if="i==0">
方向-作战-装备-环境
</span>
<span v-if="i==1">
业务系统-模型库-大类-小类
</span>
<span v-if="i==2">
模型-指标
</span>
</div>
</span>
</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="full ? 'full-screen' : 'show-box'">
<!-- 节点右键菜单 -->
<div style="width: 100%;height: 100%;">
<div ref="myPage" class="gContainer" @click="isShowNodeMenuPanel = false">
<RelationGraph ref="graphRef" :options="graphOptions" :nodes="graphData.nodes" :links="graphData.links"
:on-node-click="onNodeClick"
:on-line-click="onLineClick"
>
<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>
</div>
<div style="background-color: transparent;height: 20%;width: 40%;position: absolute;top: 1vw;right: 0;"></div>
<el-drawer v-model="drawer" title="相关文档" direction="rtl" size="30%" :modal="false" :wrapperClosable="false"
:append-to-body="true" @opened="onDrawerOpened" @closed="onDrawerClosed"
style="position: fixed;right: 0;background-color: rgba(76, 100, 233, 0.71);top: 5.35vw;height: 91%;color: #fff;font-size: 2vw;">
<el-table :data="tableData" style="border: none;width: 100%;margin-left: 3.25%;height:530px; background: transparent;overflow: auto"
v-if="drawer" :row-class-name="tableRowClassName">
<el-table-column label="文档名称" width="400">
<template #default="scope">
<div @click="goArticle(scope.row)" style="cursor: pointer; padding: 8px;">
{{ scope.row.name }}
</div>
</template>
</el-table-column>
</el-table>
</el-drawer>
</div>
</div>
</template>
<script>
import RelationGraph, {RGJsonData, RGOptions} from 'relation-graph-vue3';
import LayoutFactory from '@/assets/js/graphvis.layout.min.js'
import {config} from '@/assets/defaultConfig.js'
import {demoData} from '@/assets/demo2.js'
import HeaderInfo from "@/components/UseAll/headerInfo.vue";
import leftInfo from "@/components/UseAll/leftInfo.vue";
import {getAllTitle, getDocInfo, getTitleByGroup} from "@/api/api/doc";
import {getDomainGraphTest, getheightLight} from "@/api/api/graph";
import {Picture} from "@element-plus/icons-vue";
import {selectAticleByRelation} from '@/api/api/article'
import {height} from "fontfaceobserver";
export default {
components: {
leftInfo,
HeaderInfo,
Picture,
RelationGraph
},
data() {
return {
isShowCodePanel: false,
isShowNodeMenuPanel: false,
nodeMenuPanelPosition: { x: 0, y: 0 },
currentGroup:0,
direction: "rtl",
// visGraph实例对象
visGraph: null,
visLayout: null,//布局对象
layoutLoopName: null,//布局循环对象
// visGraph可视化交互配置
config,
//示例数据
demoData,
circleBgImage: require('@/assets/images/circle.png'),//节点背景图片
// visGraph创建节点和连线数据集
graphData: {
nodes: [],
links: []
},
nodeList: [],
linkList: [],
graphLegend: [
//{type:'图例一',color:'rgb(233,120,120)',show:true}
],//图例数组,根据数据的节点类型生成
properShow: false,//属性展示配置
tipLayer: { //提示层配置
show: false, //是否显示提示层
header: '提示信息', // 提示表头
data: [] //提示内部的数据
},
graphOptions: {
allowSwitchLineShape: true,
allowSwitchJunctionPoint: true,
defaultLineColor: '#2E74B5',
defaultNodeColor: '#2E74B5',
defaultNodeBorderWidth: 0,
defaultNodeBorderColor: '#2E74B5',
defaultNodeFontColor: '#ffffff',
defaultNodeShape: 0,
defaultNodeWidth: 40,
defaultNodeHeight: 40,
toolBarDirection: 'v',
toolBarPositionH: 'right',
defaultLineShape: 1,
defaultJunctionPoint: 'border',
// lineUseTextPath: true,
defaultLineTextOffset_x: 2,
defaultLineTextOffset_y: -3,
// 布局核心:使用 center 布局实现环形
layout: {
layoutName: 'center', // 关键:使用 center 布局
levelDistance: '1000,1000,1000,1000,3000,3000,3000,3000', // 每一层的半径(可动态修改)
startAngle: -Math.PI / 2, // 起始角度(-90°,顶部开始)
}
},
currentNode: {}, // 选中的节点对象
attrbutes: [],//选中节点或连线的属性列表
currentLink: {},// 选中的连线对象
//节点详细信息弹框
showNodeInfoDialog: false,
//关系连线信息弹层
showLinkInfoDialog: false,
//属性节点详细弹层控制开关
showProperNodeInfo: false,
properNode: {},//属性节点
currentLayoutType: 'frDirect',//当前布局类型,用于区分是否可以拖动
loading: true,
data: {
nodes: [],
links: []
},
data1: [],
defaultProps: {
children: 'level2',
label: 'docTitle',
level: 'titleLevel',
docLevel: 'docLevel',
},
names: ['0级', '一级', '二级', '三级', '四级', '五级', '六级'],
labels: ['0', '1', '2', '3', '4', '5', '6'],
linkTypes: ['info', 'type', 'locate', 'export'],
zhedie: 0,
isLoginShow: false,
jiedianType: 0,
totalNum: 0,
selectInfo: "",
viewerData: {
total: 25,
limit: 10,
skip: 0,
links: {
previous: undefined,
next: function () {
},
},
},
gg: [],
graphNodes: [],
graphEdges: [],
currentNodeId: '', //当期选中节点id
vertexData: '', //节点详细数据
full: false, //是否全屏,
simpleData: {},
keywords: '',
userNameInfo: '',
docList: [],
drawer: false,
tableData: [],
isDing: false,
// graphData:[],
nodes: [],
links: [],
heightLight:{},
width: 2000,
height: 1000,
svg: null,
rootId: 0,
defaultProps1: {
children: 'children',
label: 'docTitle',
level: 'titleLevel',
docLevel: 'docLevel',
},
heightlightTable:[],
currentShowLeve:2,
lastNodeL:"",
}
},
methods: {
showNodeMenus(nodeObject, $event) {
this.currentNode = nodeObject;
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;
},
showOrHide(){
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,
}
if (data.docTitle=="联合作战气象海洋影响评估与决策支撑体系"){
return
}
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;
},
changeGroup(groupId){
this.currentGroup = groupId
this.getAll()
this.getInfo()
},
handleNodeClick(node) {
console.log(node);
},
tableRowClassName({row, rowIndex}) {
for(var i=0;i<this.heightlightTable.length;i++){
if(this.heightlightTable[i]==row.id){
return 'success-row';
}
}
return '';
},
loadPng() {
this.visGraph.saveImage();
},
// 获取所有的知识节点信息
async drawGraphData() {
this.graphData = this.demoData;
if (this.visGraph === null) {
this.createGraph();
this.visGraph.drawData(this.graphData);
this.visGraph.incremaNodesCodinate(this.graphData.nodes);
this.reLayout();
} else {
this.createGraph();
this.visGraph.drawData(this.graphData);
this.visGraph.incremaNodesCodinate(this.graphData.nodes);
this.reLayout();
}
this.loading = false;
},
// 创建全局绘图客户端对象
createGraph() {
this.visGraph = new VisGraph(document.getElementById('graph-panel'), this.config)
},
async goCenter(node) {
try {
const docId = node.id.toString();
const graph = this.$refs.graphRef?.getInstance();
if (!graph) return;
graph.getNodes().forEach(n => {
n.selected = false;
});
const targetNode = graph.getNodes().find(n =>
n.data?.docId === docId || n.id === docId
);
await graph.focusNodeById(targetNode.id);
this.$nextTick(() => {
this.$refs.tree?.setCurrentKey(node.id);
});
} catch (error) {
console.error('定位失败:', error);
}
},
// 执行布局算法
reLayout(alpha) {
var that = this;
if (alpha == null) {
that.visLayout = null;
that.visLayout = new LayoutFactory(this.visGraph.getGraphData()).createLayout('fastFR');
that.visLayout.resetConfig({
label: {
show: true
},
friction: 0.8,
linkDistance: 400,
linkStrength: 0.2,
charge: -1000,
gravity: 0.01,
noverlap: true,
size: [that.visGraph.stage.width, that.visGraph.stage.height]
});
} else {
that.visLayout.alpha += (alpha > 1 ? 0.2 : alpha); //继续运动
}
runLayout();//开始继续动画执行
//通过动画帧控制控制布局算法的执行,有动画效果
function runLayout() {
cancelAnimationFrame(that.layoutLoopName);//停止动画控制
that.visLayout.runLayout(); //运行布局算法
that.visGraph.refresh();
if (that.visLayout.alpha > 0.05) {
that.layoutLoopName = requestAnimationFrame(runLayout);
} else {
if (that.visGraph.currentNode && that.visGraph.currentNode.isDragging) {
that.visLayout.alpha = 0.1; //继续运动
that.layoutLoopName = requestAnimationFrame(runLayout);
} else {
that.visLayout.alpha = 0; //停止运动
cancelAnimationFrame(that.layoutLoopName);
}
}
}
},
getAll() {
getTitleByGroup().then((res) => {
let data = res
data.g01["level"] = 1
data.g01["docTitle"] = data.g01["name"]
data.g02["level"] = 1
data.g02["docTitle"] = data.g02["name"]
data.g03["level"] = 1
data.g03["docTitle"] = data.g03["name"]
data.g04["level"] = 1
data.g04["docTitle"] = data.g04["name"]
data.g11["level"] = 1
data.g11["docTitle"] = data.g11["name"]
data.g12["level"] = 1
data.g12["docTitle"] = data.g12["name"]
data.g13["level"] = 1
data.g13["docTitle"] = data.g13["name"]
data.g14["level"] = 1
data.g14["docTitle"] = data.g14["name"]
data.g21["level"] = 1
data.g21["docTitle"] = data.g21["name"]
data.g22["level"] = 1
data.g22["docTitle"] = data.g22["name"]
this.data1 = []
if (this.currentGroup==0){
this.data1.push(data.g01)
this.data1.push(data.g02)
this.data1.push(data.g03)
this.data1.push(data.g04)
}
if (this.currentGroup==1){
this.data1.push(data.g11)
this.data1.push(data.g12)
this.data1.push(data.g13)
this.data1.push(data.g14)
}
if (this.currentGroup==2){
this.data1.push(data.g21)
this.data1.push(data.g22)
}
})
},
opending() {
if (this.isDing == true) {
this.isDing = !this.isDing;
} else {
this.isDing = !this.isDing;
}
},
isZhe(zhedie) {
this.zhedie = zhedie;
},
getInfoInit() {
if (localStorage.getItem("userName") != null && localStorage.getItem("userName") != "") {
this.userNameInfo = localStorage.getItem("userName");
} else {
this.$router.push('/');
}
},
logout() {
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() - 1);
document.cookie = 'satoken=; expires=${expirationDate.toUTCString()}';
localStorage.clear();
this.$router.push('/');
},
goChat() {
this.$router.push('/intelligentQA');
},
goIndex() {
this.$router.push('/');
},
goZc() {
this.$router.push('/battlefield');
},
golist() {
this.$router.push('/list');
},
goBack() {
this.$router.go(-1)
},
getInfo() {
if (this.keywords) {
let params = {nodename: this.keywords};
getDomainGraphTest(params).then((res) => {
this.zhengl(res.data);
})
} else {
getDomainGraphTest({}).then((res) => {
this.zhengl(res.data);
})
}
},
getInfo2() {
if(this.keywords!=""){
getheightLight(this.keywords).then((res)=>{
this.heightLight = {
"nodes": res.nodes.hits,
"links":res.links.hits,
"nodes1":res.nodes1
}
console.log(this.heightLight)
getDomainGraphTest({}).then((r) => {
this.zhengl(r.data);
})
})
}else{
getDomainGraphTest({}).then((res) => {
this.zhengl(res.data);
})
}
},
getNodeClass(name) {
// console.log(name)
// 确保 this.heightLight.nodes 存在且是一个数组
const nodes = this.heightLight.nodes;
const nodes1 = this.heightLight.nodes1;
if (nodes==undefined){
return "nodeclassnormal";
}
if (nodes.length === 0&&nodes1.length === 0) {
return "nodeclassnormal";
}
// 将传入的 id 转为字符串
const targetId = String(name).trim();
// 遍历 nodes 数组,检查是否有元素的 id(转字符串)与 targetId 相等
let found = nodes.some(node => {
const nodeId = node.sourceAsMap.abstracts
return nodeId === targetId;
});
let found2 = nodes1.some(node => {
const nodeId = node.docTitle
return nodeId === targetId;
});
found = found || found2
// 找到了返回 'nodeclass',否则返回 ''
return found ? 'nodeclass' : 'nodeclassnormal';
},
getLinesClass(mergedDbIds) {
const lines = this.heightLight.links;
if (lines == undefined){
return ""
}
// 将传入的 id 转为字符串
// const targetId = Number(String(id).trim());
// console.log(targetId)
const list=Array.from(mergedDbIds)
const numberArray = list.map(item => parseInt(item, 10));
const found = lines.some(line => {
const data= line.sourceAsMap.data
const array=JSON.parse(data)
console.log(array)
if(array.length>0){
return numberArray.includes(array[0]);
}else {
console.log("没有")
return false
}
});
// 找到了返回 'nodeclass',否则返回 ''
return found ? 'lineclass' : '';
},
async onLineClick(lineObject, linkObject, event) {
console.log(linkObject)
console.log(lineObject)
const from = linkObject.fromNode.data.docId
const to = linkObject.toNode.data.docId
const data = {
sourceId: from,
targetId: to,
}
this.heightlightTable=[]
console.log(lineObject.id)
let mergedDbIds=lineObject.data
const numberArray = (Array.from(mergedDbIds)).map(item => parseInt(item, 10));
const lines = this.heightLight.links;
console.log(this.heightLight.links)
if(this.heightLight.links!=undefined){
lines.some(line => {
const data= line.sourceAsMap.data
const array=JSON.parse(data)
if(array.length>0){
if(numberArray.includes(array[0])){
this.heightlightTable.push(Number(line.sourceAsMap.DBid))
}
}
});
}
console.log(this.heightlightTable)
// const id=linkObject.relations[0].id
this.tableData = await selectAticleByRelation(data);
// this.heightLight.links
// line.sourceAsMap.data
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) {
console.log(data)
const nodes = []
const links = []
const nodeList = data.nodes;
const lineList = data.links;
// 找出有连接的节点
const connectedNodeIds = new Set();
lineList.forEach(line => {
connectedNodeIds.add(line.source);
connectedNodeIds.add(line.target);
});
// 在遍历前先按 docLeve 分组统计数量
const nodesByLevel = {};
for (let i = 0; i < nodeList.length; i++) {
const node = nodeList[i];
if (node.groupId == this.currentGroup || node.docLeve == "0") {
// 仅孤立节点判断,超出层级不展示
if (Number(node.docLeve) > this.currentShowLeve) {
if (!connectedNodeIds.has(node.id)) {
continue;
}
}
const level = Number(node.docLeve);
if (!nodesByLevel[level]) {
nodesByLevel[level] = [];
}
nodesByLevel[level].push(node);
}
}
// 配置参数
const baseRadius = 1200; // 每层之间的半径差
const centerX = 0, centerY = 0;
// 遍历每一层进行布局
Object.keys(nodesByLevel).forEach(levelStr => {
const level = Number(levelStr);
const levelNodes = nodesByLevel[level];
const total = levelNodes.length;
const radius = level === 0 ? 0 : level * baseRadius; // level 0 放中心
levelNodes.forEach((node, index) => {
let x, y;
if (level === 0) {
// 中心节点放在原点
x = 0;
y = 0;
} else {
// 计算极角
const angle = (2 * Math.PI / total) * index; // 均匀分布
x = centerX + radius * Math.cos(angle);
y = centerY + radius * Math.sin(angle);
}
nodes.push({
id: node.id,
text: node.name,
data: {
docId: node.docId,
group: node.groupId
},
level: node.docLeve,
x: x,
y: y,
fixed: true, // 锁定位置
width: 250,
height: 250,
color: this.getNodeColor(node.docLeve),
expandHolderPosition: 'right',
expanded: this.getExpanded(node.docLeve),
styleClass: this.getNodeClass(node.name),
});
});
});
// 处理连线
lineList.forEach(line => {
let style=""
let num=1
if(this.getLinesClass(line.mergedDbIds)!=""){
style=this.getLinesClass(line.DbId)
num=10
}
// 查询父节点是否是展示状态
links.push({
id:line.DbId,
from: line.source,
to: line.target,
text: line.relate || '相关',
color:
line.num <= 5 ? 'rgb(255, 255, 255)' : // 白色
line.num <= 10 ? 'rgb(0, 255, 0)' : // 绿色
line.num <= 15 ? 'rgb(255, 255, 0)' : // 黄色
'rgb(178,246,255)', // 红色(包含line.num <= 20和超过20的情况)
lineWidth:num,
lineShape: 1,
styleClass:style,
data:line.mergedDbIds
})
});
this.graphData = {
'rootId': this.rootId,
nodes,
links
};
// 确保图表更新
this.$nextTick(() => {
if (this.$refs.graphRef) {
this.$refs.graphRef.setOptions(this.graphOptions);
this.$refs.graphRef.setJsonData(this.graphData);
this.$refs.graphRef.refresh();
}
});
},
goArticle(row) {
this.$router.push({
path: '/articleInfo',
query: {
id: row.id
}
})
},
onNodeClick(nodeObject, $event) {
console.log(nodeObject.id)
const graphInstance = this.$refs.graphRef.getInstance();
let node = graphInstance.getNodeById(nodeObject.id)
let relinks = graphInstance.getLinesByNode(node);
// let links = graphInstance.getLinks();
//
// for (let i=0;i<links.length;i++){
// graphInstance.getLinks()[i].lineWidth = 1
// }
if (this.lastNodeL.id==node.id){
console.log("ss11111111")
for (let i=0;i<relinks.length;i++){
console.log(graphInstance.getLinesByNode(node)[i].lineWidth)
if (graphInstance.getLinesByNode(node)[i].lineWidth == 10){
graphInstance.getLinesByNode(node)[i].lineWidth = 1
}else {
graphInstance.getLinesByNode(node)[i].lineWidth = 10
}
}
return
}
if (this.lastNodeL!=""){
let a = graphInstance.getLinesByNode(this.lastNodeL);
for (let i=0;i<a.length;i++){
graphInstance.getLinesByNode(this.lastNodeL)[i].lineWidth = 1
}
}
for (let i=0;i<relinks.length;i++){
graphInstance.getLinesByNode(node)[i].lineWidth = 10
}
this.lastNodeL = node
}
},
created() {
var that = this;
//节点的点击事件
this.config.node.onClick = function (event, node) {
var data = {
'id': node.properties.docId,
'docTitle': node.properties.name,
}
getDocInfo(data).then((res) => {
localStorage.setItem("docUrl", res.data.docUrl)
that.$router.push({
name: 'docInfo',
query: {
title: res.data.docTitle,
level: res.data.docLevel,
keyword: res.data.docTitle,
docId: res.data.id
}
})
});
node.color = 'rgb(' + node.fillColor + ')';
that.currentNode = node;
that.tipLayer.header = node.label || '';
that.tipLayer.data = node.properties.attributes || []; //节点属性列表
that.attrbutes = node.properties.attributes || []; //节点属性列表
};
},
mounted() {
//初始化加载绘图
this.getInfo();
this.getAll();
}
}
</script>
<style>
/*****页面主要布局样式定义******/
.graph-nav {
height: 80px;
background-color: #fff;
line-height: 26px;
font-size: 13px;
padding: 10px 20px;
}
.graph-area {
position: relative;
height: calc(100% - 105px);
padding: 0;
background-color: #fafafa;
border: 1px solid #ddd;
}
/******工具栏*******/
.toolbar {
position: absolute;
right: 0px;
top: 0px;
background: #efefef;
}
.toolbar .toolbar-item {
width: 40px;
height: 40px;
line-height: 40px;
font-size: 18px;
text-align: center;
color: #888;
border-bottom: 1px solid #ddd;
cursor: pointer;
}
.toolbar .toolbar-item:hover {
color: deepskyblue;
}
/*******图例区域样式定义*****/
.legend-wrap {
position: absolute;
left: 10px;
bottom: 10px;
}
.legend-wrap > .legend-item {
height: 24px;
line-height: 24px;
font-size: 12px;
}
.legend-item > .item-dot {
float: left;
display: inline-block;
height: 20px;
width: 20px;
border-radius: 10px;
background-color: rgb(210, 210, 210);
cursor: pointer;
}
.legend-item > .item-label {
display: inline-block;
float: left;
margin-left: 5px;
max-width: 120px;
}
/*****节点弹出鼠标提示层样式*****/
.tip-wrap {
position: absolute;
width: 350px;
height: auto;
min-height: 150px;
background: #fff;
box-shadow: 0px 0px 10px #999;
font-size: 14px;
}
.tip-wrap > .tip-header {
height: 30px;
line-height: 30px;
padding: 5px 10px;
border-bottom: 1px solid #ddd;
}
.tip-wrap > .tip-body {
padding: 0 10px 10px;
}
/*****右键菜单样式******/
.right-menu-layer {
position: absolute;
width: 100px;
z-index: 5;
display: none;
border-radius: 3px;
overflow: hidden;
background: #fafafa;
border: 1px solid #e1e2e2;
box-shadow: 0 0 5px #ddd;
padding: 5px 3px;
}
.right-menu-layer button {
display: block;
height: 24px;
line-height: 24px;
background: transparent;
border: none;
color: #444;
text-align: center;
cursor: pointer;
}
.right-menu-layer button > i {
margin-right: 5px;
}
.right-menu-layer button:hover {
color: slateblue;
}
.right-menu-layer button:focus {
outline: 0;
}
.box-card {
box-shadow: 0 0 3px #d4c8c8;
padding: 10px;
margin-bottom: 10px;
}
.gContainer {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
width: 100%;
height: 45vw;
}
.about {
width: 100%;
height: 100%;
/*background-image: url("../assets/img1/graphback.jpg");*/
/* 背景图垂直、水平均居中 */
background-position: center center;
/* 背景图不平铺 */
background-repeat: no-repeat;
/* 当内容高度大于图片高度时,背景图像的位置相对于viewport固定 */
background-attachment: fixed;
/* 让背景图基于容器大小伸缩 */
background-size: cover;
/* 设置背景颜色,背景图加载过程中会显示背景色 */
}
.rightBox {
width: 100%;
height: 95%;
top: 5.35vw;
position: absolute;
background-color: #2d3562;
}
.graphGround {
width: 100%;
height: 100%;
/*background-color: #0AB7FD;*/
border-radius: 2vw;
}
.graphHeader {
/*float: left;*/
width: 95%;
height: 5%;
background-color: transparent;
margin-left: 6vw;
margin-top: 0.5vw;
/*border-radius: 2vw 2vw 0 0;*/
}
.graphHeader1 {
/*float: left;*/
width: 90%;
height: 5%;
background-color: transparent;
margin-left: 1.5vw;
margin-top: 0.5vw;
/*border-radius: 2vw 2vw 0 0;*/
}
.graphContent {
width: 100%;
height: 94%;
background: transparent;
/* border: 1px solid #04538e; */
position: relative;
margin-top: 0%;
}
.gjz {
width: 25%;
height: 2vw;
float: left;
margin-right: 20%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.gjzText {
float: left;
font-size: 1vw;
height: 100%;
line-height: 2vw;
color: #ffffff;
font-family: '微软雅黑';
letter-spacing: 0.1vw;
}
.gjzInput {
width: 60%;
height: 1.6vw;
border-radius: 2vw;
border: #ffffff 1px solid;
background: transparent;
text-indent: 4px;
color: #ffffff;
font-size: 0.9vw;
margin: 0.2vw 0;
}
.jiedianInfo {
width: 100%;
height: 100%;
margin-left: 50%;
}
.jiedian {
width: 15vw;
height: 100%;
float: left;
margin-left: 26vw;
margin-right: 1vw;
}
.jiedian1 {
width: 15vw;
height: 100%;
float: left;
margin-left: 32vw;
margin-right: 1vw;
}
.jiedianText {
float: left;
font-size: 1.2vw;
color: #ffffff;
font-family: '微软雅黑';
margin-right: 8%;
letter-spacing: 0.1vw;
}
select {
color: #ffffff;
}
.jiedianList {
width: 8vw;
height: 75%;
margin-top: 1.5%;
/*box-shadow: rgba(92, 228, 229, 0.31) 1px 1px 8px 0px;*/
border-radius: 2vw;
border: #ffffff 1px solid;
background: transparent;
outline: none;
/* 鼠标移上,变小手 */
cursor: pointer;
float: left;
/* 清除默认的箭头样式 */
}
.jiedianNum {
height: 1.5vw;
width: 30%;
margin-left: 1%;
border: none;
border-radius: 2vw;
background: rgba(255, 255, 255, 0.75);
text-indent: 2px;
}
/*.jiansuo {*/
/* width: 7%;*/
/* height: 80%;*/
/* line-height: 1.8vw;*/
/* background-color: transparent;*/
/* float: right;*/
/* margin-top: 0.2%;*/
/* margin-right: 1%;*/
/* border-radius: 2vw;*/
/* text-align: center;*/
/* color: #ffffff;*/
/* border: #ffffff 1px solid;*/
/* font-size: 1vw;*/
/*}*/
.custom-menu {
position: absolute;
padding: 5px 0px;
background-color: rgba(84, 92, 100, 0.8);
top: 100px;
left: 100px;
border-radius: 5px;
z-index: 1000;
display: none;
}
.icon1 {
margin-left: 45%;;
cursor: pointer;
color: #ffffff;
width: 2vw;
height: 2vw;
font-size: 2vw;
}
.icon2 {
margin-left: 45%;
cursor: pointer;
font-size: 2px;
color: #ffffff;
width: 2vw;
height: 2vw;
font-size: 2vw;
}
.custom-menu div {
padding: 5px 0px;
text-align: center;
}
.custom-menu div span {
font-family: '微软雅黑';
font-size: 12px;
color: rgb(255, 255, 255);
}
.custom-menu div span:hover {
cursor: pointer;
color: orange;
}
.loadPng {
position: absolute;
right: 3vw;
top: 1vw;
z-index: 9999;
cursor: pointer;
font-size: 1.5vw;
color: #ffffff;
}
loadPng:hover {
color: #ffffff;
}
.screenPng {
position: absolute;
right: 1vw;
top: 2vh;
z-index: 9999;
cursor: pointer;
font-size: 1.5vw;
color: #ffffff;
}
.screenPng:hover {
color: #ffffff;
}
.show-box {
position: relative;
background: transparent;
/*border: 1px solid #04538e;*/
border-radius: 5px;
height: calc(100%);
/*border-radius: 0 0 2vw 2vw;*/
}
.full-screen {
position: fixed;
background: #2d3562;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.other {
width: 2vw;
height: 3vw;
z-index: 100;
bottom: 4vw;
position: absolute;
/*background-color: red;*/
}
*::-webkit-scrollbar {
display: none;
}
.rel-node-checked {
transition: background-color .2s ease, outline .2s ease, color .2s ease, -webkit-box-shadow .2s ease;
box-shadow: 0 0 20px 15px #C0FFF9FF !important;
}
.label {
font-size: 1vw;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: inline-block;
width: 12vw;
height: 2vw;
}
input::-webkit-input-placeholder {
color: #FFFFFF;
}
</style>
<style>
.rel-node-checked {
transition: background-color .2s ease, outline .2s ease, color .2s ease, -webkit-box-shadow .2s ease;
box-shadow: 0 0 20px 15px #C0FFF9FF !important;
}
.el-tree-node__content:hover {
background: rgba(255, 255, 255, 0.21);
font-weight: 550;
.lineInfo {
background: #0012ff !important;
}
}
.el-tree--highlight-current {
.el-tree-node.is-current > .el-tree-node__content {
background-color: rgba(255, 255, 255, 0.21);
color: #fff;
.lineInfo {
background: #0012ff !important;
}
}
}
.el-tree-node__content {
color: #ffffff;
height: 2vw !important;
padding-left: 2vw !important;
padding-right: 2vw !important;
}
.el-tree-node {
cursor: pointer;
}
.el-tree-node__children {
overflow: visible !important
}
.el-tree-node__expand-icon {
position: absolute !important;
right: 10% !important;
width: 1vw;
height: 1vw;
}
.el-tree-node is-expanded is-focusable .el-tree-node__label {
padding-left: 15px !important;
}
.el-tree-node__expand-icon {
margin-top: 5px;
-webkit-transform: rotate(-90deg);
transform: rotate(90deg);
}
.el-tree-node__expand-icon.is-leaf {
display: none;
}
/* 三角图标 展开 */
.el-tree-node__expand-icon.expanded {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.label {
font-size: 1vw;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: inline-block;
width: 12vw;
height: 2vw;
}
input::-webkit-input-placeholder {
color: #FFFFFF;
}
/* .gContainer :deep(.relation-graph) :deep(.rel-map) {
background-color: #2d3562 !important;
} */
.gContainer .relation-graph .rel-map,
.relation-graph .rel-map,
.rel-map {
background-color: #2d3562 !important;
}
.el-drawer__title {
display: flex;
justify-content: center;
align-items: center;
width: 90%;
color: #fff;
}
.el-drawer__close-btn {
width: 1.5vw;
}
.el-drawer__header {
display: flex;
}
.el-table__header {
width: 100%;
}
.el-table:not(.el-table--border) .el-table__cell {
/* border-right: none; */
border: none;
}
tr {
margin-bottom: 2vh;
}
.el-tree--highlight-current {
background: no-repeat;
}
.el-icon{
color: #FFFFFF !important;
font-size: 1vw;
}
.lineclass{
filter: drop-shadow(0 0 10px white) !important; /* 添加白色光晕 */
}
.nodeclass {
/* 白色 3px 边框 */
stroke: white !important;
stroke-width: 3 !important;
stroke-opacity: 1 !important;
font-size: 20px !important;
/* 多层光晕:内层青色,外层白色 */
filter:
drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */
drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */
drop-shadow(0 0 20px rgba(0, 255, 255, 1)) /* 内层青色光晕 */
drop-shadow(0 0 50px rgba(255, 255, 255, 1)); /* 外层白色光晕 */
/* 确保边框在填充之上 */
paint-order: stroke fill !important;
}
.nodeclassnormal{
font-size: 20px !important;
}
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: red;
font-weight: 600;
color:white;
}
.el-table .success-row:hover > .el-table__cell {
background-color: red !important;
color: white !important;
font-weight: 600;
}
.el-table .cell{
width:400px;
}
.el-table__inner-wrapper{
height: auto;
background-color: #fff;
}
.el-table__empty-block{
background-color: #fff;
width: 400px!important;
}
.label1 {
font-size: 1vw;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: inline-block;
width: 14vw;
height: 2vw;
}
.lineInfo.lineInfo-active {
background: #0012ff !important;
box-shadow: rgb(255, 255, 255) 0px 0px 4px 1px;
}
.flow-tree {
/* 默认样式(可选) */
transition: background-color 0.3s ease, font-weight 0.3s ease;
}
.flow-tree-active {
background-color: rgba(255, 255, 255, 0.21);
font-weight: 600;
}/* 选中时的高亮样式(优先级更高) */
/* hover:鼠标悬停时 */
.flow-tree:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.c-node-menu-item{
line-height: 30px;padding-left: 10px;cursor: pointer;color: #444444;font-size: 14px;border-top:#efefef solid 1px;
}
.c-node-menu-item:hover{
background-color: rgba(64, 158, 255,0.2);
color:#409eff
}
</style>