Sfoglia il codice sorgente

集成ShardingJdbc实现数据分片,并动态刷新数据节点

wukai 2 anni fa
parent
commit
3b2e14b9c4
32 ha cambiato i file con 1816 aggiunte e 112 eliminazioni
  1. 38 0
      lzga-api/lzga-api-system/src/main/java/com/jjt/system/api/RemoteActualDataNodesService.java
  2. 50 0
      lzga-api/lzga-api-system/src/main/java/com/jjt/system/api/factory/RemoteActualDataNodesFallbackFactory.java
  3. 1 0
      lzga-api/lzga-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  4. 6 3
      lzga-common/lzga-common-core/src/main/java/com/jjt/common/core/constant/ServiceNameConstants.java
  5. 26 6
      lzga-modules/lzga-doc/pom.xml
  6. 0 2
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/JJTDocApplication.java
  7. 23 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/AfterRunner.java
  8. 135 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/InitActualDataNodes.java
  9. 27 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/LambadaTools.java
  10. 52 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/controller/ActualDataNodesController.java
  11. 114 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/controller/DocInfoController.java
  12. 195 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/domain/DocInfo.java
  13. 23 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/mapper/ActualDataNodesMapper.java
  14. 72 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/mapper/DocInfoMapper.java
  15. 27 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/IActualDataNodesService.java
  16. 61 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/IDocInfoService.java
  17. 63 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/impl/ActualDataNodesServiceImpl.java
  18. 92 0
      lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/impl/DocInfoServiceImpl.java
  19. 13 16
      lzga-modules/lzga-doc/src/main/resources/lzga-doc-dev.yml
  20. 53 0
      lzga-modules/lzga-doc/src/main/resources/lzga-doc-local.yml
  21. 130 0
      lzga-modules/lzga-doc/src/main/resources/mapper/doc/DocInfoMapper.xml
  22. 60 42
      lzga-modules/lzga-doc/src/main/resources/mapper/doc/SysOperLogMapper.xml
  23. 7 12
      lzga-modules/lzga-doc/src/test/java/com/jjt/AppTest.java
  24. 44 0
      lzga-modules/lzga-doc/src/test/java/com/jjt/ShardingSpiDemoApplicationTests3.java
  25. 35 0
      lzga-modules/lzga-doc/src/test/java/com/jjt/SqlTest.java
  26. 13 17
      lzga-modules/lzga-file/src/main/java/com/jjt/file/controller/SysFileController.java
  27. 2 2
      lzga-modules/lzga-gen/src/main/resources/vm/java/controller.java.vm
  28. 11 11
      lzga-modules/lzga-gen/src/main/resources/vm/java/serviceImpl.java.vm
  29. 59 0
      lzga-modules/lzga-job/src/main/java/com/jjt/job/task/ActualDataNodesTask.java
  30. 44 0
      lzga-ui/src/api/doc/info/index.js
  31. 1 1
      lzga-ui/src/components/FileUpload/index.vue
  32. 339 0
      lzga-ui/src/views/doc/info/index.vue

+ 38 - 0
lzga-api/lzga-api-system/src/main/java/com/jjt/system/api/RemoteActualDataNodesService.java

