0
0

2 کامیت‌ها b8261cd9b4 ... 82fc12f9af

نویسنده SHA1 پیام تاریخ
  Zhangtf 82fc12f9af 思维导图 11 ماه پیش
  Zhangtf 54d573f320 思维导图 11 ماه پیش

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1219 - 2
package-lock.json


+ 5 - 1
package.json

@@ -1 +1,5 @@
-{}
+{
+  "dependencies": {
+    "mermaid": "^11.11.0"
+  }
+}

+ 6 - 0
xzl-admin/pom.xml

@@ -16,6 +16,12 @@
     </description>
 
     <dependencies>
+        <dependency>
+            <groupId>com.github.eljah</groupId>
+            <artifactId>xmindjbehaveplugin</artifactId>
+            <version>0.8</version>
+        </dependency>
+
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>

+ 145 - 0
xzl-admin/src/main/java/com/xzl/XzlApplication.java

@@ -1,17 +1,25 @@
 package com.xzl;
 
+import com.alibaba.fastjson.JSONObject;
+import com.xzl.common.core.domain.entity.MindMapNode;
 import com.xzl.common.utils.MinioUtil;
 import com.xzl.common.utils.SecurityUtils;
 import io.minio.BucketExistsArgs;
 import io.minio.MakeBucketArgs;
 import io.minio.MinioClient;
 import io.minio.PutObjectArgs;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.context.annotation.Bean;
+import org.xmind.core.*;
 
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
 
 import static com.xzl.web.core.config.MinIOConfig.getMinioClient;
 
@@ -27,5 +35,142 @@ public class XzlApplication {
     SpringApplication.run(XzlApplication.class, args);
     System.out.println(SecurityUtils.encryptPassword("123456"));
     System.out.println("系统启动成功 ...");
+    String data ="{  \n" +
+            "  \"\": \"层级1节点\",  \n" +
+            "  \"\": \"层级1备注\",  \n" +
+            "  \"sonNode\": [  \n" +
+            "    {  \n" +
+            "      \"contentTxt\": \"层级2节点\",  \n" +
+            "      \"remark\": \"层级2备注\",  \n" +
+            "      \"sonNode\": [  \n" +
+            "        {  \n" +
+            "          \"contentTxt\": \"层级3节点\",  \n" +
+            "          \"remark\": \"层级3备注\",  \n" +
+            "          \"sonNode\": []  \n" +
+            "        },  \n" +
+            "        {  \n" +
+            "          \"contentTxt\": \"层级3节点\",  \n" +
+            "          \"remark\": \"层级3备注\",  \n" +
+            "          \"sonNode\": []  \n" +
+            "        }  \n" +
+            "      ]  \n" +
+            "    },  \n" +
+            "    {  \n" +
+            "      \"contentTxt\": \"层级2节点\",  \n" +
+            "      \"remark\": \"层级2备注\",  \n" +
+            "      \"sonNode\": []  \n" +
+            "    }  \n" +
+            "  ],\n" +
+            "  \"contentTxt\": \"层级1节点2\",  \n" +
+            "  \"remark\": \"层级1备注2\",\n" +
+            "  \"sonNode\": [\n" +
+            "        {\n" +
+            "            \"contentTxt\": \"层级2节点2\",\n" +
+            "            \"remark\": \"层级2备注2\",\n" +
+            "            \"sonNode\": [\n" +
+            "                {\n" +
+            "                    \"contentTxt\": \"层级3节点2\",\n" +
+            "                    \"remark\": \"层级3备注2\",\n" +
+            "                    \"sonNode\": []\n" +
+            "                },\n" +
+            "                {\n" +
+            "                    \"contentTxt\": \"层级3节点2\",\n" +
+            "                    \"remark\": \"层级3备注2\",\n" +
+            "                    \"sonNode\": []\n" +
+            "                }\n" +
+            "            ]\n" +
+            "        },\n" +
+            "        {\n" +
+            "            \"contentTxt\": \"层级2节点2\",\n" +
+            "            \"remark\": \"层级2备注2\",\n" +
+            "            \"sonNode\": []\n" +
+            "        }\n" +
+            "    ]\n" +
+            "}\n";
+    List<MindMapNode> mindMapNodes = JSONObject.parseArray(data, MindMapNode.class);
+      try {
+          createMindMap(mindMapNodes,"测试!", new OutputStream() {
+            @Override
+            public void write(int b) throws IOException {
+
+            }
+          });
+      } catch (IOException e) {
+          throw new RuntimeException(e);
+      } catch (CoreException e) {
+          throw new RuntimeException(e);
+      }
+//创建思维导图的工作空间
+    IWorkbookBuilder workbookBuilder = Core.getWorkbookBuilder();
+    IWorkbook workbook = workbookBuilder.createWorkbook();
+//获得默认sheet
+    ISheet primarySheet = workbook.getPrimarySheet();
+
+// 创建根节点
+    ITopic rootTopic = primarySheet.getRootTopic();
+    ITopic topicSon = workbook.createTopic();
+
+    //设置根主题的标题
+    rootTopic.setTitleText("测试!");
+// 根主题对象
+    rootTopic.setStructureClass("org.xmind.ui.logic.left");
+    topicSon.setTitleText(mindMapNodes.get(1).getContentTxt());
+    // 备注
+    IPlainNotesContent plainContent = (IPlainNotesContent) workbook.createNotesContent(INotes.PLAIN);
+    plainContent.setTextContent(mindMapNodes.get(1).getRemark());
+    INotes notes = topicSon.getNotes();
+    notes.setContent(INotes.PLAIN, plainContent);
+    buildNode(mindMapNodes.get(1).getSonNode(),topicSon,workbook);
+    topicSon.add(topicSon);
+//组装节点到根节点
+    rootTopic.add(topicSon);
+
   }
