diff --git a/gyxtp/src/view/graphPageCopy.vue b/gyxtp/src/view/graphPageCopy.vue index bb3780f..6a04d84 100644 --- a/gyxtp/src/view/graphPageCopy.vue +++ b/gyxtp/src/view/graphPageCopy.vue @@ -228,6 +228,7 @@ import {getAllTitle, getDocInfo} 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: { @@ -521,22 +522,53 @@ export default { "nodes": res.nodes.hits, "links":res.links.hits } + console.log(this.heightLight) getDomainGraphTest({}).then((r) => { this.zhengl(r.data); }) }) }, - getNodeClass(id){ - if (this.heightLight=={}){ - return "" + getNodeClass(name) { + + // 确保 this.heightLight.nodes 存在且是一个数组 + const nodes = this.heightLight.nodes; + if (!Array.isArray(nodes) || nodes.length === 0) { + return ""; } - if (id) { - this.heightLight.nodes + // 将传入的 id 转为字符串 + const targetId = String(name).trim(); + // 遍历 nodes 数组,检查是否有元素的 id(转字符串)与 targetId 相等 + const found = nodes.some(node => { + const nodeId = node.sourceAsMap.abstracts + return nodeId === targetId; + }); + + + // 找到了返回 'nodeclass',否则返回 '' + return found ? 'nodeclass' : ''; + }, + getLinesClass(from) { + + const lines = this.heightLight.links; + if (lines == undefined){ + return } - return "" - return "nodeclass" + + // 将传入的 id 转为字符串 + const targetId = String(from).trim(); + const found = lines.some(line => { + const data = line.sourceAsMap.data + return data.some(item => { + const source = item.source; + console.log(source) + console.log(targetId) + return source === targetId; + }); + }); + // 找到了返回 'nodeclass',否则返回 '' + return found ? 'lineclass' : ''; }, async onLineClick(lineObject, linkObject, event) { const from = linkObject.fromNode.data.docId @@ -552,6 +584,7 @@ export default { //整理图谱数据 //整理图谱数据 zhengl(data) { + console.log(data) const nodes = [] const links = [] const nodeList = data.nodes; @@ -708,7 +741,7 @@ export default { color: color, font: `normal ${fontSize} Arial`, fontColor: fontColor, - styleClass:this.getNodeClass(node.id), + styleClass:this.getNodeClass(node.name), }); }); }); @@ -801,7 +834,7 @@ export default { color: color, font: `normal ${fontSize} Arial`, fontColor: fontColor, - styleClass:"nodeclass", + styleClass:this.getNodeClass(node.name), }); }); } else { @@ -884,7 +917,7 @@ export default { color: color, font: `normal ${fontSize} Arial`, fontColor: fontColor, - styleClass:"nodeclass", + styleClass:this.getNodeClass(node.name), }); currentLeftX -= 200; @@ -952,7 +985,7 @@ export default { color: color, font: `normal ${fontSize} Arial`, fontColor: fontColor, - styleClass:"nodeclass", + styleClass:this.getNodeClass(node.name), }); currentRightX += 200; @@ -960,9 +993,9 @@ export default { } }); }); - // 处理连线 lineList.forEach(line => { + console.log(line) links.push({ from: line.source, to: line.target, @@ -972,451 +1005,9 @@ export default { line.num <= 10 ? 'rgb(0, 255, 0)' : // 绿色 line.num <= 15 ? 'rgb(255, 255, 0)' : // 黄色 'rgb(178,246,255)', // 红色(包含line.num <= 20和超过20的情况) - lineWidth:10, - lineShape: 1, - styleClass:"lineclass", - }) - }); - - 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(); - } - }); - }, - - zhengl1(data) { - const nodes = [] - const links = [] - const nodeList = data.nodes; - const lineList = data.links; - - // 创建节点映射表,方便查找 - const nodeMap = {}; - nodeList.forEach(node => { - nodeMap[node.id] = node; - }); - - // 找出有连接的节点 - const connectedNodeIds = new Set(); - lineList.forEach(line => { - connectedNodeIds.add(line.source); - connectedNodeIds.add(line.target); - }); - - // 按层级和组别分组孤立节点 - const isolatedNodesByGroupAndLevel = {}; - nodeList.forEach(node => { - if (!connectedNodeIds.has(node.id)) { - const groupId = node.groupId || '1'; - const level = node.docLeve || '0'; - if (!isolatedNodesByGroupAndLevel[groupId]) { - isolatedNodesByGroupAndLevel[groupId] = {}; - } - if (!isolatedNodesByGroupAndLevel[groupId][level]) { - isolatedNodesByGroupAndLevel[groupId][level] = []; - } - isolatedNodesByGroupAndLevel[groupId][level].push(node); - } - }); - - // 存储每个层级每个组别的节点位置信息 - const levelGroupPositions = {}; - - // 处理有连接的节点 - 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 = { - '0': -10200, // 左侧区域 - '1': 0, // 中间区域 - '2': 10200 // 右侧区域 - }; - - // 处理每个组别的节点 - Object.keys(groupedNodes).forEach(groupId => { - 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 + levelNodes.length * 200 + 200, // 右侧可用位置 - hasConnectedNodes: levelNodes.length > 0 - }; - } - - levelNodes.forEach((node, index) => { - if (levelNum === 0) this.rootId = node.id; - - // 根据层级设置节点样式 - 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; - const y = levelNum * 1400; - - // 添加节点 - 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 - }); - }); - }); - }); - } - - // 处理孤立节点 - 放置在有连线节点的两侧 - 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 = 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; - - nodes.push({ - id: node.id, - text: node.name, - data: { - docId: node.docId, - group: node.groupId - }, - x: x, - y: y, - fixed: true, - width: 150, - height: 150, - color: color, - font: `normal ${fontSize} Arial`, - fontColor: fontColor - }); - }); - } 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)'; - } - - nodes.push({ - id: node.id, - text: node.name, - data: { - docId: node.docId, - group: node.groupId - }, - x: currentLeftX, - y: y, - fixed: true, - width: 150, - height: 150, - color: color, - font: `normal ${fontSize} Arial`, - fontColor: fontColor - }); - - 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)'; - } - - nodes.push({ - id: node.id, - text: node.name, - data: { - docId: node.docId, - group: node.groupId - }, - x: currentRightX, - y: y, - fixed: true, - width: 150, - height: 150, - color: color, - font: `normal ${fontSize} Arial`, - fontColor: fontColor - }); - - currentRightX += 200; - }); - } - }); - }); - - // 处理连线 - lineList.forEach(line => { - links.push({ - 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(255, 0, 0)', // 红色(包含line.num <= 20和超过20的情况) - lineWidth: - line.num <= 5 ? 1 : - line.num <= 10 ? 1.1 : - line.num <= 15 ? 1.2 : - line.num <= 20 ? 15 : 1.3, + lineWidth:1, lineShape: 1, + styleClass:this.getLinesClass(line.source), }) }); diff --git a/ruoyi-api/src/main/java/com/ruoyi/api/controller/EsTestController.java b/ruoyi-api/src/main/java/com/ruoyi/api/controller/EsTestController.java index 73925be..9dde732 100644 --- a/ruoyi-api/src/main/java/com/ruoyi/api/controller/EsTestController.java +++ b/ruoyi-api/src/main/java/com/ruoyi/api/controller/EsTestController.java @@ -9,7 +9,9 @@ import com.ruoyi.api.domain.ESDao; import com.ruoyi.api.domain.ZhyDocApi; import com.ruoyi.api.mapper.ZhyDocApiMapper; import com.ruoyi.system.domain.ZhyArticle; +import com.ruoyi.system.domain.ZhyDocRelation; import com.ruoyi.system.mapper.ZhyArticleMapper; +import com.ruoyi.system.mapper.ZhyDocRelationMapper; import org.elasticsearch.search.SearchHits; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; @@ -45,6 +47,8 @@ public class EsTestController { @Autowired ZhyArticleMapper zhyArticleMapper; + @Autowired + ZhyDocRelationMapper zhyDocRelationMapper; @Autowired private org.elasticsearch.client.RestHighLevelClient client; @@ -57,7 +61,8 @@ public class EsTestController { @GetMapping("/esdeleteIndex") public boolean deleteIndex() throws IOException { - return elasticSearchUtil.deleteIndex("111"); + elasticSearchUtil.deleteIndex("nodes"); + return elasticSearchUtil.deleteIndex("links"); } @GetMapping("/esQuery2") public SearchHits indexCreate2() throws Throwable { @@ -116,6 +121,7 @@ public class EsTestController { esDao.DBid = id; esDao.type = "node"; esDao.abstracts = abstracts; + esDao.data = null; bookList.add(esDao); } elasticSearchUtil.addDocBatch("nodes", bookList, ESDao.class, "id"); @@ -126,12 +132,16 @@ public class EsTestController { for (int i=0;i a = zhyDocRelationMapper.selectZhyRelationshipArticle(zhyDocRelation); ESDao esDao = new ESDao(); esDao.id = id; esDao.DBid = id; esDao.type = "line"; esDao.abstracts = abstracts; + esDao.data = a; bookList.add(esDao); } elasticSearchUtil.addDocBatch("links", bookList, ESDao.class, "id"); diff --git a/ruoyi-api/src/main/java/com/ruoyi/api/domain/ESDao.java b/ruoyi-api/src/main/java/com/ruoyi/api/domain/ESDao.java index eb97987..b91be99 100644 --- a/ruoyi-api/src/main/java/com/ruoyi/api/domain/ESDao.java +++ b/ruoyi-api/src/main/java/com/ruoyi/api/domain/ESDao.java @@ -1,25 +1,38 @@ package com.ruoyi.api.domain; +import java.util.List; +import java.util.Map; + public class ESDao { public String id; public String DBid; //图谱中线id public String type; public String abstracts; //摘要 + public List data; public String getId() { return id; } + public List getData() { + return data; + } + @Override public String toString() { return "ESDao{" + - "id=" + id + - ", DBid=" + DBid + - ", type=" + type + + "id='" + id + '\'' + + ", DBid='" + DBid + '\'' + + ", type='" + type + '\'' + ", abstracts='" + abstracts + '\'' + + ", data=" + data + '}'; } + public void setData(List data) { + this.data = data; + } + public void setId(String id) { this.id = id; } diff --git a/ruoyi-api/src/main/java/com/ruoyi/api/service/impl/GraphServiceImpl.java b/ruoyi-api/src/main/java/com/ruoyi/api/service/impl/GraphServiceImpl.java index c675e03..100ed98 100644 --- a/ruoyi-api/src/main/java/com/ruoyi/api/service/impl/GraphServiceImpl.java +++ b/ruoyi-api/src/main/java/com/ruoyi/api/service/impl/GraphServiceImpl.java @@ -872,6 +872,9 @@ public class GraphServiceImpl implements GraphService { Map> mergedMap = new LinkedHashMap<>(); for (HashMap rel : relations) { + +// System.out.println(rel); + String sourceId = String.valueOf(rel.get("sourceid")); String targetId = String.valueOf(rel.get("targetid")); String key = sourceId + "->" + targetId; @@ -880,6 +883,7 @@ public class GraphServiceImpl implements GraphService { link.put("source", sourceId); link.put("target", targetId); link.put("relate", rel.get("name")); + link.put("id",rel.get("uuid")); HashMap srcNode = nodeIndex.get(sourceId); HashMap tgtNode = nodeIndex.get(targetId); diff --git a/ruoyi-system/src/main/resources/mapper/system/ZhyDocRelationMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ZhyDocRelationMapper.xml index 9adbc06..2f2b2c9 100644 --- a/ruoyi-system/src/main/resources/mapper/system/ZhyDocRelationMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/ZhyDocRelationMapper.xml @@ -132,6 +132,9 @@ from zhy_relationship AND r.targetName = #{targetName} + + AND r.article_id = #{articleId} + ORDER BY r.create_time DESC