@@ -0,0 +1,38 @@
+package com.jjt.system.api;
+
+import com.jjt.common.core.constant.SecurityConstants;
+import com.jjt.common.core.constant.ServiceNameConstants;
+import com.jjt.common.core.domain.R;
+import com.jjt.system.api.domain.SysUser;
+import com.jjt.system.api.factory.RemoteUserFallbackFactory;
+import com.jjt.system.api.model.LoginUser;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 用户服务
+ *
+ * @author ruoyi
+ */
+@FeignClient(contextId = "remoteActualDataNodesService", value = ServiceNameConstants.DOC_SERVICE, fallbackFactory = RemoteUserFallbackFactory.class)
+public interface RemoteActualDataNodesService {
+    /**
+     * 添加数据节点
+     *
+     * @param tableNames 表名列表
+     * @param source     请求来源
+     * @return 结果
+     */
+    @PostMapping("/nodes/create")
+    public R<?> createActualDataNodes(@RequestBody List<String> tableNames, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+
+    /**
+     * 刷新数据节点
+     *
+     * @param source 请求来源
+     */
+    @GetMapping("/nodes/refresh")
+    public R<?> refreshActualDataNodes(@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
+}

+ 50 - 0
lzga-api/lzga-api-system/src/main/java/com/jjt/system/api/factory/RemoteActualDataNodesFallbackFactory.java

@@ -0,0 +1,50 @@
+package com.jjt.system.api.factory;
+
+import com.jjt.common.core.domain.R;
+import com.jjt.system.api.RemoteActualDataNodesService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.openfeign.FallbackFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 用户服务降级处理
+ *
+ * @author ruoyi
+ */
+@Component
+public class RemoteActualDataNodesFallbackFactory implements FallbackFactory<RemoteActualDataNodesService> {
+    private static final Logger log = LoggerFactory.getLogger(RemoteActualDataNodesFallbackFactory.class);
+
+    @Override
+    public RemoteActualDataNodesService create(Throwable throwable) {
+        log.error("数据节点服务调用失败:{}", throwable.getMessage());
+        return new RemoteActualDataNodesService() {
+
+            /**
+             * 添加数据节点
+             *
+             * @param tableNames 表名列表
+             * @param source    请求来源
+             * @return 结果
+             */
+            @Override
+            public R<?> createActualDataNodes(List<String> tableNames, String source) {
+                return R.fail("添加数据节点失败:" + throwable.getMessage());
+            }
+
+            /**
+             * 刷新数据节点
+             *
+             * @param source          请求来源
+             */
+            @Override
+            public R<?> refreshActualDataNodes(String source) {
+                return R.fail("刷新数据节点失败:" + throwable.getMessage());
+            }
+
+        };
+    }
+}

+ 1 - 0
lzga-api/lzga-api-system/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1,3 +1,4 @@
 com.jjt.system.api.factory.RemoteUserFallbackFactory
 com.jjt.system.api.factory.RemoteLogFallbackFactory
 com.jjt.system.api.factory.RemoteFileFallbackFactory
+com.jjt.system.api.factory.RemoteActualDataNodesFallbackFactory

+ 6 - 3
lzga-common/lzga-common-core/src/main/java/com/jjt/common/core/constant/ServiceNameConstants.java

@@ -2,11 +2,10 @@ package com.jjt.common.core.constant;
 
 /**
  * 服务名称
- * 
+ *
  * @author ruoyi
  */
-public class ServiceNameConstants
-{
+public class ServiceNameConstants {
     /**
      * 认证服务的serviceid
      */
@@ -21,4 +20,8 @@ public class ServiceNameConstants
      * 文件服务的serviceid
      */
     public static final String FILE_SERVICE = "lzga-file";
+    /**
+     * 文档服务的serviceid
+     */
+    public static final String DOC_SERVICE = "lzga-doc";
 }

+ 26 - 6
lzga-modules/lzga-doc/pom.xml

@@ -18,12 +18,10 @@
 
     <dependencies>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>3.8.1</version>
-            <scope>test</scope>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.11</version>
         </dependency>
-
         <!-- Druid -->
         <dependency>
             <groupId>com.alibaba</groupId>
@@ -39,7 +37,7 @@
         <dependency>
             <groupId>org.apache.shardingsphere</groupId>
             <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
-            <version>5.1.2</version>
+            <version>5.2.0</version>
         </dependency>
 
         <!-- SpringCloud Alibaba Nacos -->
@@ -92,6 +90,28 @@
             <groupId>com.jjt</groupId>
             <artifactId>jjt-common-log</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <version>5.3.25</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+            <version>2.7.8</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <finalName>${project.artifactId}</finalName>

+ 0 - 2
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/JJTDocApplication.java

@@ -12,8 +12,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  *
  * @author ruoyi
  */
-//@EnableCustomSwagger2
-//@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
 @EnableCustomConfig
 @EnableCustomSwagger2
 @EnableRyFeignClients

+ 23 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/AfterRunner.java

@@ -0,0 +1,23 @@
+package com.jjt.doc.config;
+
+import com.jjt.doc.service.IActualDataNodesService;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Component
+@Order(value = 8)
+public class AfterRunner implements ApplicationRunner {
+    @Resource
+    private IActualDataNodesService actualDataNodesService;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        actualDataNodesService.refreshActualDataNodes();
+        System.out.println("刷新数据节点成功!!!");
+    }
+}

+ 135 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/InitActualDataNodes.java

@@ -0,0 +1,135 @@
+package com.jjt.doc.config;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource;
+import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.util.expr.InlineExpressionParser;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.rule.TableRule;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+/**
+ * 动态刷新 ShardingJdbc数据节点
+ */
+public class InitActualDataNodes {
+    @Resource
+    private ShardingSphereDataSource shardingSphereDataSource;
+    /**
+     * 这里是逻辑schema的名字,不要动
+     */
+    private final static String schemaName = "logic_db";
+
+    @SneakyThrows(ReflectiveOperationException.class)
+    public static ContextManager getContextManager(final ShardingSphereDataSource dataSource) {
+        Field field = ShardingSphereDataSource.class.getDeclaredField("contextManager");
+        field.setAccessible(true);
+        return (ContextManager) field.get(dataSource);
+    }
+
+    /**
+     * 行表达式刷新数据节点
+     *
+     * @param logicTableName
+     * @param actualDataNodes
+     */
+    public void generateActualDataNodes(String logicTableName, String actualDataNodes) {
+        // generate actualDataNodes
+        this.updateShardRuleActualDataNodes(shardingSphereDataSource, schemaName, logicTableName, actualDataNodes);
+    }
+
+    /**
+     * List列表刷新数据节点
+     *
+     * @param logicTableName  逻辑表名
+     * @param actualDataNodes 实际表名 数据源名.table名
+     */
+    public void generateActualDataNodes(String logicTableName, List<String> actualDataNodes) {
+        // generate actualDataNodes
+        this.updateShardRuleActualDataNodes(shardingSphereDataSource, schemaName, logicTableName, actualDataNodes.stream().collect(Collectors.joining(",")));
+    }
+
+    /**
+     * 刷新数据节点
+     *
+     * @param dataSource      sharding数据源
+     * @param schemaName      逻辑数据库名
+     * @param logicTableName  逻辑表名
+     * @param actualDataNodes 数据节点
+     */
+    public void updateShardRuleActualDataNodes(ShardingSphereDataSource dataSource, String schemaName, String logicTableName, String actualDataNodes) {
+        // 根据inline 表达式转换DataNode节点
+        List<String> newStrDataNodes = new InlineExpressionParser(actualDataNodes).splitAndEvaluate();
+        //sharding数据源
+        ContextManager contextManager = getContextManager(dataSource);
+        //所有的拆分表
+        Collection<ShardingSphereRule> tableRules = contextManager.getMetaDataContexts()
+                .getMetaData()
+                .getDatabase(schemaName)
+                .getRuleMetaData()
+                .getRules();
+        try {
+            for (ShardingSphereRule shardingSphereRule : tableRules) {
+                if (shardingSphereRule instanceof ShardingRule) {
+                    ShardingRule rule = (ShardingRule) shardingSphereRule;
+                    TableRule tableRule = rule.getTableRule(logicTableName);
+                    // 动态刷新actualDataNodesField
+                    Field actualDataNodesField = TableRule.class.getDeclaredField("actualDataNodes");
+                    Field modifiersField = Field.class.getDeclaredField("modifiers");
+                    modifiersField.setAccessible(true);
+                    // 设置修饰符:private
+                    modifiersField.setInt(actualDataNodesField, actualDataNodesField.getModifiers() & ~Modifier.FINAL);
+                    //  新节点 循环动态拼接所有节点表名
+                    List<DataNode> newDataNodes = newStrDataNodes.stream().map(DataNode::new).collect(Collectors.toList());
+                    actualDataNodesField.setAccessible(true);
+                    // 数据更新回去
+                    actualDataNodesField.set(tableRule, newDataNodes);
+                    Set<String> actualTables = Sets.newHashSet();
+                    // dataNodeIntegerMap
+                    Map<DataNode, Integer> dataNodeIntegerMap = Maps.newHashMap();
+                    newDataNodes.forEach(LambadaTools.forEachWithIndex(dataNodeIntegerMap::put));
+
+                    Map<String, List<DataNode>> dataSourceNodes = newDataNodes.stream().collect(Collectors.groupingBy(DataNode::getDataSourceName));
+
+                    // 动态刷新:actualTables
+                    Field actualTablesField = TableRule.class.getDeclaredField("actualTables");
+                    actualTablesField.setAccessible(true);
+                    actualTablesField.set(tableRule, actualTables);
+
+                    // 动态刷新:dataNodeIndexMap
+                    Field dataNodeIndexMapField = TableRule.class.getDeclaredField("dataNodeIndexMap");
+                    dataNodeIndexMapField.setAccessible(true);
+                    dataNodeIndexMapField.set(tableRule, dataNodeIntegerMap);
+
+                    // 动态刷新:datasourceToTablesMap
+                    Map<String, Collection<String>> datasourceToTablesMap = Maps.newHashMap();
+                    // 不同数据源,表不一样
+                    dataSourceNodes.forEach((ds, node) -> {
+                        datasourceToTablesMap.put(ds, node.stream().map(DataNode::getTableName).collect(Collectors.toSet()));
+                    });
+
+                    Field datasourceToTablesMapField = TableRule.class.getDeclaredField("dataSourceToTablesMap");
+                    datasourceToTablesMapField.setAccessible(true);
+                    datasourceToTablesMapField.set(tableRule, datasourceToTablesMap);
+                }
+            }
+        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+            log.error("刷新节点报错了", e);
+        }
+    }
+}

+ 27 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/config/LambadaTools.java

@@ -0,0 +1,27 @@
+package com.jjt.doc.config;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class LambadaTools {
+    /**
+     * 利用BiConsumer实现foreach循环支持index
+     *
+     * @param biConsumer
+     * @param <T>
+     * @return
+     */
+    public static <T> Consumer<T> forEachWithIndex(BiConsumer<T, Integer> biConsumer) {
+        /*这里说明一下,我们每次传入forEach都是一个重新实例化的Consumer对象,在lambada表达式中我们无法对int进行++操作,
+        我们模拟AtomicInteger对象,写个getAndIncrement方法,不能直接使用AtomicInteger哦*/
+        class IncrementInt {
+            int i = 0;
+
+            public int getAndIncrement() {
+                return i++;
+            }
+        }
+        IncrementInt incrementInt = new IncrementInt();
+        return t -> biConsumer.accept(t, incrementInt.getAndIncrement());
+    }
+}

+ 52 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/controller/ActualDataNodesController.java

@@ -0,0 +1,52 @@
+package com.jjt.doc.controller;
+
+import com.jjt.common.core.utils.poi.ExcelUtil;
+import com.jjt.common.core.web.controller.BaseController;
+import com.jjt.common.core.web.domain.AjaxResult;
+import com.jjt.common.core.web.page.TableDataInfo;
+import com.jjt.common.log.annotation.Log;
+import com.jjt.common.log.enums.BusinessType;
+import com.jjt.common.security.annotation.RequiresPermissions;
+import com.jjt.doc.config.InitActualDataNodes;
+import com.jjt.doc.domain.DocInfo;
+import com.jjt.doc.service.IActualDataNodesService;
+import com.jjt.doc.service.IDocInfoService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 文档基本信息Controller
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+@RestController
+@RequestMapping("/nodes")
+public class ActualDataNodesController extends BaseController {
+    @Resource
+    private IDocInfoService docInfoService;
+    @Resource
+    private IActualDataNodesService actualDataNodesService;
+
+    /**
+     * 刷新数据节点
+     */
+    @Log(title = "刷新数据节点", businessType = BusinessType.OTHER)
+    @RequestMapping("/refresh")
+    public void refresh() {
+        actualDataNodesService.refreshActualDataNodes();
+    }
+
+    @Log(title = "创建数据节点", businessType = BusinessType.INSERT)
+    @PostMapping("/create")
+    public void create(@RequestBody List<String> tableNames) {
+        for (String tableName : tableNames) {
+            actualDataNodesService.createActualDataNodes(tableName);
+        }
+        refresh();
+    }
+}

+ 114 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/controller/DocInfoController.java

@@ -0,0 +1,114 @@
+package com.jjt.doc.controller;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+
+import com.jjt.doc.config.InitActualDataNodes;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.jjt.common.log.annotation.Log;
+import com.jjt.common.log.enums.BusinessType;
+import com.jjt.common.security.annotation.RequiresPermissions;
+import com.jjt.doc.domain.DocInfo;
+import com.jjt.doc.service.IDocInfoService;
+import com.jjt.common.core.web.controller.BaseController;
+import com.jjt.common.core.web.domain.AjaxResult;
+import com.jjt.common.core.utils.poi.ExcelUtil;
+import com.jjt.common.core.web.page.TableDataInfo;
+
+/**
+ * 文档基本信息Controller
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+@RestController
+@RequestMapping("/info")
+public class DocInfoController extends BaseController {
+    @Resource
+    private IDocInfoService docInfoService;
+    @Resource
+    private InitActualDataNodes initActualDataNodesAO;
+
+    public void generateActualDataNodesTest() {
+        // 行表达式 至于行表达式看不懂,自己找资料 或者执行testInline 看下有哪些节点
+        String inlineStr = "ds0.doc_info_$->{2022..2023}";
+        // logicTableName 逻辑表名 actualDataNodes 行表达式
+//        initActualDataNodesAO.generateActualDataNodes("doc_info", inlineStr);
+        // 行表达式List 和上面的结果是一样的做了一层转换而已 这样写更舒服一点
+        List<String> inlineList = Arrays.asList(inlineStr);
+        initActualDataNodesAO.generateActualDataNodes("doc_info", inlineList);
+
+    }
+
+    /**
+     * 查询文档基本信息列表
+     */
+    @RequiresPermissions("doc:info:list")
+    @GetMapping("/list")
+    public TableDataInfo list(DocInfo docInfo) {
+        startPage();
+        List<DocInfo> list = docInfoService.selectDocInfoList(docInfo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出文档基本信息列表
+     */
+    @RequiresPermissions("doc:info:export")
+    @Log(title = "文档基本信息", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DocInfo docInfo) {
+        List<DocInfo> list = docInfoService.selectDocInfoList(docInfo);
+        ExcelUtil<DocInfo> util = new ExcelUtil<DocInfo>(DocInfo.class);
+        util.exportExcel(response, list, "文档基本信息数据");
+    }
+
+    /**
+     * 获取文档基本信息详细信息
+     */
+    @RequiresPermissions("doc:info:query")
+    @GetMapping(value = "/{docId}")
+    public AjaxResult getInfo(@PathVariable("docId") Long docId) {
+        generateActualDataNodesTest();
+        return success(docInfoService.selectDocInfoByDocId(docId));
+    }
+
+    /**
+     * 新增文档基本信息
+     */
+    @RequiresPermissions("doc:info:add")
+    @Log(title = "文档基本信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DocInfo docInfo) {
+        return toAjax(docInfoService.insertDocInfo(docInfo));
+    }
+
+    /**
+     * 修改文档基本信息
+     */
+    @RequiresPermissions("doc:info:edit")
+    @Log(title = "文档基本信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DocInfo docInfo) {
+        return toAjax(docInfoService.updateDocInfo(docInfo));
+    }
+
+    /**
+     * 删除文档基本信息
+     */
+    @RequiresPermissions("doc:info:remove")
+    @Log(title = "文档基本信息", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{docIds}")
+    public AjaxResult remove(@PathVariable Long[] docIds) {
+        return toAjax(docInfoService.deleteDocInfoByDocIds(docIds));
+    }
+}

+ 195 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/domain/DocInfo.java

@@ -0,0 +1,195 @@
+package com.jjt.doc.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.jjt.common.core.annotation.Excel;
+import com.jjt.common.core.web.domain.BaseEntity;
+
+/**
+ * 文档基本信息对象 doc_info
+ * 
+ * @author wukai
+ * @date 2023-03-20
+ */
+public class DocInfo extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 文档ID */
+    private Long docId;
+
+    /** 文档名称 */
+    @Excel(name = "文档名称")
+    private String docName;
+
+    /** 文档类型;doc;docx;xls;xlsx;pdf;mp3;mp4; */
+    @Excel(name = "文档类型;doc;docx;xls;xlsx;pdf;mp3;mp4;")
+    private String docType;
+
+    /** 文档大小 */
+    @Excel(name = "文档大小")
+    private Long docSize;
+
+    /** 文档分类 */
+    @Excel(name = "文档分类")
+    private Long classifyId;
+
+    /** 文档描述 */
+    @Excel(name = "文档描述")
+    private String docDesc;
+
+    /** 文档存储路径 */
+    @Excel(name = "文档存储路径")
+    private String docPath;
+
+    /** 允许编辑;1.允许 非1.不允许 */
+    @Excel(name = "允许编辑;1.允许 非1.不允许")
+    private String allowEdit;
+
+    /** 文档归属类型;1.公共文档 2.部门文档 3.私有文档 */
+    @Excel(name = "文档归属类型;1.公共文档 2.部门文档 3.私有文档")
+    private String docOf;
+
+    /** 文档归属;公共文档存储个人ID,部门文档存储部门ID,个人文档存储用户ID */
+    @Excel(name = "文档归属;公共文档存储个人ID,部门文档存储部门ID,个人文档存储用户ID")
+    private Long owner;
+
+    /** 文档创建年份;文档创建年份,分表用 */
+    @Excel(name = "文档创建年份;文档创建年份,分表用")
+    private Long createYear;
+
+    /** 逻辑删除标志;1/非1 */
+    private String isDel;
+
+    public void setDocId(Long docId) 
+    {
+        this.docId = docId;
+    }
+
+    public Long getDocId() 
+    {
+        return docId;
+    }
+    public void setDocName(String docName) 
+    {
+        this.docName = docName;
+    }
+
+    public String getDocName() 
+    {
+        return docName;
+    }
+    public void setDocType(String docType) 
+    {
+        this.docType = docType;
+    }
+
+    public String getDocType() 
+    {
+        return docType;
+    }
+    public void setDocSize(Long docSize) 
+    {
+        this.docSize = docSize;
+    }
+
+    public Long getDocSize() 
+    {
+        return docSize;
+    }
+    public void setClassifyId(Long classifyId) 
+    {
+        this.classifyId = classifyId;
+    }
+
+    public Long getClassifyId() 
+    {
+        return classifyId;
+    }
+    public void setDocDesc(String docDesc) 
+    {
+        this.docDesc = docDesc;
+    }
+
+    public String getDocDesc() 
+    {
+        return docDesc;
+    }
+    public void setDocPath(String docPath) 
+    {
+        this.docPath = docPath;
+    }
+
+    public String getDocPath() 
+    {
+        return docPath;
+    }
+    public void setAllowEdit(String allowEdit) 
+    {
+        this.allowEdit = allowEdit;
+    }
+
+    public String getAllowEdit() 
+    {
+        return allowEdit;
+    }
+    public void setDocOf(String docOf) 
+    {
+        this.docOf = docOf;
+    }
+
+    public String getDocOf() 
+    {
+        return docOf;
+    }
+    public void setOwner(Long owner) 
+    {
+        this.owner = owner;
+    }
+
+    public Long getOwner() 
+    {
+        return owner;
+    }
+    public void setCreateYear(Long createYear) 
+    {
+        this.createYear = createYear;
+    }
+
+    public Long getCreateYear() 
+    {
+        return createYear;
+    }
+    public void setIsDel(String isDel) 
+    {
+        this.isDel = isDel;
+    }
+
+    public String getIsDel() 
+    {
+        return isDel;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("docId", getDocId())
+            .append("docName", getDocName())
+            .append("docType", getDocType())
+            .append("docSize", getDocSize())
+            .append("classifyId", getClassifyId())
+            .append("docDesc", getDocDesc())
+            .append("docPath", getDocPath())
+            .append("allowEdit", getAllowEdit())
+            .append("docOf", getDocOf())
+            .append("owner", getOwner())
+            .append("createYear", getCreateYear())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .append("isDel", getIsDel())
+            .toString();
+    }
+}

+ 23 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/mapper/ActualDataNodesMapper.java

@@ -0,0 +1,23 @@
+package com.jjt.doc.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jjt.doc.domain.DocInfo;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * 文档基本信息Mapper接口
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+public interface ActualDataNodesMapper {
+    @Update("CREATE TABLE IF NOT EXISTS ${name} LIKE doc_info")
+    void createDataNode(@Param("name") String name);
+
+    @Select("SHOW TABLES LIKE 'doc_info_%'")
+    List<String> selectAllDataNodes();
+}

+ 72 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/mapper/DocInfoMapper.java

@@ -0,0 +1,72 @@
+package com.jjt.doc.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jjt.common.core.web.domain.BaseEntity;
+import com.jjt.doc.domain.DocInfo;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 文档基本信息Mapper接口
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+public interface DocInfoMapper extends BaseMapper<DocInfo> {
+    /**
+     * 查询文档基本信息
+     *
+     * @param docId 文档基本信息主键
+     * @return 文档基本信息
+     */
+    public DocInfo selectDocInfoByDocId(Long docId);
+
+    /**
+     * 查询文档基本信息列表
+     *
+     * @param docInfo 文档基本信息
+     * @return 文档基本信息集合
+     */
+    public List<DocInfo> selectDocInfoList(DocInfo docInfo);
+
+    /**
+     * 新增文档基本信息
+     *
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    public int insertDocInfo(DocInfo docInfo);
+
+    /**
+     * 修改文档基本信息
+     *
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    public int updateDocInfo(DocInfo docInfo);
+
+    /**
+     * 删除文档基本信息
+     *
+     * @param docId 文档基本信息主键
+     * @return 结果
+     */
+    public int deleteDocInfoByDocId(Long docId);
+
+    /**
+     * 批量删除文档基本信息
+     *
+     * @param docIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDocInfoByDocIds(Long[] docIds);
+
+    @Update("CREATE TABLE IF NOT EXISTS ${name} LIKE doc_info")
+    void createTable(@Param("name") String name);
+
+    @Select("SHOW TABLES LIKE 'doc_info%'")
+    List<String> showTables();
+}

+ 27 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/IActualDataNodesService.java

@@ -0,0 +1,27 @@
+package com.jjt.doc.service;
+
+import com.jjt.doc.domain.DocInfo;
+
+import java.util.List;
+
+/**
+ * 文档基本信息Service接口
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+public interface IActualDataNodesService {
+
+    /**
+     * 添加数据节点
+     *
+     * @param tableName 数据节点名称 数据源.物理表名
+     * @return
+     */
+    void createActualDataNodes(String tableName);
+
+    /**
+     * 刷新数据节点
+     */
+    void refreshActualDataNodes();
+}

+ 61 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/IDocInfoService.java

@@ -0,0 +1,61 @@
+package com.jjt.doc.service;
+
+import java.util.List;
+import com.jjt.doc.domain.DocInfo;
+
+/**
+ * 文档基本信息Service接口
+ * 
+ * @author wukai
+ * @date 2023-03-20
+ */
+public interface IDocInfoService 
+{
+    /**
+     * 查询文档基本信息
+     * 
+     * @param docId 文档基本信息主键
+     * @return 文档基本信息
+     */
+    public DocInfo selectDocInfoByDocId(Long docId);
+
+    /**
+     * 查询文档基本信息列表
+     * 
+     * @param docInfo 文档基本信息
+     * @return 文档基本信息集合
+     */
+    public List<DocInfo> selectDocInfoList(DocInfo docInfo);
+
+    /**
+     * 新增文档基本信息
+     * 
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    public int insertDocInfo(DocInfo docInfo);
+
+    /**
+     * 修改文档基本信息
+     * 
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    public int updateDocInfo(DocInfo docInfo);
+
+    /**
+     * 批量删除文档基本信息
+     * 
+     * @param docIds 需要删除的文档基本信息主键集合
+     * @return 结果
+     */
+    public int deleteDocInfoByDocIds(Long[] docIds);
+
+    /**
+     * 删除文档基本信息信息
+     * 
+     * @param docId 文档基本信息主键
+     * @return 结果
+     */
+    public int deleteDocInfoByDocId(Long docId);
+}

+ 63 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/impl/ActualDataNodesServiceImpl.java

@@ -0,0 +1,63 @@
+package com.jjt.doc.service.impl;
+
+import com.jjt.common.core.utils.DateUtils;
+import com.jjt.doc.config.InitActualDataNodes;
+import com.jjt.doc.domain.DocInfo;
+import com.jjt.doc.mapper.ActualDataNodesMapper;
+import com.jjt.doc.mapper.DocInfoMapper;
+import com.jjt.doc.service.IActualDataNodesService;
+import com.jjt.doc.service.IDocInfoService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 文档基本信息Service业务层处理
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+@Service
+public class ActualDataNodesServiceImpl implements IActualDataNodesService {
+    @Resource
+    private ActualDataNodesMapper nodesMapper;
+    @Resource
+    private InitActualDataNodes initActualDataNodes;
+
+    /**
+     * 查询所有数据节点
+     *
+     * @return 数据节点列表
+     */
+    private List<String> selectAllActualDataNodes() {
+        List<String> tableNames = nodesMapper.selectAllDataNodes();
+        List<String> inlineList = new ArrayList<>(tableNames.size());
+        for (String s : tableNames) {
+            String ss = "ds0." + s;
+            inlineList.add(ss);
+        }
+        return inlineList;
+    }
+
+    /**
+     * 添加数据节点
+     *
+     * @param tableName 数据节点名称 数据源.物理表名
+     */
+    @Override
+    public void createActualDataNodes(String tableName) {
+        nodesMapper.createDataNode(tableName);
+    }
+
+    /**
+     * 刷新数据节点
+     */
+    @Override
+    public void refreshActualDataNodes() {
+        String logicTableName = "doc_info";
+        List<String> actualDataNodes = selectAllActualDataNodes();
+        initActualDataNodes.generateActualDataNodes(logicTableName, actualDataNodes);
+    }
+}

+ 92 - 0
lzga-modules/lzga-doc/src/main/java/com/jjt/doc/service/impl/DocInfoServiceImpl.java

@@ -0,0 +1,92 @@
+package com.jjt.doc.service.impl;
+
+import java.util.List;
+
+import com.jjt.common.core.utils.DateUtils;
+import org.springframework.stereotype.Service;
+import com.jjt.doc.mapper.DocInfoMapper;
+import com.jjt.doc.domain.DocInfo;
+
+import javax.annotation.Resource;
+
+import com.jjt.doc.service.IDocInfoService;
+
+/**
+ * 文档基本信息Service业务层处理
+ *
+ * @author wukai
+ * @date 2023-03-20
+ */
+@Service
+public class DocInfoServiceImpl implements IDocInfoService {
+    @Resource
+    private DocInfoMapper docInfoMapper;
+
+    /**
+     * 查询文档基本信息
+     *
+     * @param docId 文档基本信息主键
+     * @return 文档基本信息
+     */
+    @Override
+    public DocInfo selectDocInfoByDocId(Long docId) {
+        return docInfoMapper.selectDocInfoByDocId(docId);
+    }
+
+    /**
+     * 查询文档基本信息列表
+     *
+     * @param docInfo 文档基本信息
+     * @return 文档基本信息
+     */
+    @Override
+    public List<DocInfo> selectDocInfoList(DocInfo docInfo) {
+        return docInfoMapper.selectDocInfoList(docInfo);
+    }
+
+    /**
+     * 新增文档基本信息
+     *
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    @Override
+    public int insertDocInfo(DocInfo docInfo) {
+        docInfo.setCreateTime(DateUtils.getNowDate());
+        return docInfoMapper.insertDocInfo(docInfo);
+    }
+
+    /**
+     * 修改文档基本信息
+     *
+     * @param docInfo 文档基本信息
+     * @return 结果
+     */
+    @Override
+    public int updateDocInfo(DocInfo docInfo) {
+        docInfo.setUpdateTime(DateUtils.getNowDate());
+        return docInfoMapper.updateDocInfo(docInfo);
+    }
+
+    /**
+     * 批量删除文档基本信息
+     *
+     * @param docIds 需要删除的文档基本信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteDocInfoByDocIds(Long[] docIds) {
+        return docInfoMapper.deleteDocInfoByDocIds(docIds);
+    }
+
+    /**
+     * 删除文档基本信息信息
+     *
+     * @param docId 文档基本信息主键
+     * @return 结果
+     */
+    @Override
+    public int deleteDocInfoByDocId(Long docId) {
+        return docInfoMapper.deleteDocInfoByDocId(docId);
+    }
+}

+ 13 - 16
lzga-modules/lzga-doc/src/test/java/com/jjt/t.yml → lzga-modules/lzga-doc/src/main/resources/lzga-doc-dev.yml

@@ -7,43 +7,40 @@ spring:
   # 分库分表配置
   shardingsphere:
     datasource:
-      names: ds0
       ds0:
         driver-class-name: com.mysql.cj.jdbc.Driver
         type: com.alibaba.druid.pool.DruidDataSource
         url: jdbc:mysql://192.168.188.88:3306/jjt-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
         username: root
         password: 123456
+      names: ds0
     props:
       sql-show: true
     rules:
       sharding:
-        sharding-algorithms:
+        shardingAlgorithms:
           table-inline:
             props:
-              algorithm-expression: sys_oper_log_$->{request_method},doc_info_$->{create_year}
+              algorithm-expression: doc_info_$->{create_year}
             type: INLINE
         tables:
-          sys_oper_log:
-            actual-data-nodes: ds0.sys_oper_log_GET,ds0.sys_oper_log_POST,ds0.sys_oper_log_PUT,ds0.sys_oper_log_DELETE
-            table-strategy:
-              standard:
-                sharding-algorithm-name: table-inline
-                sharding-column: request_method
           doc_info:
-            actual-data-nodes: ds0.doc_info_$->{2023..2099}
-            table-strategy:
+            actualDataNodes: ds0.doc_info
+            tableStrategy:
               standard:
-                sharding-algorithm-name: table-inline
-                sharding-column: create_year
-            key-generator:
+                shardingAlgorithmName: table-inline
+                shardingColumn: create_year
+            keyGenerateStrategy:
               column: doc_id
-              type: SNOWFLAKE
+              keyGeneratorName: id-key
+        keyGenerators:
+          id-key:
+            type: SNOWFLAKE
 
 # mybatis-plus配置
 mybatis-plus:
   # 搜索指定包别名
-  typeAliasesPackage: com.jjt.*
+  typeAliasesPackage: com.jjt.doc
   # 配置mapper的扫描,找到所有的mapper.xml映射文件
   mapperLocations: classpath:mapper/**/*.xml
 

+ 53 - 0
lzga-modules/lzga-doc/src/main/resources/lzga-doc-local.yml

@@ -0,0 +1,53 @@
+# spring配置
+spring:
+  redis:
+    host: 192.168.188.88
+    port: 6379
+    password: redis123
+  # 分库分表配置
+  shardingsphere:
+    datasource:
+      ds0:
+        driver-class-name: com.mysql.cj.jdbc.Driver
+        type: com.alibaba.druid.pool.DruidDataSource
+        url: jdbc:mysql://192.168.188.88:3306/jjt-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: 123456
+      names: ds0
+    props:
+      sql-show: true
+    rules:
+      sharding:
+        shardingAlgorithms:
+          table-inline:
+            props:
+              strategy: standard
+              algorithmClassName: com.jjt.doc.config.DateShardingAlgorithm
+#              algorithm-expression: doc_info_{'2023'}
+            type: CLASS_BASED
+        tables:
+          doc_info:
+            actualDataNodes: ds0.doc_info$->{2023}
+            tableStrategy:
+              standard:
+                shardingAlgorithmName: table-inline
+                shardingColumn: create_year
+            keyGenerateStrategy:
+              column: doc_id
+              keyGeneratorName: id-key
+        keyGenerators:
+          id-key:
+            type: SNOWFLAKE
+
+# mybatis-plus配置
+mybatis-plus:
+  # 搜索指定包别名
+  typeAliasesPackage: com.jjt.doc
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath:mapper/**/*.xml
+
+# swagger配置
+swagger:
+  title: 系统模块接口文档
+  license: Powered By jjt
+  licenseUrl:

+ 130 - 0
lzga-modules/lzga-doc/src/main/resources/mapper/doc/DocInfoMapper.xml

@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.jjt.doc.mapper.DocInfoMapper">
+    
+    <resultMap type="DocInfo" id="DocInfoResult">
+        <result property="docId"    column="DOC_ID"    />
+        <result property="docName"    column="DOC_NAME"    />
+        <result property="docType"    column="DOC_TYPE"    />
+        <result property="docSize"    column="DOC_SIZE"    />
+        <result property="classifyId"    column="CLASSIFY_ID"    />
+        <result property="docDesc"    column="DOC_DESC"    />
+        <result property="docPath"    column="DOC_PATH"    />
+        <result property="allowEdit"    column="ALLOW_EDIT"    />
+        <result property="docOf"    column="DOC_OF"    />
+        <result property="owner"    column="OWNER"    />
+        <result property="createYear"    column="CREATE_YEAR"    />
+        <result property="createBy"    column="CREATE_BY"    />
+        <result property="createTime"    column="CREATE_TIME"    />
+        <result property="updateBy"    column="UPDATE_BY"    />
+        <result property="updateTime"    column="UPDATE_TIME"    />
+        <result property="remark"    column="REMARK"    />
+        <result property="isDel"    column="IS_DEL"    />
+    </resultMap>
+
+    <sql id="selectDocInfoVo">
+        select DOC_ID, DOC_NAME, DOC_TYPE, DOC_SIZE, CLASSIFY_ID, DOC_DESC, DOC_PATH, ALLOW_EDIT, DOC_OF, OWNER, CREATE_YEAR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK, IS_DEL from doc_info
+    </sql>
+
+    <select id="selectDocInfoList" parameterType="DocInfo" resultMap="DocInfoResult">
+        <include refid="selectDocInfoVo"/>
+        <where>  
+            <if test="docName != null  and docName != ''"> and DOC_NAME like concat('%', #{docName}, '%')</if>
+            <if test="docType != null  and docType != ''"> and DOC_TYPE = #{docType}</if>
+            <if test="docSize != null "> and DOC_SIZE = #{docSize}</if>
+            <if test="classifyId != null "> and CLASSIFY_ID = #{classifyId}</if>
+            <if test="docDesc != null  and docDesc != ''"> and DOC_DESC = #{docDesc}</if>
+            <if test="docPath != null  and docPath != ''"> and DOC_PATH = #{docPath}</if>
+            <if test="allowEdit != null  and allowEdit != ''"> and ALLOW_EDIT = #{allowEdit}</if>
+            <if test="docOf != null  and docOf != ''"> and DOC_OF = #{docOf}</if>
+            <if test="owner != null "> and OWNER = #{owner}</if>
+            <if test="createYear != null "> and CREATE_YEAR = #{createYear}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="remark != null  and remark != ''"> and REMARK = #{remark}</if>
+        </where>
+    </select>
+    
+    <select id="selectDocInfoByDocId" parameterType="Long" resultMap="DocInfoResult">
+        <include refid="selectDocInfoVo"/>
+        where DOC_ID = #{docId}
+    </select>
+        
+    <insert id="insertDocInfo" parameterType="DocInfo" useGeneratedKeys="true" keyProperty="docId">
+        insert into doc_info
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="docName != null">DOC_NAME,</if>
+            <if test="docType != null">DOC_TYPE,</if>
+            <if test="docSize != null">DOC_SIZE,</if>
+            <if test="classifyId != null">CLASSIFY_ID,</if>
+            <if test="docDesc != null">DOC_DESC,</if>
+            <if test="docPath != null">DOC_PATH,</if>
+            <if test="allowEdit != null">ALLOW_EDIT,</if>
+            <if test="docOf != null">DOC_OF,</if>
+            <if test="owner != null">OWNER,</if>
+            <if test="createYear != null">CREATE_YEAR,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="remark != null">REMARK,</if>
+            <if test="isDel != null">IS_DEL,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="docName != null">#{docName},</if>
+            <if test="docType != null">#{docType},</if>
+            <if test="docSize != null">#{docSize},</if>
+            <if test="classifyId != null">#{classifyId},</if>
+            <if test="docDesc != null">#{docDesc},</if>
+            <if test="docPath != null">#{docPath},</if>
+            <if test="allowEdit != null">#{allowEdit},</if>
+            <if test="docOf != null">#{docOf},</if>
+            <if test="owner != null">#{owner},</if>
+            <if test="createYear != null">#{createYear},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="isDel != null">#{isDel},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDocInfo" parameterType="DocInfo">
+        update doc_info
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="docName != null">DOC_NAME = #{docName},</if>
+            <if test="docType != null">DOC_TYPE = #{docType},</if>
+            <if test="docSize != null">DOC_SIZE = #{docSize},</if>
+            <if test="classifyId != null">CLASSIFY_ID = #{classifyId},</if>
+            <if test="docDesc != null">DOC_DESC = #{docDesc},</if>
+            <if test="docPath != null">DOC_PATH = #{docPath},</if>
+            <if test="allowEdit != null">ALLOW_EDIT = #{allowEdit},</if>
+            <if test="docOf != null">DOC_OF = #{docOf},</if>
+            <if test="owner != null">OWNER = #{owner},</if>
+            <if test="createYear != null">CREATE_YEAR = #{createYear},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="remark != null">REMARK = #{remark},</if>
+            <if test="isDel != null">IS_DEL = #{isDel},</if>
+        </trim>
+        where DOC_ID = #{docId}
+    </update>
+
+    <delete id="deleteDocInfoByDocId" parameterType="Long">
+        delete from doc_info where DOC_ID = #{docId}
+    </delete>
+
+    <delete id="deleteDocInfoByDocIds" parameterType="String">
+        delete from doc_info where DOC_ID in 
+        <foreach item="docId" collection="array" open="(" separator="," close=")">
+            #{docId}
+        </foreach>
+    </delete>
+</mapper>

+ 60 - 42
lzga-modules/lzga-doc/src/main/resources/mapper/doc/SysOperLogMapper.xml

@@ -1,58 +1,74 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jjt.doc.mapper.SysOperLogMapper">
-    
+
     <resultMap type="SysOperLog" id="SysOperLogResult">
-        <result property="operId"    column="oper_id"    />
-        <result property="title"    column="title"    />
-        <result property="businessType"    column="business_type"    />
-        <result property="method"    column="method"    />
-        <result property="requestMethod"    column="request_method"    />
-        <result property="operatorType"    column="operator_type"    />
-        <result property="operName"    column="oper_name"    />
-        <result property="deptName"    column="dept_name"    />
-        <result property="operUrl"    column="oper_url"    />
-        <result property="operIp"    column="oper_ip"    />
-        <result property="operLocation"    column="oper_location"    />
-        <result property="operParam"    column="oper_param"    />
-        <result property="jsonResult"    column="json_result"    />
-        <result property="status"    column="status"    />
-        <result property="errorMsg"    column="error_msg"    />
-        <result property="operTime"    column="oper_time"    />
+        <result property="operId" column="oper_id"/>
+        <result property="title" column="title"/>
+        <result property="businessType" column="business_type"/>
+        <result property="method" column="method"/>
+        <result property="requestMethod" column="request_method"/>
+        <result property="operatorType" column="operator_type"/>
+        <result property="operName" column="oper_name"/>
+        <result property="deptName" column="dept_name"/>
+        <result property="operUrl" column="oper_url"/>
+        <result property="operIp" column="oper_ip"/>
+        <result property="operLocation" column="oper_location"/>
+        <result property="operParam" column="oper_param"/>
+        <result property="jsonResult" column="json_result"/>
+        <result property="status" column="status"/>
+        <result property="errorMsg" column="error_msg"/>
+        <result property="operTime" column="oper_time"/>
     </resultMap>
 
     <sql id="selectSysOperLogVo">
-        select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time from sys_oper_log
+        select oper_id,
+               title,
+               business_type,
+               method,
+               request_method,
+               operator_type,
+               oper_name,
+               dept_name,
+               oper_url,
+               oper_ip,
+               oper_location,
+               oper_param,
+               json_result,
+               status,
+               error_msg,
+               oper_time
+        from sys_oper_log
     </sql>
 
     <select id="selectSysOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
         <include refid="selectSysOperLogVo"/>
-        <where>  
-            <if test="title != null  and title != ''"> and title = #{title}</if>
-            <if test="businessType != null "> and business_type = #{businessType}</if>
-            <if test="method != null  and method != ''"> and method = #{method}</if>
-            <if test="requestMethod != null  and requestMethod != ''"> and request_method = #{requestMethod}</if>
-            <if test="operatorType != null "> and operator_type = #{operatorType}</if>
-            <if test="operName != null  and operName != ''"> and oper_name like concat('%', #{operName}, '%')</if>
-            <if test="deptName != null  and deptName != ''"> and dept_name like concat('%', #{deptName}, '%')</if>
-            <if test="operUrl != null  and operUrl != ''"> and oper_url = #{operUrl}</if>
-            <if test="operIp != null  and operIp != ''"> and oper_ip = #{operIp}</if>
-            <if test="operLocation != null  and operLocation != ''"> and oper_location = #{operLocation}</if>
-            <if test="operParam != null  and operParam != ''"> and oper_param = #{operParam}</if>
-            <if test="jsonResult != null  and jsonResult != ''"> and json_result = #{jsonResult}</if>
-            <if test="status != null "> and status = #{status}</if>
-            <if test="errorMsg != null  and errorMsg != ''"> and error_msg = #{errorMsg}</if>
-            <if test="operTime != null "> and oper_time = #{operTime}</if>
+        <where>
+            <if test="title != null  and title != ''">and title = #{title}</if>
+            <if test="businessType != null ">and business_type = #{businessType}</if>
+            <if test="method != null  and method != ''">and method = #{method}</if>
+            <if test="requestMethod != null  and requestMethod != ''">and request_method = #{requestMethod}</if>
+            <if test="operatorType != null ">and operator_type = #{operatorType}</if>
+            <if test="operName != null  and operName != ''">and oper_name like concat('%', #{operName}, '%')</if>
+            <if test="deptName != null  and deptName != ''">and dept_name like concat('%', #{deptName}, '%')</if>
+            <if test="operUrl != null  and operUrl != ''">and oper_url = #{operUrl}</if>
+            <if test="operIp != null  and operIp != ''">and oper_ip = #{operIp}</if>
+            <if test="operLocation != null  and operLocation != ''">and oper_location = #{operLocation}</if>
+            <if test="operParam != null  and operParam != ''">and oper_param = #{operParam}</if>
+            <if test="jsonResult != null  and jsonResult != ''">and json_result = #{jsonResult}</if>
+            <if test="status != null ">and status = #{status}</if>
+            <if test="errorMsg != null  and errorMsg != ''">and error_msg = #{errorMsg}</if>
+            <if test="operTime != null ">and oper_time = #{operTime}</if>
         </where>
     </select>
-    
+
     <select id="selectSysOperLogByOperId" parameterType="Long" resultMap="SysOperLogResult">
         <include refid="selectSysOperLogVo"/>
         where oper_id = #{operId}
     </select>
-        
+
     <insert id="insertSysOperLog" parameterType="SysOperLog" useGeneratedKeys="true" keyProperty="operId">
         insert into sys_oper_log
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -71,7 +87,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="status != null">status,</if>
             <if test="errorMsg != null">error_msg,</if>
             <if test="operTime != null">oper_time,</if>
-         </trim>
+        </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="title != null">#{title},</if>
             <if test="businessType != null">#{businessType},</if>
@@ -88,7 +104,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="status != null">#{status},</if>
             <if test="errorMsg != null">#{errorMsg},</if>
             <if test="operTime != null">#{operTime},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateSysOperLog" parameterType="SysOperLog">
@@ -114,11 +130,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </update>
 
     <delete id="deleteSysOperLogByOperId" parameterType="Long">
-        delete from sys_oper_log where oper_id = #{operId}
+        delete
+        from sys_oper_log
+        where oper_id = #{operId}
     </delete>
 
     <delete id="deleteSysOperLogByOperIds" parameterType="String">
-        delete from sys_oper_log where oper_id in 
+        delete from sys_oper_log where oper_id in
         <foreach item="operId" collection="array" open="(" separator="," close=")">
             #{operId}
         </foreach>

+ 7 - 12
lzga-modules/lzga-doc/src/test/java/com/jjt/AppTest.java

@@ -7,32 +7,27 @@ import junit.framework.TestSuite;
 /**
  * Unit test for simple App.
  */
-public class AppTest 
-    extends TestCase
-{
+public class AppTest extends TestCase {
     /**
      * Create the test case
      *
      * @param testName name of the test case
      */
-    public AppTest( String testName )
-    {
-        super( testName );
+    public AppTest(String testName) {
+        super(testName);
     }
 
     /**
      * @return the suite of tests being tested
      */
-    public static Test suite()
-    {
-        return new TestSuite( AppTest.class );
+    public static Test suite() {
+        return new TestSuite(AppTest.class);
     }
 
     /**
      * Rigourous Test :-)
      */
-    public void testApp()
-    {
-        assertTrue( true );
+    public void testApp() {
+        assertTrue(true);
     }
 }

+ 44 - 0
lzga-modules/lzga-doc/src/test/java/com/jjt/ShardingSpiDemoApplicationTests3.java

@@ -0,0 +1,44 @@
+package com.jjt;
+
+import com.jjt.doc.config.InitActualDataNodes;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.infra.util.expr.InlineExpressionParser;
+import org.junit.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+
+@SpringBootTest
+@Slf4j
+public class ShardingSpiDemoApplicationTests3 {
+
+    @Resource
+    private InitActualDataNodes initActualDataNodesAO;
+
+    @Test
+    public void generateActualDataNodesTest() {
+        // 行表达式 至于行表达式看不懂,自己找资料 或者执行testInline 看下有哪些节点
+        String inlineStr = "ds_$->{0..1}.student_$->{0..2},ds_1.student_12347,ds_0.student_147258";
+        // logicTableName 逻辑表名 actualDataNodes 行表达式
+        initActualDataNodesAO.generateActualDataNodes("student", inlineStr);
+        // 行表达式List 和上面的结果是一样的做了一层转换而已 这样写更舒服一点
+        List<String> inlineList = Arrays.asList("ds_$->{0..1}.student_$->{0..2}", "ds_1.student_12347", "ds_0.student_147258");
+        initActualDataNodesAO.generateActualDataNodes("student", inlineList);
+
+    }
+
+    @Test
+    public void testInline() {
+        String inlineStr = "ds_$->{0..1}.student_$->{0..2},ds_1.student_12347,ds_0.student_147258";
+        List<String> newStrDataNodes = new InlineExpressionParser(inlineStr).splitAndEvaluate();
+        System.out.println(newStrDataNodes);
+
+        List<String> inlineList = Arrays.asList("ds_$->{0..1}.student_$->{0..2}", "ds_1.student_12347", "ds_0.student_147258");
+        List<String> newStrDataNodes2 = new InlineExpressionParser(String.join(",", inlineList)).splitAndEvaluate();
+        System.out.println(newStrDataNodes2);
+    }
+
+
+}

+ 35 - 0
lzga-modules/lzga-doc/src/test/java/com/jjt/SqlTest.java

@@ -0,0 +1,35 @@
+package com.jjt;
+
+import com.jjt.doc.JJTDocApplication;
+import com.jjt.doc.mapper.DocInfoMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author wukai
+ * @description
+ * @date 2022-06-08 11:20:37
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = JJTDocApplication.class)
+//@ActiveProfiles("dev")
+public class SqlTest {
+    @Resource
+    private DocInfoMapper docInfoMapper;
+
+
+    @Test
+    public void test() {
+        List<String> xx = docInfoMapper.showTables();
+        for (String x : xx) {
+            System.err.println(x);
+        }
+    }
+
+}

+ 13 - 17
lzga-modules/lzga-file/src/main/java/com/jjt/file/controller/SysFileController.java

@@ -1,47 +1,43 @@
 package com.jjt.file.controller;
 
+import com.jjt.common.core.domain.R;
+import com.jjt.common.core.utils.file.FileUtils;
+import com.jjt.file.service.ISysFileService;
+import com.jjt.system.api.domain.SysFile;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.multipart.MultipartFile;
-import com.jjt.common.core.domain.R;
-import com.jjt.common.core.utils.file.FileUtils;
-import com.jjt.file.service.ISysFileService;
-import com.jjt.system.api.domain.SysFile;
+
+import javax.annotation.Resource;
 
 /**
  * 文件请求处理
- * 
+ *
  * @author ruoyi
  */
 @RestController
-public class SysFileController
-{
+public class SysFileController {
     private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
 
-    @Autowired
+    @Resource
     private ISysFileService sysFileService;
 
     /**
      * 文件上传请求
      */
     @PostMapping("upload")
-    public R<SysFile> upload(MultipartFile file)
-    {
-        try
-        {
+    public R<SysFile> upload(MultipartFile file) {
+        try {
             // 上传并返回访问地址
             String url = sysFileService.uploadFile(file);
             SysFile sysFile = new SysFile();
             sysFile.setName(FileUtils.getName(url));
             sysFile.setUrl(url);
             return R.ok(sysFile);
-        }
-        catch (Exception e)
-        {
-            log.error("上传文件失败", e);
+        } catch (Exception e) {
+            log.error("上传文件失败" , e);
             return R.fail(e.getMessage());
         }
     }

+ 2 - 2
lzga-modules/lzga-gen/src/main/resources/vm/java/controller.java.vm

@@ -2,8 +2,8 @@ package ${packageName}.controller;
 
 import java.util.List;
 import java.io.IOException;
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -35,7 +35,7 @@ import com.jjt.common.core.web.page.TableDataInfo;
 @RequestMapping("/${businessName}")
 public class ${ClassName}Controller extends BaseController
 {
-    @Autowired
+    @Resource
     private I${ClassName}Service ${className}Service;
 
     /**

+ 11 - 11
lzga-modules/lzga-gen/src/main/resources/vm/java/serviceImpl.java.vm

@@ -7,7 +7,6 @@ import com.jjt.common.core.utils.DateUtils;
 #break
 #end
 #end
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 #if($table.sub)
 import java.util.ArrayList;
@@ -17,23 +16,24 @@ import ${packageName}.domain.${subClassName};
 #end
 import ${packageName}.mapper.${ClassName}Mapper;
 import ${packageName}.domain.${ClassName};
+import javax.annotation.Resource;
 import ${packageName}.service.I${ClassName}Service;
 
 /**
  * ${functionName}Service业务层处理
- * 
+ *
  * @author ${author}
  * @date ${datetime}
  */
 @Service
-public class ${ClassName}ServiceImpl implements I${ClassName}Service 
+public class ${ClassName}ServiceImpl implements I${ClassName}Service
 {
-    @Autowired
+    @Resource
     private ${ClassName}Mapper ${className}Mapper;
 
     /**
      * 查询${functionName}
-     * 
+     *
      * @param ${pkColumn.javaField} ${functionName}主键
      * @return ${functionName}
      */
@@ -45,7 +45,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 查询${functionName}列表
-     * 
+     *
      * @param ${className} ${functionName}
      * @return ${functionName}
      */
@@ -57,7 +57,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 新增${functionName}
-     * 
+     *
      * @param ${className} ${functionName}
      * @return 结果
      */
@@ -83,7 +83,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 修改${functionName}
-     * 
+     *
      * @param ${className} ${functionName}
      * @return 结果
      */
@@ -107,7 +107,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 批量删除${functionName}
-     * 
+     *
      * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
      * @return 结果
      */
@@ -125,7 +125,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 删除${functionName}信息
-     * 
+     *
      * @param ${pkColumn.javaField} ${functionName}主键
      * @return 结果
      */
@@ -144,7 +144,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 
     /**
      * 新增${subTable.functionName}信息
-     * 
+     *
      * @param ${className} ${functionName}对象
      */
     public void insert${subClassName}(${ClassName} ${className})

+ 59 - 0
lzga-modules/lzga-job/src/main/java/com/jjt/job/task/ActualDataNodesTask.java

@@ -0,0 +1,59 @@
+package com.jjt.job.task;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
+import com.jjt.common.core.constant.SecurityConstants;
+import com.jjt.common.core.utils.StringUtils;
+import com.jjt.system.api.RemoteActualDataNodesService;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 定时任务调度测试
+ *
+ * @author ruoyi
+ */
+@Component("actualDataNodesTask")
+public class ActualDataNodesTask {
+    @Resource
+    private RemoteActualDataNodesService remoteActualDataNodesService;
+
+    /**
+     * 每年的12月26日生成未来10年的表
+     *
+     * @return
+     */
+    public void createActualDataNodes() {
+        int currentYear = LocalDateTime.now().getYear();
+        List<String> tableNames = new ArrayList<>(10);
+
+        for (int i = currentYear + 1; i <= currentYear + 10; i++) {
+            String tableName = "doc_info_" + i;
+            tableNames.add(tableName);
+        }
+        //创建表
+        remoteActualDataNodesService.createActualDataNodes(tableNames, SecurityConstants.INNER);
+    }
+
+    /**
+     * 每年的12月26日生成未来10年的表
+     *
+     * @return
+     */
+    public void refreshActualDataNodes() {
+        remoteActualDataNodesService.refreshActualDataNodes(SecurityConstants.INNER);
+    }
+
+    public static void main(String[] args) {
+        List<String> tableNames = new ArrayList<>();
+        tableNames.add("t");
+        tableNames.add("t1");
+        tableNames.add("t2");
+        System.err.println(JSON.toJSONString(tableNames));
+    }
+}

+ 44 - 0
lzga-ui/src/api/doc/info/index.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询文档基本信息列表
+export function listInfo(query) {
+  return request({
+    url: '/doc/info/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询文档基本信息详细
+export function getInfo(docId) {
+  return request({
+    url: '/doc/info/' + docId,
+    method: 'get'
+  })
+}
+
+// 新增文档基本信息
+export function addInfo(data) {
+  return request({
+    url: '/doc/info',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改文档基本信息
+export function updateInfo(data) {
+  return request({
+    url: '/doc/info',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除文档基本信息
+export function delInfo(docId) {
+  return request({
+    url: '/doc/info/' + docId,
+    method: 'delete'
+  })
+}

+ 1 - 1
lzga-ui/src/components/FileUpload/index.vue

@@ -60,7 +60,7 @@ export default {
     // 文件类型, 例如['png', 'jpg', 'jpeg']
     fileType: {
       type: Array,
-      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
+      default: () => ["doc","docx", "xls","xlsx", "ppt", "txt", "pdf"],
     },
     // 是否显示提示
     isShowTip: {

+ 339 - 0
lzga-ui/src/views/doc/info/index.vue

@@ -0,0 +1,339 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="文档名称" prop="docName">
+        <el-input
+          v-model="queryParams.docName"
+          placeholder="请输入文档名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="文档分类" prop="classifyId">
+        <el-input
+          v-model="queryParams.classifyId"
+          placeholder="请输入文档分类"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="年份" prop="createYear">
+        <el-input
+          v-model="queryParams.createYear"
+          placeholder="请输入文档创建年份;文档创建年份,分表用"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['doc:info:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['doc:info:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['doc:info:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['doc:info:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="infoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="文档ID" align="center" prop="docId" />
+      <el-table-column label="文档名称" align="center" prop="docName" />
+      <el-table-column label="文档类型" align="center" prop="docType" />
+      <el-table-column label="文档大小" align="center" prop="docSize" />
+      <el-table-column label="文档分类" align="center" prop="classifyId" />
+      <el-table-column label="文档描述" align="center" prop="docDesc" />
+      <el-table-column label="文档存储路径" align="center" prop="docPath" />
+      <el-table-column label="允许编辑" align="center" prop="allowEdit" />
+      <el-table-column label="文档归属类型" align="center" prop="docOf" />
+      <el-table-column label="文档归属" align="center" prop="owner" />
+      <el-table-column label="文档年份" align="center" prop="createYear" />
+      <el-table-column label="创建人" align="center" prop="createBy" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="更新人" align="center" prop="updateBy" />
+      <el-table-column label="更新时间" align="center" prop="updateTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['doc:info:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['doc:info:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改文档基本信息对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="文档名称" prop="docName">
+          <el-input v-model="form.docName" placeholder="请输入文档名称" />
+        </el-form-item>
+        <el-form-item label="文档大小" prop="docSize">
+          <el-input v-model="form.docSize" placeholder="请输入文档大小" />
+        </el-form-item>
+        <el-form-item label="文档分类" prop="classifyId">
+          <el-input v-model="form.classifyId" placeholder="请输入文档分类" />
+        </el-form-item>
+        <el-form-item label="文档描述" prop="docDesc">
+          <el-input v-model="form.docDesc" placeholder="请输入文档描述" />
+        </el-form-item>
+        <el-form-item label="文档存储路径" prop="docPath">
+          <file-upload v-model="form.docPath"/>
+        </el-form-item>
+        <el-form-item label="允许编辑" prop="allowEdit">
+          <el-input v-model="form.allowEdit" placeholder="请输入允许编辑;1.允许 非1.不允许" />
+        </el-form-item>
+        <el-form-item label="文档归属类型" prop="docOf">
+          <el-input v-model="form.docOf" placeholder="请输入文档归属类型;1.公共文档 2.部门文档 3.私有文档" />
+        </el-form-item>
+        <el-form-item label="文档归属" prop="owner">
+          <el-input v-model="form.owner" placeholder="请输入文档归属;公共文档存储个人ID,部门文档存储部门ID,个人文档存储用户ID" />
+        </el-form-item>
+        <el-form-item label="文档年份" prop="createYear">
+          <el-input v-model="form.createYear" placeholder="请输入文档创建年份;文档创建年份,分表用" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listInfo, getInfo, delInfo, addInfo, updateInfo } from "@/api/doc/info";
+
+export default {
+  name: "Info",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 文档基本信息表格数据
+      infoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        docName: null,
+        docType: null,
+        docSize: null,
+        classifyId: null,
+        docDesc: null,
+        docPath: null,
+        allowEdit: null,
+        docOf: null,
+        owner: null,
+        createYear: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询文档基本信息列表 */
+    getList() {
+      this.loading = true;
+      listInfo(this.queryParams).then(response => {
+        this.infoList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        docId: null,
+        docName: null,
+        docType: null,
+        docSize: null,
+        classifyId: null,
+        docDesc: null,
+        docPath: null,
+        allowEdit: null,
+        docOf: null,
+        owner: null,
+        createYear: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        remark: null,
+        isDel: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.docId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加文档基本信息";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const docId = row.docId || this.ids
+      getInfo(docId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改文档基本信息";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.docId != null) {
+            updateInfo(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addInfo(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const docIds = row.docId || this.ids;
+      this.$modal.confirm('是否确认删除文档基本信息编号为"' + docIds + '"的数据项?').then(function() {
+        return delInfo(docIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('doc/info/export', {
+        ...this.queryParams
+      }, `info_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>