+
+  /**
+   * 创建脑图
+   * @param nodes 目标节点
+   * @param root 根节点名称
+   * @param os 输出
+   * @throws IOException
+   * @throws CoreException
+   */
+  public static void createMindMap(List<MindMapNode> nodes, String root,OutputStream os) throws IOException, CoreException {
+    //创建脑图工作空间
+    IWorkbookBuilder workbookBuilder = Core.getWorkbookBuilder();
+    IWorkbook workbook = workbookBuilder.createWorkbook();
+    //获得默认sheet
+    ISheet primarySheet = workbook.getPrimarySheet();
+    ITopic rootTopic = primarySheet.getRootTopic();
+    //根节点的标题
+    rootTopic.setTitleText(root);
+    rootTopic.setStructureClass("org.xmind.ui.logic.right");
+    buildNode(nodes,rootTopic,workbook);
+    workbook.save(os);
+  }
+
+  /**
+   * 创建脑图节点
+   * @param mindMapNodes 节点结合
+   * @param topic 根节点
+   * @param workbook 工作空间
+   */
+  private static void buildNode(List<MindMapNode> mindMapNodes, ITopic topic, IWorkbook workbook) {
+    if (ObjectUtils.isEmpty(mindMapNodes)) {
+      return;
+    } else {
+      for (MindMapNode mindMapNode : mindMapNodes) {
+        ITopic topicSon = workbook.createTopic();
+        topicSon.setTitleText(mindMapNode.getContentTxt());
+        // 备注
+        IPlainNotesContent plainContent = (IPlainNotesContent) workbook.createNotesContent(INotes.PLAIN);
+        plainContent.setTextContent(mindMapNode.getRemark());
+        INotes notes = topicSon.getNotes();
+        notes.setContent(INotes.PLAIN, plainContent);
+        buildNode(mindMapNode.getSonNode(),topicSon,workbook);
+        topic.add(topicSon);
+      }
+    }
+  }
+
 }

+ 4 - 11
xzl-admin/src/main/java/com/xzl/web/core/config/MinIOConfig.java

@@ -1,26 +1,19 @@
 package com.xzl.web.core.config;
-import io.minio.BucketExistsArgs;
-import io.minio.MakeBucketArgs;
 import io.minio.MinioClient;
