@@ -16,6 +43,7 @@ import {getgraphInfo, test, userLogin} from "@/api/login";
import VisGraph from '@/assets/js/graphvis.min.20241008.js'
import LayoutFactory from '@/assets/js/graphvis.layout.min.js'
import {config} from '@/assets/defaultConfig.js'
+import {addNode} from "@/api/file";
export default {
// eslint-disable-next-line vue/multi-word-component-names
@@ -29,6 +57,17 @@ export default {
links: []
},
config,
+ visGraph: null, // 组件中保存VisGraph实例
+ isModalVisible: false,
+ newBranchContent: '',
+ selectedNode: null,
+
+ newBranchValue: '',
+ newBranchFileId: '',
+ newBranchLevel: null,
+ newBranchParentId: '',
+ newBranchRelation:''
+
}
},
methods:{
@@ -65,10 +104,77 @@ export default {
// this.goCenter();
}
this.loading = false;
+
},
// 创建全局绘图客户端对象
createGraph() {
- this.visGraph = new VisGraph(document.getElementById('graph-panel'), this.config)
+ const configWithEvents = {
+ ...this.config,
+ node: {
+ ...this.config.node,
+ ondblClick: (event, node) => {
+ this.showPopup(node);
+ }
+ }
+ };
+ this.visGraph = new VisGraph(document.getElementById('graph-panel'), configWithEvents);
+ },
+ showPopup(node) {
+ this.selectedNode = node;
+ this.newBranchParentId = node.properties.docId;
+ this.newBranchLevel = node.properties.level - 1;
+ this.isModalVisible = true; // 显示模态框
+ },
+ closeModal() {
+ this.isModalVisible = false;
+ this.newBranchContent = '';
+ this.selectedNode = null;
+ },
+ async addNewBranch() {
+ const content = this.newBranchContent.trim();
+ const value = this.newBranchValue.trim();
+ const fileId = this.newBranchFileId.trim();
+ const relation = this.newBranchRelation.trim();
+
+ if (this.selectedNode && content && value) {
+ // 构造数据
+ const data = {
+ fileId: fileId,
+ txtName: content,
+ TxtValue: value,
+ relation: relation,
+ parentId: this.newBranchParentId,
+ level: this.newBranchLevel
+ };
+
+ try {
+ await addNode(data);
+
+ // 创建新节点
+ const newNodeId = Date.now().toString(); // 使用时间戳作为唯一ID
+ const newNode = {
+ id: newNodeId,
+ label: content,
+ properties: { name: content, docId: newNodeId, level: this.newBranchLevel },
+ ...this.getNodeStyle(this.newBranchLevel) // 根据层级应用样式
+ };
+ const newLink = {
+ source: this.selectedNode.id,
+ target: newNodeId,
+ type: '',
+ };
+ this.graphData.nodes.push(newNode);
+ this.graphData.links.push(newLink);
+
+ // 刷新图谱
+ this.visGraph.drawData(this.graphData);
+ this.reLayout();
+ this.closeModal(); // 关闭模态框
+ } catch (error) {
+ console.error('Failed to add new branch:', error);
+ alert('Failed to add new branch. Please try again.');
+ }
+ }
},
// 执行布局算法
reLayout(alpha) {
@@ -123,103 +229,15 @@ export default {
var allOne = nodeList[0].docId
for (let a = 0; a < nodeList.length; a++) {
- if (nodeList[a].group == '0') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 450,
- color: '227,203,0',
- font: 'normal 70px Arial',
- fontColor: '255,255,255'
- })
- }
- if (nodeList[a].group == '1') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 350,
- width:350,
- height:300,
- color: '47,47,230',
- font: 'normal 68px Arial',
- fontColor: '255,255,255'
- })
- }
- if (nodeList[a].group == '2') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 300,
- width:300,
- height:250,
- color: '255,138,0',
- font: 'normal 50px Arial',
- fontColor: '255,255,255'
- })
- }
- if (nodeList[a].group == '3') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 250,
- width:250,
- height:250,
- color: '30,255,0',
- font: 'normal 40px Arial',
- fontColor: '0,0,0'
- })
- }
- if (nodeList[a].group == '4') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 200,
- width:200,
- height:200,
- color: '248,143,248',
- font: 'normal 32px Arial',
- fontColor: '255,255,255'
- })
- }
- if (nodeList[a].group == '5') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 150,
- width:150,
- height:150,
- color: '65,154,255',
- font: 'normal 30px Arial',
- fontColor: '255,255,255'
- })
- }
- if (nodeList[a].group == '6') {
- const aaa = {name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne}
- nodes.push({
- id: nodeList[a].id,
- label: nodeList[a].name,
- properties: aaa,
- size: 100,
- width:100,
- height:100,
- color: '0,228,255',
- font: 'normal 28px Arial',
- fontColor: '0,0,0'
- })
- }
+ const group = parseInt(nodeList[a].group, 10);
+ const style = this.getNodeStyle(group);
+ nodes.push({
+ id: nodeList[a].id,
+ label: nodeList[a].name,
+ properties: { name: nodeList[a].name, docId: nodeList[a].docId, parent: allOne },
+ ...style // 展开 style 对象以应用样式属性
+ });
}
@@ -242,7 +260,19 @@ export default {
}
this.drawGraphData();
},
+ getNodeStyle(group) {
+ const styles = [
+ { size: 450, color: '227,203,0', font: 'normal 70px Arial', fontColor: '255,255,255' },
+ { size: 350, width: 350, height: 300, color: '47,47,230', font: 'normal 68px Arial', fontColor: '255,255,255' },
+ { size: 300, width: 300, height: 250, color: '255,138,0', font: 'normal 50px Arial', fontColor: '255,255,255' },
+ { size: 250, width: 250, height: 250, color: '30,255,0', font: 'normal 40px Arial', fontColor: '0,0,0' },
+ { size: 200, width: 200, height: 200, color: '248,143,248', font: 'normal 32px Arial', fontColor: '255,255,255' },
+ { size: 150, width: 150, height: 150, color: '65,154,255', font: 'normal 30px Arial', fontColor: '255,255,255' },
+ { size: 100, width: 100, height: 100, color: '0,228,255', font: 'normal 28px Arial', fontColor: '0,0,0' }
+ ];
+ return styles[group] || {};
+ },
doLogin(){
userLogin().then((res)=>{
console.log(res);
diff --git a/src/main/java/com/main/woka/Common/util/KcInfo.java b/src/main/java/com/main/woka/Common/util/KcInfo.java
index 47c1ca9..343af4b 100644
--- a/src/main/java/com/main/woka/Common/util/KcInfo.java
+++ b/src/main/java/com/main/woka/Common/util/KcInfo.java
@@ -18,13 +18,11 @@ public class KcInfo {
private Long isGraph;
private Long level;
private Long groupId;
-
+ private Integer fileId;
public Integer getFileId() {return fileId;}
public void setFileId(Integer fileId) {this.fileId = fileId;}
- private Integer fileId;
-
public Long getId() {
return id;
}
diff --git a/src/main/java/com/main/woka/Filter/SaTokenFilter.java b/src/main/java/com/main/woka/Filter/SaTokenFilter.java
index fe7aa37..54ecdea 100644
--- a/src/main/java/com/main/woka/Filter/SaTokenFilter.java
+++ b/src/main/java/com/main/woka/Filter/SaTokenFilter.java
@@ -4,7 +4,6 @@ import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -21,7 +20,7 @@ public class SaTokenFilter implements WebMvcConfigurer {
// SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
// // 权限校验 -- 不同模块校验不同权限
// SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
- })).excludePathPatterns("/user/doLogin"); //开放
+ })).excludePathPatterns("/user/doLogin").excludePathPatterns("/file/**"); //开放
}
}
diff --git a/src/main/java/com/main/woka/Web/Controller/KcTlFileController.java b/src/main/java/com/main/woka/Web/Controller/KcTlFileController.java
index 8f73fca..2558370 100644
--- a/src/main/java/com/main/woka/Web/Controller/KcTlFileController.java
+++ b/src/main/java/com/main/woka/Web/Controller/KcTlFileController.java
@@ -1,25 +1,27 @@
package com.main.woka.Web.Controller;
import com.main.woka.Common.core.AjaxResult;
-import com.main.woka.Common.util.KcTlFile;
-import com.main.woka.Common.util.Neo4jUtil;
-import com.main.woka.Common.util.WebSocket;
+import com.main.woka.Common.util.*;
import com.main.woka.Web.Mapper.KcFileMapper;
import com.main.woka.Web.Mapper.KcInfoRelationMapper;
import com.main.woka.Web.Service.impl.KcTlFileServiceImpl;
import com.main.woka.Web.Service.impl.PdfUtil;
+import org.neo4j.driver.v1.StatementResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileWriter;
import java.io.IOException;
+import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.*;
@RestController
@RequestMapping("/file")
@@ -113,6 +115,147 @@ public class KcTlFileController extends BaseController {
return subDir.getPath();
}
+ @PostMapping("/addNode")
+ public AjaxResult addNode(@RequestBody Map