From a6111acfd3130046a278927dd85886c668483212 Mon Sep 17 00:00:00 2001 From: linsheng0116 <1401679367@qq.com> Date: Mon, 13 Jan 2025 08:54:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?2025.1.8=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index e103c7d..e20118a 100644 --- a/pom.xml +++ b/pom.xml @@ -150,6 +150,7 @@ poi-ooxml ${poi.version} + org.springframework spring-test From 7c463c8bf258a20d55fe0d6336ab5e49899c2d85 Mon Sep 17 00:00:00 2001 From: linsheng0116 <1401679367@qq.com> Date: Mon, 20 Jan 2025 13:03:43 +0800 Subject: [PATCH 2/2] =?UTF-8?q?2025.1.8=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kcui/src/api/file.js | 8 + kcui/src/view/Home.vue | 224 ++++++++++++--------- .../java/com/main/woka/Common/util/KcInfo.java | 4 +- .../java/com/main/woka/Filter/SaTokenFilter.java | 3 +- .../woka/Web/Controller/KcTlFileController.java | 151 +++++++++++++- src/main/resources/Mapper/KcInfoRelationMapper.xml | 2 +- 6 files changed, 285 insertions(+), 107 deletions(-) diff --git a/kcui/src/api/file.js b/kcui/src/api/file.js index 42f6744..0eae896 100644 --- a/kcui/src/api/file.js +++ b/kcui/src/api/file.js @@ -19,4 +19,12 @@ export function addFile(file, config = {}) { data: formData, ...finalConfig }); +} + +export function addNode(data) { + return request({ + url: '/file/addNode', + method: 'post', + data:data + }) } \ No newline at end of file diff --git a/kcui/src/view/Home.vue b/kcui/src/view/Home.vue index bcbc787..f81713c 100644 --- a/kcui/src/view/Home.vue +++ b/kcui/src/view/Home.vue @@ -8,6 +8,33 @@
+ + + @@ -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 requestBody) throws IOException { + System.out.println(requestBody); + + Integer fileId = Integer.valueOf(requestBody.get("fileId")); + String txtName = requestBody.get("txtName"); + String TxtValue = requestBody.get("TxtValue"); + + String relation = requestBody.get("relation"); + Long parentId = Long.valueOf(requestBody.get("parentId")); + Long level = Long.valueOf(requestBody.get("level")); + KcTlFile kcTlFile = kcFileMapper.getFileById(fileId); + String url = kcTlFile.getFileUrl(); + int lastBackslashIndex = url.lastIndexOf('\\'); + String pathPart = url.substring(0, lastBackslashIndex + 1); + String result = pathPart + "wordSplitter"; + + String txtUrl = createTxtFile(result, txtName, TxtValue); + + + KcInfo kcInfo = new KcInfo(); + kcInfo.setFileId(fileId); + kcInfo.setCreateTime(new Date()); + kcInfo.setTwUrl(txtUrl); + kcInfo.setName(txtName); + kcInfo.setParentId(parentId); + kcInfo.setLevel(level); + kcInfo.setCreateTime(new Date()); + kcInfo.setCreateBy(Long.valueOf(String.valueOf(getUserId()))); + kcFileMapper.insertDoc(kcInfo); + + + + + + + //创建图谱 + String cql = "create (doc: Doc{"; + + List listNew = new ArrayList<>(); + if (kcInfo.getId() != null) { + Map bb = new HashMap<>(); + bb.put("key", "docId"); + bb.put("value", String.valueOf(kcInfo.getId())); + listNew.add(bb); + } + if (kcInfo.getName() != null && !kcInfo.getName().equals("")) { + Map bb = new HashMap<>(); + bb.put("key", "name"); + bb.put("value", String.valueOf(kcInfo.getName())); + listNew.add(bb); + } + if (kcInfo.getLevel() != null) { + Map bb = new HashMap<>(); + if (kcInfo.getLevel() == 1) { + bb.put("key", "leve"); + bb.put("value", "leve1"); + } + if (kcInfo.getLevel() == 2) { + bb.put("key", "leve"); + bb.put("value", "leve2"); + } + if (kcInfo.getLevel() == 3) { + bb.put("key", "leve"); + bb.put("value", "leve3"); + } + if (kcInfo.getLevel() == 4) { + bb.put("key", "leve"); + bb.put("value", "leve4"); + } + if (kcInfo.getLevel() == 5) { + bb.put("key", "leve"); + bb.put("value", "leve5"); + } + if (kcInfo.getLevel() == 6) { + bb.put("key", "leve"); + bb.put("value", "leve6"); + } + listNew.add(bb); + } + + for (int a = 0; a < listNew.size(); a++) { + + + if (listNew.get(a).size() > 1) { + if (a == 0) { + cql = cql + listNew.get(a).get("key") + ":'" + listNew.get(a).get("value") + "'"; + } else if (a == (listNew.size() - 1)) { + cql = cql + "," + listNew.get(a).get("key") + ":'" + listNew.get(a).get("value") + "'})"; + } else { + cql = cql + "," + listNew.get(a).get("key") + ":'" + listNew.get(a).get("value") + "'"; + } + } else { + cql = cql + listNew.get(a).get("key") + ":'" + listNew.get(a).get("value") + "'}) return doc"; + } + + } + StatementResult result1 = neo4jUtil.excuteCypherSql(cql); + int yy = kcFileMapper.updateGraphStatus(kcInfo.getId()); + + + //创建关系 + + KcInfoRelation zz = new KcInfoRelation(); + zz.setRelation(relation); + zz.setSourceId(parentId); + zz.setTargetId(kcInfo.getId()); + //查询上级 + KcInfo zz1 = new KcInfo(); + zz1.setId(parentId); + KcInfo oldDoc = kcFileMapper.selectDocById(zz1); + zz.setSourceName(oldDoc.getName()); + zz.setTargetName(txtName); + zz.setCreateTime(new Date()); + kcInfoRelationMapper.insertKcRelationship(zz); + + + //创建图谱 + String cqr = "MATCH (a:Doc),(b:Doc) WHERE a.docId = '" + zz.getSourceId() + "' AND b.docId = '" + zz.getTargetId() + "'CREATE (a)-[r:" + zz.getRelation() + "] -> (b) RETURN r"; + StatementResult result2 = neo4jUtil.excuteCypherSql(cqr); + + zz.setIsGraph(1l); + int yy1 = kcInfoRelationMapper.updateKcRelationship(zz); + + + return AjaxResult.success(); + } + + public String createTxtFile(String url, String txtName, String txtValue) { + String directory = url; + String filePath = Paths.get(directory, txtName).toString() + ".txt"; + + try (FileWriter writer = new FileWriter(filePath)) { + writer.write(txtValue); + System.out.println("File created successfully at: " + filePath); + } catch (IOException e) { + System.err.println("An error occurred while creating the file."); + e.printStackTrace(); + } + return filePath; + } } \ No newline at end of file diff --git a/src/main/resources/Mapper/KcInfoRelationMapper.xml b/src/main/resources/Mapper/KcInfoRelationMapper.xml index 1a11665..6c7f9d3 100644 --- a/src/main/resources/Mapper/KcInfoRelationMapper.xml +++ b/src/main/resources/Mapper/KcInfoRelationMapper.xml @@ -96,7 +96,7 @@ relation = #{relation}, source_id = #{sourceId}, - targe_id = #{targetId}, + target_id = #{targetId}, is_graph = #{isGraph}, where id = #{id}