-import io.minio.PutObjectArgs;
-import io.minio.errors.*;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
-import java.io.FileInputStream;
-
 @Configuration
 public class MinIOConfig {
-    private static final String ENDPOINT = "http://192.168.1.12:9000";
+    private static final String ENDPOINT = "http://127.0.0.1:9000";
     private static final String ACCESS_KEY = "your-access-key";
     private static final String SECRET_KEY = "your-secret-key";
 
     @Bean
-    public static MinioClient getMinioClient() throws Exception {
-
-
+    public MinioClient getMinioClient() throws Exception {
+        System.out.println("minioClient ...");
         return MinioClient.builder()
-                .endpoint("http://localhost:9000")
+                .endpoint("http://127.0.0.1:9000")
                 .credentials("minioadmin", "minioadmin")
                 .build();
     }

+ 7 - 4
xzl-admin/src/main/java/com/xzl/web/service/impl/KnowledgeFileServiceImpl.java

@@ -22,6 +22,7 @@ import com.xzl.web.service.KnowledgeFileService;
 import io.minio.*;
 
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Service;
@@ -30,7 +31,6 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
 
-import static com.xzl.web.core.config.MinIOConfig.getMinioClient;
 
 /**
  * 文件Service业务层处理
@@ -44,6 +44,9 @@ public class KnowledgeFileServiceImpl implements KnowledgeFileService {
     private final ISysFileFolderService sysFileFolderService;
     private final MinioUtil minioUtil;
 
+    @Autowired
+    private MinioClient minioClient;
+
 
     // 手动维护的文件扩展名与 ContentType 映射表
     private static final Map<String, String> CONTENT_TYPE_MAP = new HashMap<>();
@@ -121,7 +124,7 @@ public class KnowledgeFileServiceImpl implements KnowledgeFileService {
         // 删除MinIO存储桶中的文件
         for (KnowledgeFile file : files) {
             try {
-                MinioClient minioClient = getMinioClient();
+//                MinioClient minioClient = getMinioClient();
                 minioClient.removeObject(RemoveObjectArgs.builder()
                         .bucket(BUCKET_NAME)
                         .object(file.getFilePath())
@@ -234,7 +237,7 @@ public class KnowledgeFileServiceImpl implements KnowledgeFileService {
      */
     public void uploadFile(String bucketName, String objectName, MultipartFile file, String contentType) {
         try {
-            MinioClient minioClient = getMinioClient();
+//            MinioClient minioClient = getMinioClient();
 
             // 检查存储桶是否存在,不存在则创建
             boolean found = minioClient.bucketExists(BucketExistsArgs.builder()
@@ -350,7 +353,7 @@ public class KnowledgeFileServiceImpl implements KnowledgeFileService {
             // 记录详细错误日志
             System.err.println("文件下载失败: " + e.getMessage());
             e.printStackTrace();
-            
+
             // 提供更友好的错误响应
             try {
                 response.reset();

+ 2 - 2
xzl-admin/src/main/resources/application-dev.yml

@@ -11,7 +11,7 @@ spring:
 #                username: jerry
  #               password: zjr38zjR@
                 username: root
-                password: root
+                password: 123456
 #                url: jdbc:mysql://localhost:3306/xtdb?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
 #                username: root
 #                password: 1234
@@ -71,7 +71,7 @@ sqlFilePath: /usr/local/sql
 ERImagePath: /usr/local/ERImage
 
 minio:
-    endpoint: http://localhost:9000
+    endpoint: http://192.168.145.1:9000
     access-key: minioadmin
     secret-key: minioadmin
     bucket-name: mc-kb

+ 43 - 0
xzl-common/src/main/java/com/xzl/common/core/domain/entity/MindMapNode.java

@@ -0,0 +1,43 @@
+package com.xzl.common.core.domain.entity;
+
+import java.util.List;
+
+public class MindMapNode {
+    public String getContentTxt() {
+        return contentTxt;
+    }
+
+    public void setContentTxt(String contentTxt) {
+        this.contentTxt = contentTxt;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public List<MindMapNode> getSonNode() {
+        return sonNode;
+    }
+
+    public void setSonNode(List<MindMapNode> sonNode) {
+        this.sonNode = sonNode;
+    }
+
+    /**
+     * 内容
+     */
+    private String contentTxt;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 子节点
+     */
+    private List<MindMapNode> sonNode;
+
+}

+ 24 - 24
xzl-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -25,12 +25,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="remark"       column="remark"       />
         <result property="dingDeptId"   column="ding_dept_id" />
         <result property="dingUnionId"  column="ding_union_id"/>
-        <result property="nlpName"  column="nlp_name"/>
-        <result property="nlpPwd"  column="nlp_pwd"/>
+<!--        <result property="nlpName"  column="nlp_name"/>-->
+<!--        <result property="nlpPwd"  column="nlp_pwd"/>-->
         <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
     </resultMap>
-	
+
     <resultMap id="deptResult" type="SysDept">
         <id     property="deptId"    column="dept_id"     />
         <result property="parentId"  column="parent_id"   />
@@ -40,7 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="leader"    column="leader"      />
         <result property="status"    column="dept_status" />
     </resultMap>
-	
+
     <resultMap id="RoleResult" type="SysRole">
         <id     property="roleId"       column="role_id"        />
         <result property="roleName"     column="role_name"      />
@@ -49,9 +49,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="dataScope"    column="data_scope"     />
         <result property="status"       column="role_status"    />
     </resultMap>
-	
+
 	<sql id="selectUserVo">
-        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, 
+        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status, u.nlp_name, u.nlp_pwd
         from sys_user u
@@ -59,7 +59,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		    left join sys_user_role ur on u.user_id = ur.user_id
 		    left join sys_role r on r.role_id = ur.role_id
     </sql>
-    
+
     <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
 		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader ,
 		u.nlp_name, u.nlp_pwd
@@ -90,7 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<!-- 数据范围过滤 -->
 		${params.dataScope}
 	</select>
-	
+
 	<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
 	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
 	    from sys_user u
@@ -107,7 +107,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<!-- 数据范围过滤 -->
 		${params.dataScope}
 	</select>
-	
+
 	<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
 	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
 	    from sys_user u
@@ -125,29 +125,29 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<!-- 数据范围过滤 -->
 		${params.dataScope}
 	</select>
-	
+
 	<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
 	    <include refid="selectUserVo"/>
 		where u.user_name = #{userName} and u.del_flag = '0'
 	</select>
-	
+
 	<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
 		<include refid="selectUserVo"/>
 		where u.user_id = #{userId}
 	</select>
-	
+
 	<select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
 		select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1
 	</select>
-	
+
 	<select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
 		select user_id, phonenumber from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1
 	</select>
-	
+
 	<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
 		select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
 	</select>
-	
+
 	<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
  		insert into sys_user(
  			<if test="userId != null and userId != 0">user_id,</if>
@@ -187,7 +187,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		    sysdate()
  		)
 	</insert>
-	
+
 	<update id="updateUser" parameterType="SysUser">
  		update sys_user
  		<set>
@@ -212,28 +212,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  		</set>
  		where user_id = #{userId}
 	</update>
-	
+
 	<update id="updateUserStatus" parameterType="SysUser">
  		update sys_user set status = #{status} where user_id = #{userId}
 	</update>
-	
+
 	<update id="updateUserAvatar" parameterType="SysUser">
  		update sys_user set avatar = #{avatar} where user_name = #{userName}
 	</update>
-	
+
 	<update id="resetUserPwd" parameterType="SysUser">
  		update sys_user set password = #{password} where user_name = #{userName}
 	</update>
-	
+
 	<delete id="deleteUserById" parameterType="Long">
  		update sys_user set del_flag = '2' where user_id = #{userId}
  	</delete>
- 	
+
  	<delete id="deleteUserByIds" parameterType="Long">
  		update sys_user set del_flag = '2' where user_id in
  		<foreach collection="array" item="userId" open="(" separator="," close=")">
  			#{userId}
-        </foreach> 
+        </foreach>
  	</delete>
-	
-</mapper> 
+
+</mapper>

+ 1 - 1
xzl-ui/build/index.js

@@ -19,7 +19,7 @@ if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
   app.use(
     publicPath,
     serveStatic('./dist', {
-      index: ['index.html', '/']
+      index: ['mindmap.html', '/']
     })
   )
 

+ 6 - 0
xzl-ui/package.json

@@ -40,6 +40,7 @@
     "axios": "0.24.0",
     "clipboard": "2.0.8",
     "core-js": "3.25.3",
+    "d3": "^7.9.0",
     "echarts": "5.4.0",
     "element-ui": "2.15.13",
     "file-saver": "^2.0.5",
@@ -49,6 +50,10 @@
     "js-beautify": "1.13.0",
     "js-cookie": "3.0.1",
     "jsencrypt": "3.0.0-rc.1",
+    "markmap-common": "^0.15.3",
+    "markmap-lib": "^0.15.4",
+    "markmap-view": "^0.15.4",
+    "mermaid": "^8.14.0",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",
@@ -74,6 +79,7 @@
     "connect": "3.6.6",
     "eslint": "7.15.0",
     "eslint-plugin-vue": "7.2.0",
+    "html-loader": "^1.3.2",
     "lint-staged": "10.5.3",
     "runjs": "4.4.2",
     "sass": "1.32.13",

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 3 - 0
xzl-ui/src/api/system/m.js


+ 6 - 0
xzl-ui/src/router/index.js

@@ -41,6 +41,12 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/mindmap',
+    name: 'Mindmap',
+    component: () => import('@/views/fileTree/folder/MindmapView'),
+    meta: { title: '思维导图' }
+  },
   {
     path: '/login',
     component: () => import('@/views/login'),

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10 - 0
xzl-ui/src/utils/dict/mind.js


+ 278 - 0
xzl-ui/src/views/fileTree/folder/MindmapView.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="mindmap-container" :class="{ 'fullscreen-mode': isFullscreen }">
+    <div class="header">
+      <h1>麻城知识库思维导图</h1>
+      <div class="controls">
+        <button @click="downloadSvg" class="control-btn">
+          <i class="el-icon-download"></i>
+          下载SVG
+        </button>
+        <!--        <button @click="toggleFullscreen" class="control-btn">-->
+        <!--          <i :class="isFullscreen ? 'el-icon-shrink' : 'el-icon-full-screen'"></i>-->
+        <!--          {{ isFullscreen ? '退出全屏' : '全屏显示' }}-->
+        <!--        </button>-->
+      </div>
+    </div>
+
+    <div class="markmap-wrapper">
+      <div class="markmap">
+        <pre class="markmap-content">{{ markdownContent }}</pre>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MindmapView',
+  data() {
+    return {
+      markdownContent: `# 麻城知识库
+
+## 会议记录
+- 部门会议
+  - 小组会议
+  - 项目会议
+
+## 领导信息
+- 部门领导
+  - 信息
+
+## 综合档案
+- 工作档案
+  - 小组档案
+- 活动档案
+  - 周年庆
+
+## 政策汇总
+- 省政策
+  - 区政策
+  - 乡镇政策
+
+## 安全守则
+- 安全
+
+## 财务管理
+- 财务
+  - 111`,
+      isFullscreen: false
+    };
+  },
+  mounted() {
+    this.loadMarkmap();
+    // 添加resize监听
+    window.addEventListener('resize', this.handleResize);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.handleResize);
+  },
+  methods: {
+    getQueryData() {
+      const query = this.$route.query;
+      this.markdownContent = decodeURIComponent(query.data);
+    },
+    loadMarkmap() {
+      this.getQueryData();
+      // 动态加载markmap
+      const script = document.createElement('script');
+      script.src = 'https://cdn.jsdelivr.net/npm/markmap-autoloader';
+      script.onload = () => {
+        if (typeof markmapAutoLoader === 'function') {
+          markmapAutoLoader();
+          // 初始化完成后调整尺寸
+          this.$nextTick(() => {
+            setTimeout(this.fixSvgDimensions, 100);
+          });
+        }
+      };
+      document.head.appendChild(script);
+    },
+
+    fixSvgDimensions() {
+      // 获取所有SVG元素并修复尺寸
+      const svgElements = document.querySelectorAll('.markmap svg');
+      svgElements.forEach(svg => {
+        // 确保SVG有正确的尺寸属性
+        if (!svg.hasAttribute('width')) {
+          svg.setAttribute('width', '100%');
+        }
+        if (!svg.hasAttribute('height')) {
+          svg.setAttribute('height', '100%');
+        }
+
+        // 设置CSS确保正确显示
+        svg.style.width = '100%';
+        svg.style.height = '100%';
+        svg.style.display = 'block';
+
+        // 如果有markmap实例,调用fit方法
+        if (svg.__markmap__) {
+          svg.__markmap__.fit();
+        }
+      });
+    },
+
+    handleResize() {
+      // 窗口大小变化时重新调整
+      this.fixSvgDimensions();
+    },
+
+    toggleFullscreen() {
+      this.isFullscreen = !this.isFullscreen;
+      // 切换全屏后重新调整SVG
+      this.$nextTick(() => {
+        setTimeout(this.fixSvgDimensions, 300);
+      });
+    },
+
+    downloadSvg() {
+      const svgElement = document.querySelector('.markmap svg');
+      if (!svgElement) {
+        console.error('未找到SVG元素');
+        return;
+      }
+
+      try {
+        // 克隆SVG元素以避免影响原始显示
+        const clonedSvg = svgElement.cloneNode(true);
+
+        // 设置固定的宽度和高度以确保导出质量
+        const bbox = svgElement.getBBox();
+        clonedSvg.setAttribute('width', bbox.width + 100);
+        clonedSvg.setAttribute('height', bbox.height + 100);
+        clonedSvg.setAttribute('viewBox', `${bbox.x - 50} ${bbox.y - 50} ${bbox.width + 100} ${bbox.height + 100}`);
+
+        // 序列化SVG
+        const serializer = new XMLSerializer();
+        const svgStr = serializer.serializeToString(clonedSvg);
+
+        // 创建Blob并下载
+        const blob = new Blob([svgStr], { type: 'image/svg+xml' });
+        const url = URL.createObjectURL(blob);
+        const downloadLink = document.createElement('a');
+
+        // 生成文件名
+        const fileName = `麻城知识库思维导图_${new Date().toISOString().slice(0, 10)}.svg`;
+
+        downloadLink.href = url;
+        downloadLink.download = fileName;
+        document.body.appendChild(downloadLink);
+        downloadLink.click();
+        document.body.removeChild(downloadLink);
+
+        // 清理URL
+        setTimeout(() => URL.revokeObjectURL(url), 100);
+      } catch (error) {
+        console.error('下载SVG时出错:', error);
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.mindmap-container {
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+  background: white;
+  padding: 20px;
+  box-sizing: border-box;
+}
+
+.mindmap-container.fullscreen-mode {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 9999;
+  padding: 20px;
+  background: white;
+}
+
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid #e0e0e0;
+  flex-shrink: 0;
+}
+
+h1 {
+  margin: 0;
+  font-size: 24px;
+  color: #333;
+  font-weight: 600;
+}
+
+.controls {
+  display: flex;
+  gap: 12px;
+}
+
+.control-btn {
+  padding: 8px 16px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  background: white;
+  color: #606266;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 14px;
+  transition: all 0.3s ease;
+}
+
+.control-btn:hover {
+  background: #f5f7fa;
+  border-color: #c0c4cc;
+}
+
+.markmap-wrapper {
+  flex: 1;
+  min-height: 0;
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+  overflow: hidden;
+  position: relative;
+}
+
+.markmap {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.markmap-content {
+  display: none;
+}
+</style>
+
+<style>
+/* 全局样式 - 这是解决SVG全屏问题的关键 */
+.markmap svg {
+  width: 100% !important;
+  height: 100% !important;
+  display: block !important;
+}
+
+.markmap {
+  width: 100% !important;
+  height: 100% !important;
+}
+
+/* 确保markmap生成的SVG正确显示 */
+.markmap > svg {
+  max-width: none !important;
+  max-height: none !important;
+}
+</style>

+ 210 - 5
xzl-ui/src/views/fileTree/folder/index.vue

@@ -73,6 +73,15 @@
     @click="handleUpdateFolderName(data)">
     修改
   </el-button>
+
+        <el-button
+          size="mini"
+          type="primary"
+          plain
+          style="width: 120px;border: none; text-align: center;"
+          @click="swdt(data)">
+    查看思维导图
+  </el-button>
       <!-- 删除按钮始终显示 -->
   <el-button
     size="mini"
@@ -569,13 +578,13 @@ export default {
     });
   },
   methods: {
+
     parseTime,
     dict,
     /** 查询文件列表 */
     getList() {
       this.loading = true;
       let params = this.queryParams;
-      console.log('当前参数D:', params);
 
       // 自定义添加时间范围参数(小写开头)
       if (this.createDateRange && this.createDateRange.length === 2) {
@@ -595,7 +604,6 @@ export default {
         delete params.endUpdateTime;
       }
 
-      console.log('请求参数:', params);
       listFile(params).then(response => {
         this.fileList = response.rows;
         this.total = response.total;
@@ -606,7 +614,6 @@ export default {
     getFileTree() {
       folderTreeSelectByDeptId().then(response => {
         this.fileOptions = response.data;
-        console.log("获取到的文件夹树:", this.fileOptions);
       })
     },
     // 筛选节点
@@ -614,11 +621,210 @@ export default {
       if (!value) return true;
       return data.label.indexOf(value) !== -1;
     },
-    // 节点单击事件
+    /**
+     * 将子树转换为mermaid思维导图文本
+     * @param {object} node - 子树根节点(由getSubTree返回)
+     * @returns {string} mermaid思维导图代码
+     */
+    // 获取子树结构
+    getSubTree(nodeId, tree = this.fileOptions) {
+      for (const node of tree) {
+        if (node.id === nodeId) {
+          return JSON.parse(JSON.stringify(node)); // 深拷贝节点
+        }
+        if (node.children && node.children.length > 0) {
+          const result = this.getSubTree(nodeId, node.children);
+          if (result) return result;
+        }
+      }
+      return null;
+    },
+
+    convertToMindmap(node) {
+      if (!node || !node.label) return 'mindmap\n  (空数据)';
+
+      const MAX_DEPTH = 5;
+      const lines = ['mindmap']; // mindmap单独一行,不加空格
+
+      const generateLines = (currentNode, indentLevel = 1) => {
+        if (indentLevel > MAX_DEPTH) return;
+
+        // 处理空标签情况
+        const label = currentNode.label || '未命名节点';
+
+        // 转义特殊字符(括号、引号等)
+        const escapedLabel = label
+          .replace(/[()]/g, '\\$&') // 转义括号
+          .replace(/"/g, '\\"')     // 转义引号
+          .replace(/\s+/g, ' ')     // 替换多个空格为单个空格
+          .trim();                  // 去除首尾空格
+
+        // 每个节点单独一行,使用2个空格缩进
+        const indent = '  '.repeat(indentLevel);
+        lines.push(`${indent}${escapedLabel}`);
+
+        if (currentNode.children?.length) {
+          currentNode.children.forEach(child =>
+            generateLines(child, indentLevel + 1)
+          );
+        }
+      };
+
+      generateLines(node);
+
+      // 返回格式化的字符串,确保没有多余空格
+      return lines.join('\n');
+    },
+    convertToMarkdown(node) {
+      if (!node || !node.label) return '# 空数据';
+
+      const MAX_DEPTH = 5;
+      let markdownContent = `# ${node.label}\n\n`;
+
+      const generateMarkdown = (currentNode, depth = 2) => {
+        if (depth > MAX_DEPTH) return;
+
+        if (currentNode.children && currentNode.children.length > 0) {
+          currentNode.children.forEach(child => {
+            const indent = '  '.repeat(depth - 2);
+            markdownContent += `${indent}## ${child.label}\n`;
+
+            if (child.children && child.children.length > 0) {
+              child.children.forEach(grandchild => {
+                const subIndent = '  '.repeat(depth - 1);
+                markdownContent += `${subIndent}- ${grandchild.label}\n`;
+
+                if (grandchild.children && grandchild.children.length > 0) {
+                  grandchild.children.forEach(greatGrandchild => {
+                    const subSubIndent = '  '.repeat(depth);
+                    markdownContent += `${subSubIndent}- ${greatGrandchild.label}\n`;
+                  });
+                }
+              });
+            }
+
+            markdownContent += '\n';
+          });
+        }
+      };
+
+      generateMarkdown(node, 2);
+      return markdownContent;
+    },
+    swdt(data){
+      // 新增:生成Markdown格式思维导图并跳转
+      try {
+        const subTree = this.getSubTree(data.id);
+        if (!subTree) {
+          this.$message.error('未找到该节点的子树数据');
+          return;
+        }
+
+        const markdownData = this.convertToMarkdown(subTree);
+        console.log('生成的Markdown格式数据:', markdownData);
+
+        // 跳转到思维导图页面
+        // this.$router.push({
+        //   path: '/mindmap',
+        //   query: {
+        //     data: encodeURIComponent(markdownData),
+        //     title: data.label,
+        //     format: 'markdown'
+        //   }
+        // });
+
+        const routeData = this.$router.resolve({
+          path: '/mindmap',
+          query: {
+            data: encodeURIComponent(markdownData),
+            title: data.label,
+            format: 'markdown'
+          }
+        });
+        window.open(routeData.href, '_blank');
+      } catch (error) {
+        console.error('生成思维导图失败:', error);
+        this.$message.error('生成思维导图失败');
+      }
+    },
+    // 修改后的handleNodeClick方法
     handleNodeClick(data) {
+      // ...原有文件列表加载逻辑
+
       this.queryParams.folderId = data.id;
       this.selectedFolderId = data.id;
       this.handleQuery();
+
+    },
+// 验证思维导图数据格式
+    validateMermaidData(data) {
+      if (!data) return false;
+
+      // 基本格式检查
+      const lines = data.split('\n');
+      if (lines.length < 2) return false;
+
+      // 第一行必须是 'mindmap' 且单独一行
+      if (lines[0].trim() !== 'mindmap') return false;
+
+      return true;
+    },
+    async renderMindmap() {
+      try {
+        // 获取传递的数据
+        let mindmapData = decodeURIComponent(this.$route.query.data || '');
+        const title = this.$route.query.title || '思维导图';
+
+        // 保存原始数据用于调试
+        this.rawData = mindmapData;
+
+        console.log('接收到的思维导图数据:', mindmapData);
+
+        if (!mindmapData) {
+          throw new Error('未获取到思维导图数据');
+        }
+
+        // 清理数据:确保mindmap后是换行符
+        mindmapData = mindmapData.replace(/^mindmap\s+/, 'mindmap\n');
+
+        // 设置页面标题
+        document.title = title;
+
+        // 确保DOM已更新
+        await this.$nextTick();
+
+        // 检查容器元素是否存在
+        if (!this.$refs.mindmap) {
+          throw new Error('找不到思维导图容器元素');
+        }
+
+        // 清除容器内容
+        this.$refs.mindmap.innerHTML = '';
+
+        // 初始化并配置Mermaid
+        this.mermaid.initialize({
+          startOnLoad: false,
+          theme: 'neutral',
+          mindmap: {
+            nodeSpacing: 50,
+            levelDistance: 100
+          },
+          securityLevel: 'loose',
+          logLevel: 5 // 开启详细调试日志
+        });
+
+        // 渲染思维导图
+        const { svg } = await this.mermaid.render(
+          'mindmap',
+          mindmapData,
+          this.$refs.mindmap
+        );
+
+        this.$refs.mindmap.innerHTML = svg;
+      } catch (error) {
+        console.error('渲染思维导图失败:', error);
+        this.error = `渲染错误: ${error.message}\n\n请检查思维导图数据格式`;
+      }
     },
    /** 获取用户信息 */
    getUserInfo() {
@@ -791,7 +997,6 @@ export default {
       this.$message.error('文件上传失败,请重试');
     },
     getFolderName(row) {
-      console.log('row', row)
       return row.folderName
     },
     indexMethod(index) {

+ 66 - 0
xzl-ui/src/views/fileTree/folder/qqq.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>麻城知识库思维导图</title>
+    <!-- 使用Markmap替代Mermaid -->
+    <script src="https://cdn.jsdelivr.net/npm/markmap-autoloader"></script>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 0;
+            padding: 20px;
+            background-color: #f5f5f5;
+        }
+        .container {
+            background: white;
+            padding: 20px;
+            border-radius: 8px;
+            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+            max-width: 1200px;
+            margin: 0 auto;
+        }
+        .markmap {
+            width: 100%;
+            height: 600px;
+            border: 1px solid #ddd;
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <h1>麻城知识库思维导图</h1>
+        <div class="markmap">
+# 麻城知识库
+
+## 会议记录
+- 部门会议
+  - 小组会议
+  - 项目会议
+
+## 领导信息
+- 部门领导
+  - 信息
+
+## 综合档案
+- 工作档案
+  - 小组档案
+- 活动档案
+  - 周年庆
+
+## 政策汇总
+- 省政策
+  - 区政策
+  - 乡镇政策
+
+## 安全守则
+- 安全
+
+## 财务管理
+- 财务
+  - 111
+        </div>
+    </div>
+</body>
+</html>