Bläddra i källkod

新增 系统监控
修复 租户权限bug
更新 主键统一更新为id,remarks统一改为remark

18339543638 2 år sedan
förälder
incheckning
dbf0550266
48 ändrade filer med 988 tillägg och 1620 borttagningar
  1. 10 0
      tr-dependencies/pom.xml
  2. 126 0
      tr-framework/src/main/java/cn/tr/core/utils/CommonNetWorkInfoUtil.java
  3. 4 4
      tr-modules/tr-module-system/pom.xml
  4. 3 5
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictDTO.java
  5. 2 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemDTO.java
  6. 4 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemSmallDTO.java
  7. 4 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictQueryDTO.java
  8. 1 4
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictItemPO.java
  9. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictPO.java
  10. 5 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictItemServiceImpl.java
  11. 12 5
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictServiceImpl.java
  12. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysUserMapper.java
  13. 55 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/DevMonitorController.java
  14. 7 7
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/SysUserOnlineController.java
  15. 254 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/dto/DevMonitorServerResult.java
  16. 2 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/package-info.java
  17. 32 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/service/DevMonitorService.java
  18. 163 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/service/impl/DevMonitorServiceImpl.java
  19. 4 4
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java
  20. 0 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/service/CurrentUserService.java
  21. 6 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/controller/SysTenantController.java
  22. 15 15
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/controller/SysTenantPackageController.java
  23. 15 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/enums/PackageEnum.java
  24. 2 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/ISysTenantPackageMenuService.java
  25. 12 13
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantPackageMenuServiceImpl.java
  26. 15 4
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantPackageServiceImpl.java
  27. 3 8
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantServiceImpl.java
  28. 2 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysMenuController.java
  29. 5 7
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysRoleController.java
  30. 15 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuDTO.java
  31. 42 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysPortalDTO.java
  32. 7 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysRoleDTO.java
  33. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserDTO.java
  34. 47 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysPortalPO.java
  35. 8 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysRolePO.java
  36. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysUserPO.java
  37. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysRoleRepository.java
  38. 3 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysMenuService.java
  39. 16 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysMenuServiceImpl.java
  40. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysRoleServiceImpl.java
  41. 3 3
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java
  42. 0 6
      tr-plugins/tr-spring-boot-starter-plugin-biz-excel/pom.xml
  43. 0 1487
      tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/test/java/cn/tr/plugin/excel/WordTest.java
  44. 55 0
      tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/handler/ListTypeHandler.java
  45. 15 0
      tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/handler/StringListTypeHandler.java
  46. 1 5
      tr-test/pom.xml
  47. 1 0
      tr-test/src/main/resources/application-doc.yml
  48. 4 1
      tr-test/src/main/resources/application.yml

+ 10 - 0
tr-dependencies/pom.xml

@@ -64,6 +64,8 @@
         <!--渲染模板引擎-->
         <beetl.version>1.2.40.Beetl.RELEASE</beetl.version>
 
+        <!--硬件信息-->
+        <oshi.core.version>6.2.2</oshi.core.version>
 
         <ali.dysmsapi.version>2.2.1</ali.dysmsapi.version>
     </properties>
@@ -228,6 +230,14 @@
             <!--OSS模块-->
 
 
+
+            <!--系统硬件信息-->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.core.version}</version>
+            </dependency>
+
             <!-- excel导入导出工具 -->
             <dependency>
                 <groupId>org.apache.poi</groupId>

+ 126 - 0
tr-framework/src/main/java/cn/tr/core/utils/CommonNetWorkInfoUtil.java

@@ -0,0 +1,126 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.core.utils;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.system.SystemUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.*;
+
+/**
+ * 通用获取当前网速工具类
+ *
+ * @author xuyuxiang
+ * @date 2022/9/1 23:45
+ */
+@Slf4j
+public class CommonNetWorkInfoUtil {
+
+    /**
+     * 网速测速时间2s
+     */
+    private static final int SLEEP_SECONDS = 2;
+
+    /**
+     * 获取网络上下行速率,格式{"UP": "123KB/S, "DOWN": "345KB/S"}
+     *
+     * @author xuyuxiang
+     * @date 2022/9/1 23:51
+     */
+    public static Map<String, String> getNetworkUpRate() {
+        Map<String, String> result = new HashMap<>();
+        Process pro = null;
+        Runtime r = Runtime.getRuntime();
+        BufferedReader input = null;
+        try {
+            boolean isWindows = SystemUtil.getOsInfo().isWindows();
+            String command = isWindows ? "netstat -e" : "ifconfig";
+            pro = r.exec(command);
+            input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
+            long[] result1 = readInLine(input, isWindows);
+            Thread.sleep(SLEEP_SECONDS * 1000);
+            pro.destroy();
+            input.close();
+            pro = r.exec(command);
+            input = new BufferedReader(new InputStreamReader(pro.getInputStream()));
+            long[] result2 = readInLine(input, isWindows);
+            String upSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
+                    .div(NumberUtil.sub(result2[0], result1[0]), SLEEP_SECONDS)));
+            String downSpeed = FileUtil.readableFileSize(Convert.toLong(NumberUtil
+                    .div(NumberUtil.sub(result2[1], result1[1]), SLEEP_SECONDS)));
+            result.put("UP", upSpeed + (upSpeed.endsWith("B")?"/S":"B/S"));
+            result.put("DOWN", downSpeed + (downSpeed.endsWith("B")?"/S":"B/S"));
+        } catch (Exception e) {
+            log.info(">>> 网络测速失败,原因:");
+            e.printStackTrace();
+        } finally {
+            if (input != null) {
+                try {
+                    input.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            Optional.ofNullable(pro).ifPresent(Process::destroy);
+        }
+        return result;
+    }
+
+    private static String formatNumber(double f) {
+        return new Formatter().format("%.2f", f).toString();
+    }
+
+    private static long[] readInLine(BufferedReader input, boolean isWindows) {
+        long[] arr = new long[2];
+        StringTokenizer tokenStat;
+        try {
+            if (isWindows) {
+                // 获取windows环境下的网口上下行速率
+                input.readLine();
+                input.readLine();
+                input.readLine();
+                input.readLine();
+                tokenStat = new StringTokenizer(input.readLine());
+                tokenStat.nextToken();
+                arr[0] = Long.parseLong(tokenStat.nextToken());
+                arr[1] = Long.parseLong(tokenStat.nextToken());
+            } else {
+                // 获取linux环境下的网口上下行速率
+                long rx = 0, tx = 0;
+                String line = null;
+                //RX packets:4171603 errors:0 dropped:0 overruns:0 frame:0
+                //TX packets:4171603 errors:0 dropped:0 overruns:0 carrier:0
+                while ((line = input.readLine()) != null) {
+                    if (line.contains("RX packets")) {
+                        rx += Long.parseLong(line.substring(line.indexOf("RX packets") + 11, line.indexOf(" ",
+                                line.indexOf("RX packets") + 11)));
+                    } else if (line.contains("TX packets")) {
+                        tx += Long.parseLong(line.substring(line.indexOf("TX packets") + 11, line.indexOf(" ",
+                                line.indexOf("TX packets") + 11)));
+                    }
+                }
+                arr[0] = rx;
+                arr[1] = tx;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return arr;
+    }
+}

+ 4 - 4
tr-modules/tr-module-system/pom.xml

@@ -43,10 +43,10 @@
             <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
         </dependency>
 
-        <!--<dependency>-->
-            <!--<groupId>cn.tr</groupId>-->
-            <!--<artifactId>tr-spring-boot-starter-plugin-mp-enhance-actable</artifactId>-->
-        <!--</dependency>-->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>cn.tr</groupId>

+ 3 - 5
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictDTO.java

@@ -3,14 +3,12 @@ package cn.tr.module.sys.dict.dto;
 import cn.tr.core.validation.Insert;
 import cn.tr.core.validation.Update;
 import cn.tr.plugin.mybatis.pojo.BaseDTO;
-import cn.tr.plugin.mybatis.pojo.BasePO;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
 import javax.validation.constraints.NotNull;
-import java.io.Serializable;
 
 /**
  * 字典对象 sys_dict
@@ -26,7 +24,7 @@ public class SysDictDTO extends BaseDTO {
 
     @ApiModelProperty(value = "主键")
     @NotNull(message = "字典id不能为空",groups = {Update.class})
-    private String dictId;
+    private String id;
 
 
     @ApiModelProperty(value = "字典编码",required = true)
@@ -37,12 +35,12 @@ public class SysDictDTO extends BaseDTO {
     @ApiModelProperty(value = "字典名称",required = true)
     private String dictName;
 
-    @ApiModelProperty(value = "字典类型 字典值:sys_com_type",required = true)
+    @ApiModelProperty(value = "字典类型  sys:系统字典 biz:业务字典",required = true)
     @NotNull(message = "字典类型不能为空",groups = {Insert.class, Update.class})
     private String dictType;
 
     @ApiModelProperty(value = "备注")
-    private String remarks;
+    private String remark;
 
     @ApiModelProperty(value = "状态 0正常;1停用",required = true)
     @NotNull(message = "字典状态不能为空",groups = {Insert.class, Update.class})

+ 2 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemDTO.java

@@ -26,7 +26,8 @@ public class SysDictItemDTO extends BaseDTO {
     private static final long serialVersionUID = 1L;
 
     @ApiModelProperty(value = "主键")
-    private String dictItemId;
+    @NotNull(message = "字典项id不能为空",groups = {Update.class})
+    private String id;
 
     @ApiModelProperty(value = "字典ID" ,required = true)
     @NotNull(message = "字典id不能为空",groups = {Insert.class, Update.class})
@@ -48,15 +49,10 @@ public class SysDictItemDTO extends BaseDTO {
     private Integer sort;
 
     @ApiModelProperty(value = "备注")
-    @Length(min=1,max = 512,groups = {Insert.class, Update.class},message = "备注 字段长度需在 1至512 之间")
     private String remark;
 
     @ApiModelProperty(value = "回显颜色"  )
     @Length(min=1,max = 255,groups = {Insert.class, Update.class},message = "回显颜色 字段长度需在 1至255 之间")
     private String color;
 
-    @ApiModelProperty(value = "状态 0正常;1停用" ,required = true  )
-    @NotNull(message = "状态不能为空",groups = {Insert.class, Update.class})
-    private Boolean disable;
-
 }

+ 4 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemSmallDTO.java

@@ -14,6 +14,8 @@ import java.io.Serializable;
 public class SysDictItemSmallDTO implements Serializable {
     private static final long serialVersionUID = -2738872740080930736L;
 
+    private String dictItemId;
+
     private String value;
 
     private String label;
@@ -22,5 +24,7 @@ public class SysDictItemSmallDTO implements Serializable {
 
     private String remark;
 
+    private Boolean disable;
+
     private String color;
 }

+ 4 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictQueryDTO.java

@@ -20,4 +20,8 @@ public class SysDictQueryDTO implements Serializable {
 
     @ApiModelProperty("字典编码")
     private String dictCode;
+
+    @ApiModelProperty("字典编码")
+    private String dictType;
+
 }

+ 1 - 4
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictItemPO.java

@@ -23,7 +23,7 @@ public class SysDictItemPO extends BasePO {
 
     @ApiModelProperty(value = "主键")
     @TableId
-    private String dictItemId;
+    private String id;
 
     @ApiModelProperty(value = "字典ID")
     private String dictId;
@@ -44,7 +44,4 @@ public class SysDictItemPO extends BasePO {
     @ApiModelProperty(value = "备注")
     private String remark;
 
-    @ApiModelProperty(value = "状态 0正常;1停用")
-    private Boolean disable;
-
 }

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictPO.java

@@ -25,7 +25,7 @@ public class SysDictPO extends BasePO {
 
     @ApiModelProperty(value = "主键")
     @TableId
-    private String dictId;
+    private String id;
 
 
     @ApiModelProperty(value = "字典编码")
@@ -38,7 +38,7 @@ public class SysDictPO extends BasePO {
     private String dictType;
 
     @ApiModelProperty(value = "备注")
-    private String remarks;
+    private String remark;
 
     @ApiModelProperty(value = "状态 0正常;1停用")
     private Boolean disable;

+ 5 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictItemServiceImpl.java

@@ -41,7 +41,7 @@ public class SysDictItemServiceImpl implements ISysDictItemService {
         if(StrUtil.isNotEmpty(query.getDictCode())){
             SysDictDTO dict = dictService.selectDictByCode(query.getDictCode());
             if(dict!=null){
-                dictIds.add(dict.getDictId());
+                dictIds.add(dict.getId());
             }
         }
         return DictItemMapper.INSTANCE.toDictItemDtoList(
@@ -71,7 +71,7 @@ public class SysDictItemServiceImpl implements ISysDictItemService {
     public int deleteDictItemByIds(Collection<String> ids) {
         List<SysDictItemPO> items = dictItemRepository.selectList(
                 new LambdaQueryWrapper<SysDictItemPO>()
-                        .in(SysDictItemPO::getDictItemId,ids)
+                        .in(SysDictItemPO::getId,ids)
         );
         if(CollectionUtil.isEmpty(items)){
             return CollectionUtil.size(ids);
@@ -80,13 +80,13 @@ public class SysDictItemServiceImpl implements ISysDictItemService {
         List<SysDictDTO> dicts = dictService.selectDictByIds(
                 items.stream().map(SysDictItemPO::getDictId).collect(Collectors.toSet())
         );
-        Map< String, SysDictDTO> dictMap = dicts.stream().collect(Collectors.groupingBy(SysDictDTO::getDictId, Collectors.collectingAndThen(Collectors.toList(), CollUtil::getFirst)));
+        Map< String, SysDictDTO> dictMap = dicts.stream().collect(Collectors.groupingBy(SysDictDTO::getId, Collectors.collectingAndThen(Collectors.toList(), CollUtil::getFirst)));
         items.forEach(item->{
             SysDictDTO dict = dictMap.get(item.getDictId());
             if(dict==null){
                 return;
             }
-            refreshDictByDictId(dict.getDictId());
+            refreshDictByDictId(dict.getId());
         });
         return result;
     }
@@ -107,7 +107,7 @@ public class SysDictItemServiceImpl implements ISysDictItemService {
             return new ArrayList<>();
         }
         List<SysDictItemSmallDTO> result = DictItemMapper.INSTANCE.toDictItemSmallDtoList(dictItemRepository.selectList(new LambdaQueryWrapper<SysDictItemPO>()
-                .eq(SysDictItemPO::getDictId, dict.getDictId())));
+                .eq(SysDictItemPO::getDictId, dict.getId())));
         result.sort(Comparator.comparing(SysDictItemSmallDTO::getSort));
         return result;
     }
@@ -118,6 +118,5 @@ public class SysDictItemServiceImpl implements ISysDictItemService {
             return;
         }
         self.delCache(dict.getDictCode());
-
     }
 }

+ 12 - 5
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictServiceImpl.java

@@ -6,7 +6,9 @@ import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.module.sys.dict.dto.SysDictDTO;
 import cn.tr.module.sys.dict.dto.SysDictQueryDTO;
+import cn.tr.module.sys.dict.po.SysDictItemPO;
 import cn.tr.module.sys.dict.po.SysDictPO;
+import cn.tr.module.sys.dict.repository.SysDictItemRepository;
 import cn.tr.module.sys.dict.repository.SysDictRepository;
 import cn.tr.module.sys.dict.service.ISysDictService;
 import cn.tr.module.sys.mapper.dict.DictMapper;
@@ -15,6 +17,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -31,14 +34,14 @@ import java.util.List;
 @Service
 public class SysDictServiceImpl implements ISysDictService {
     private final SysDictRepository dictRepository;
-    private final DictManager dictManager;
-
+    private final SysDictItemRepository dictItemRepository;
     @Override
     public List<SysDictDTO> selectDictDataList(SysDictQueryDTO query) {
         return DictMapper.INSTANCE.toDictDtoList(dictRepository.selectList(
                 new LambdaQueryWrapper<SysDictPO>()
                         .like(StrUtil.isNotEmpty(query.getDictCode()), SysDictPO::getDictCode,query.getDictCode())
                         .like(StrUtil.isNotEmpty(query.getDictName()), SysDictPO::getDictName,query.getDictName())
+                        .eq(StrUtil.isNotEmpty(query.getDictType()), SysDictPO::getDictType,query.getDictType())
                 )
         );
     }
@@ -55,7 +58,7 @@ public class SysDictServiceImpl implements ISysDictService {
         }
         return DictMapper.INSTANCE.toDictDtoList(dictRepository.selectList(
                 new LambdaQueryWrapper<SysDictPO>()
-                        .in(SysDictPO::getDictId,ids)
+                        .in(SysDictPO::getId,ids)
                 )
         );
     }
@@ -82,15 +85,19 @@ public class SysDictServiceImpl implements ISysDictService {
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public int deleteDictByIds(Collection<String> ids) {
-        return dictRepository.deleteBatchIds(ids);
+        int result = dictRepository.deleteBatchIds(ids);
+        dictItemRepository.delete(new LambdaQueryWrapper<SysDictItemPO>()
+        .in(SysDictItemPO::getDictId,ids));
+        return result;
     }
 
     @Override
     public boolean updateDictById(SysDictDTO source) {
         SysDictPO dict = DictMapper.INSTANCE.toDictPO(source);
         SysDictDTO dictByCode = selectDictByCode(dict.getDictCode());
-        if(dictByCode!=null&&!StrUtil.equals(source.getDictId(),dictByCode.getDictId())){
+        if(dictByCode!=null&&!StrUtil.equals(source.getId(),dictByCode.getId())){
             throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("字典编码{%s}不能重复",source.getDictCode()));
         }
         return dictRepository.updateById(dict)!=0;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysUserMapper.java

@@ -19,7 +19,7 @@ public interface SysUserMapper {
     SysUserMapper INSTANCE = Mappers.getMapper(SysUserMapper.class);
 
     @Mappings(
-            @Mapping(source = "userId",target = "userId")
+            @Mapping(source = "id",target = "id")
     )
     List<UserLoginInfoBO> toUserLoginInfoDTOList(List<SysUserPO> source);
 

+ 55 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/DevMonitorController.java

@@ -0,0 +1,55 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.sys.monitor.controller;
+
+import cn.tr.core.pojo.CommonResult;
+import cn.tr.module.sys.monitor.dto.DevMonitorServerResult;
+import cn.tr.module.sys.monitor.service.DevMonitorService;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 监控控制器
+ *
+ * @author xuyuxiang
+ * @date 2022/6/21 14:57
+ **/
+@Api(tags = "系统服务器监控")
+@ApiSupport(author = "lf")
+@Validated
+@RestController
+@RequestMapping("/monitor/serverInfo")
+public class DevMonitorController {
+
+    @Autowired
+    private DevMonitorService devMonitorService;
+
+    /**
+     * 获取服务器监控信息
+     *
+     * @author xuyuxiang
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperation("获取服务器监控信息")
+    @GetMapping
+    public CommonResult<DevMonitorServerResult> serverInfo() {
+        return CommonResult.success(devMonitorService.serverInfo());
+    }
+}

+ 7 - 7
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysUserOnlineController.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/controller/SysUserOnlineController.java

@@ -1,4 +1,4 @@
-package cn.tr.module.sys.user.controller;
+package cn.tr.module.sys.monitor.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.session.SaSession;
@@ -37,12 +37,12 @@ import java.util.stream.Collectors;
  */
 @RestController
 @Api(tags = "在线用户监控")
-@RequestMapping("/online")
+@RequestMapping("/monitor/online")
 public class SysUserOnlineController extends BaseController {
 
-    @SaCheckPermission("sys:online:list")
-    @PostMapping("/list")
-    @ApiOperation(value = "在线用户列表",notes = "权限 - monitor:online:list")
+    @SaCheckPermission("monitor:online:query")
+    @PostMapping("/query/page")
+    @ApiOperation(value = "在线用户列表",notes = "权限 - monitor:online:query")
     @ApiImplicitParams(
             @ApiImplicitParam(name = "name",example = "用户名或昵称查询")
     )
@@ -63,8 +63,8 @@ public class SysUserOnlineController extends BaseController {
     /**
      * 强退用户
      */
-    @SaCheckPermission("sys:online:forceLogout")
-    @ApiOperation("强退用户")
+    @SaCheckPermission("monitor:online:forceLogout")
+    @ApiOperation(value = "强退用户",notes = "权限 - monitor:online:forceLogout")
     @PostMapping("/forceLogout")
     public CommonResult forceLogout(@RequestBody @Validated OnlineUserOperationDTO source) {
         StpLogic stpLogic = SaTokenUtils.getStpUtil(source.getLoginType());

+ 254 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/dto/DevMonitorServerResult.java

@@ -0,0 +1,254 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.sys.monitor.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 服务器监控结果
+ *
+ * @author xuyuxiang
+ * @date 2022/9/1 16:00
+ */
+@Getter
+@Setter
+public class DevMonitorServerResult {
+
+    /* ==============概览数据============ */
+    /** CPU信息 */
+    @ApiModelProperty(value = "CPU信息", position = 1)
+    private DevMonitorCpuInfo devMonitorCpuInfo;
+
+    /** 内存信息 */
+    @ApiModelProperty(value = "内存信息", position = 2)
+    private DevMonitorMemoryInfo devMonitorMemoryInfo;
+
+    /** 存储信息 */
+    @ApiModelProperty(value = "存储信息", position = 3)
+    private DevMonitorStorageInfo devMonitorStorageInfo;
+
+    /** 网络信息 */
+    @ApiModelProperty(value = "网络信息", position = 4)
+    private DevMonitorNetworkInfo devMonitorNetworkInfo;
+
+    /* ==============服务器数据============ */
+    /** 服务器信息 */
+    @ApiModelProperty(value = "服务器信息", position = 5)
+    private DevMonitorServerInfo devMonitorServerInfo;
+
+    /* ==============JVM数据============ */
+    /** JVM信息 */
+    @ApiModelProperty(value = "JVM信息", position = 6)
+    private DevMonitorJvmInfo devMonitorJvmInfo;
+
+    /**
+     * CPU信息类
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorCpuInfo {
+
+        /** CPU名称 */
+        @ApiModelProperty(value = "CPU名称", position = 1)
+        private String cupName;
+
+        /** CPU数量 */
+        @ApiModelProperty(value = "CPU数量", position = 2)
+        private String cupNum;
+
+        /** CPU物理核心数 */
+        @ApiModelProperty(value = "CPU物理核心数", position = 3)
+        private String cpuPhysicalCoreNum;
+
+        /** CPU逻辑核心数 */
+        @ApiModelProperty(value = "CPU逻辑核心数", position = 4)
+        private String cpuLogicalCoreNum;
+
+        /** CPU系统使用率 */
+        @ApiModelProperty(value = "CPU系统使用率", position = 5)
+        private String cpuSysUseRate;
+
+        /** CPU用户使用率 */
+        @ApiModelProperty(value = "CPU用户使用率", position = 6)
+        private String cpuUserUseRate;
+
+        /** CPU当前总使用率 */
+        @ApiModelProperty(value = "CPU当前总使用率", position = 7)
+        private Double cpuTotalUseRate;
+
+        /** CPU当前等待率 */
+        @ApiModelProperty(value = "CPU当前等待率", position = 8)
+        private String cpuWaitRate;
+
+        /** CPU当前空闲率 */
+        @ApiModelProperty(value = "CPU当前空闲率", position = 9)
+        private String cpuFreeRate;
+    }
+
+    /**
+     * 内存信息类
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorMemoryInfo {
+
+        /** 内存总量 */
+        @ApiModelProperty(value = "内存总量", position = 1)
+        private String memoryTotal;
+
+        /** 内存已用 */
+        @ApiModelProperty(value = "内存已用", position = 2)
+        private String memoryUsed;
+
+        /** 内存剩余 */
+        @ApiModelProperty(value = "内存剩余", position = 3)
+        private String memoryFree;
+
+        /** 内存使用率 */
+        @ApiModelProperty(value = "内存使用率", position = 4)
+        private Double memoryUseRate;
+    }
+
+    /**
+     * 存储信息
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorStorageInfo {
+
+        /** 存储总量 */
+        @ApiModelProperty(value = "存储总量", position = 1)
+        private String storageTotal;
+
+        /** 存储已用 */
+        @ApiModelProperty(value = "存储已用", position = 2)
+        private String storageUsed;
+
+        /** 存储剩余 */
+        @ApiModelProperty(value = "存储剩余", position = 3)
+        private String storageFree;
+
+        /** 存储使用率 */
+        @ApiModelProperty(value = "存储使用率", position = 4)
+        private Double storageUseRate;
+    }
+
+    /**
+     * 网络信息类
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorNetworkInfo {
+
+        /** 上行速率 */
+        @ApiModelProperty(value = "上行速率", position = 1)
+        private String upLinkRate;
+
+        /** 下行速率 */
+        @ApiModelProperty(value = "下行速率", position = 2)
+        private String downLinkRate;
+
+    }
+
+    /**
+     * 服务器信息类
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorServerInfo {
+
+        /** 服务器名称 */
+        @ApiModelProperty(value = "服务器名称", position = 1)
+        private String serverName;
+
+        /** 服务器操作系统 */
+        @ApiModelProperty(value = "服务器操作系统", position = 2)
+        private String serverOs;
+
+        /** 服务器IP */
+        @ApiModelProperty(value = "服务器IP", position = 3)
+        private String serverIp;
+
+        /** 服务器架构 */
+        @ApiModelProperty(value = "服务器架构", position = 4)
+        private String serverArchitecture;
+    }
+
+    /**
+     * JVM信息类
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 16:42
+     */
+    @Getter
+    @Setter
+    public static class DevMonitorJvmInfo {
+
+        /** JVM名称 */
+        @ApiModelProperty(value = "JVM名称", position = 1)
+        private String jvmName;
+
+        /** JVM版本 */
+        @ApiModelProperty(value = "JVM版本", position = 2)
+        private String jvmVersion;
+
+        /** JVM总分配内存 */
+        @ApiModelProperty(value = "JVM总分配内存", position = 3)
+        private String jvmMemoryTotal;
+
+        /** JVM已用内存 */
+        @ApiModelProperty(value = "JVM已用内存", position = 4)
+        private String jvmMemoryUsed;
+
+        /** JVM剩余内存 */
+        @ApiModelProperty(value = "JVM剩余内存", position = 5)
+        private String jvmMemoryFree;
+
+        /** JVM内存使用率 */
+        @ApiModelProperty(value = "JVM内存使用率", position = 6)
+        private Double jvmUseRate;
+
+        /** JVM启动时间 */
+        @ApiModelProperty(value = "JVM启动时间", position = 7)
+        private String jvmStartTime;
+
+        /** JVM运行时长 */
+        @ApiModelProperty(value = "JVM运行时长", position = 8)
+        private String jvmRunTime;
+
+        /** Java版本 */
+        @ApiModelProperty(value = "Java版本", position = 9)
+        private String javaVersion;
+
+        /** Java安装路径 */
+        @ApiModelProperty(value = "Java安装路径", position = 10)
+        private String javaPath;
+    }
+}

+ 2 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/package-info.java

@@ -0,0 +1,2 @@
+package cn.tr.module.sys.monitor;
+//系统监控相关

+ 32 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/service/DevMonitorService.java

@@ -0,0 +1,32 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.sys.monitor.service;
+
+import cn.tr.module.sys.monitor.dto.DevMonitorServerResult;
+
+/**
+ * 监控Service接口
+ *
+ * @author xuyuxiang
+ * @date 2022/9/1 15:59
+ */
+public interface DevMonitorService {
+
+    /**
+     * 获取服务器监控信息
+     *
+     * @author xuyuxiang
+     * @date 2022/9/1 16:02
+     */
+    DevMonitorServerResult serverInfo();
+}

+ 163 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/monitor/service/impl/DevMonitorServiceImpl.java

@@ -0,0 +1,163 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.sys.monitor.service.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.net.NetUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.system.JvmInfo;
+import cn.hutool.system.OsInfo;
+import cn.hutool.system.RuntimeInfo;
+import cn.hutool.system.SystemUtil;
+import cn.tr.core.utils.CommonNetWorkInfoUtil;
+import cn.tr.module.sys.monitor.dto.DevMonitorServerResult;
+import cn.tr.module.sys.monitor.service.DevMonitorService;
+import org.springframework.stereotype.Service;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OperatingSystem;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 监控Service接口实现类
+ *
+ * @author xuyuxiang
+ * @date 2022/9/1 15:59
+ */
+@Service
+public class DevMonitorServiceImpl implements DevMonitorService {
+
+    @Override
+    public DevMonitorServerResult serverInfo() {
+        DevMonitorServerResult devMonitorServerResult = new DevMonitorServerResult();
+        SystemInfo si = new SystemInfo();
+        HardwareAbstractionLayer hal = si.getHardware();
+        CentralProcessor cpu = hal.getProcessor();
+
+        // CPU信息
+        DevMonitorServerResult.DevMonitorCpuInfo devMonitorCpuInfo = new DevMonitorServerResult.DevMonitorCpuInfo();
+        devMonitorCpuInfo.setCupName(StrUtil.trim(cpu.getProcessorIdentifier().getName()));
+        devMonitorCpuInfo.setCupNum(cpu.getPhysicalPackageCount() + "颗物理CPU");
+        devMonitorCpuInfo.setCpuPhysicalCoreNum(cpu.getPhysicalProcessorCount() + "个物理核心");
+        devMonitorCpuInfo.setCpuLogicalCoreNum(cpu.getLogicalProcessorCount() + "个逻辑核心");
+        long[] prevTicks = cpu.getSystemCpuLoadTicks();
+        ThreadUtil.sleep(1000);
+        long[] ticks = cpu.getSystemCpuLoadTicks();
+        long nice = ticks[CentralProcessor.TickType.NICE.getIndex()]
+                - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
+        long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()]
+                - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
+        long softIrq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()]
+                - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
+        long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()]
+                - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
+        long sys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()]
+                - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
+        long user = ticks[CentralProcessor.TickType.USER.getIndex()]
+                - prevTicks[CentralProcessor.TickType.USER.getIndex()];
+        long ioWait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()]
+                - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
+        long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()]
+                - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
+        long totalCpu = user + nice + sys + idle + ioWait + irq + softIrq + steal;
+        devMonitorCpuInfo.setCpuSysUseRate(NumberUtil.div(NumberUtil.mul(sys, 100), totalCpu, 2) + "%");
+        devMonitorCpuInfo.setCpuUserUseRate(NumberUtil.div(NumberUtil.mul(user, 100), totalCpu, 2) + "%");
+        devMonitorCpuInfo.setCpuTotalUseRate(NumberUtil.div(NumberUtil.mul(NumberUtil.add(sys, user), 100), totalCpu, 2));
+        devMonitorCpuInfo.setCpuWaitRate(NumberUtil.div(NumberUtil.mul(ioWait, 100), totalCpu, 2) + "%");
+        devMonitorCpuInfo.setCpuFreeRate(NumberUtil.div(NumberUtil.mul(idle, 100), totalCpu, 2) + "%");
+        devMonitorServerResult.setDevMonitorCpuInfo(devMonitorCpuInfo);
+
+        // 内存信息
+        GlobalMemory memory = hal.getMemory();
+        DevMonitorServerResult.DevMonitorMemoryInfo devMonitorMemoryInfo = new DevMonitorServerResult.DevMonitorMemoryInfo();
+        long used = memory.getTotal() - memory.getAvailable();
+        devMonitorMemoryInfo.setMemoryTotal(FileUtil.readableFileSize(memory.getTotal()));
+        devMonitorMemoryInfo.setMemoryUsed(FileUtil.readableFileSize(used));
+        devMonitorMemoryInfo.setMemoryFree(FileUtil.readableFileSize(memory.getAvailable()));
+        devMonitorMemoryInfo.setMemoryUseRate(NumberUtil.mul(NumberUtil.div(used, memory.getTotal(), 4), 100));
+        devMonitorServerResult.setDevMonitorMemoryInfo(devMonitorMemoryInfo);
+
+        // 存储信息
+        DevMonitorServerResult.DevMonitorStorageInfo devMonitorStorageInfo = new DevMonitorServerResult.DevMonitorStorageInfo();
+        OperatingSystem operatingSystem = si.getOperatingSystem();
+        FileSystem fileSystem = operatingSystem.getFileSystem();
+        AtomicLong storageTotal = new AtomicLong();
+        AtomicLong storageUsed = new AtomicLong();
+        AtomicLong storageFree = new AtomicLong();
+        fileSystem.getFileStores().forEach(osFileStore -> {
+            long totalSpace = osFileStore.getTotalSpace();
+            long usableSpace = osFileStore.getUsableSpace();
+            long freeSpace = osFileStore.getFreeSpace();
+            long usedSpace = totalSpace - usableSpace;
+            storageTotal.addAndGet(totalSpace);
+            storageUsed.addAndGet(usedSpace);
+            storageFree.addAndGet(freeSpace);
+        });
+        devMonitorStorageInfo.setStorageTotal(FileUtil.readableFileSize(storageTotal.get()));
+        devMonitorStorageInfo.setStorageUsed(FileUtil.readableFileSize(storageUsed.get()));
+        devMonitorStorageInfo.setStorageFree(FileUtil.readableFileSize(storageFree.get()));
+        devMonitorStorageInfo.setStorageUseRate(NumberUtil.mul(NumberUtil.div(storageUsed.doubleValue(), storageTotal.doubleValue(), 4), 100));
+        devMonitorServerResult.setDevMonitorStorageInfo(devMonitorStorageInfo);
+
+        // 网络信息
+        DevMonitorServerResult.DevMonitorNetworkInfo devMonitorNetworkInfo = new DevMonitorServerResult.DevMonitorNetworkInfo();
+        Map<String, String> networkUpRate = CommonNetWorkInfoUtil.getNetworkUpRate();
+        devMonitorNetworkInfo.setUpLinkRate(networkUpRate.get("UP"));
+        devMonitorNetworkInfo.setDownLinkRate(networkUpRate.get("DOWN"));
+        devMonitorServerResult.setDevMonitorNetworkInfo(devMonitorNetworkInfo);
+
+        // 服务器信息
+        OsInfo osInfo = SystemUtil.getOsInfo();
+        DevMonitorServerResult.DevMonitorServerInfo devMonitorServerInfo = new DevMonitorServerResult.DevMonitorServerInfo();
+        devMonitorServerInfo.setServerName(NetUtil.getLocalHostName());
+        devMonitorServerInfo.setServerOs(osInfo.getName());
+        devMonitorServerInfo.setServerIp(NetUtil.getLocalhostStr());
+        devMonitorServerInfo.setServerArchitecture(osInfo.getArch());
+        devMonitorServerResult.setDevMonitorServerInfo(devMonitorServerInfo);
+
+        // JVM信息
+        DevMonitorServerResult.DevMonitorJvmInfo devMonitorJvmInfo = new DevMonitorServerResult.DevMonitorJvmInfo();
+        RuntimeInfo runtimeInfo = SystemUtil.getRuntimeInfo();
+        JvmInfo jvmInfo = SystemUtil.getJvmInfo();
+        devMonitorJvmInfo.setJvmName(jvmInfo.getName());
+        devMonitorJvmInfo.setJvmVersion(jvmInfo.getVersion());
+        long totalMemory = runtimeInfo.getTotalMemory();
+        devMonitorJvmInfo.setJvmMemoryTotal(FileUtil.readableFileSize(totalMemory));
+        devMonitorJvmInfo.setJvmMemoryFree(FileUtil.readableFileSize(runtimeInfo.getFreeMemory()));
+        long jvmMemoryUsed = NumberUtil.sub(new BigDecimal(runtimeInfo
+                .getTotalMemory()), new BigDecimal(runtimeInfo.getFreeMemory())).longValue();
+        devMonitorJvmInfo.setJvmMemoryUsed(FileUtil.readableFileSize(jvmMemoryUsed));
+        double jvmUseRate = NumberUtil.mul(NumberUtil.div(jvmMemoryUsed, totalMemory, 4), 100);
+        devMonitorJvmInfo.setJvmUseRate(jvmUseRate);
+        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
+        DateTime startTime = DateUtil.date(runtimeMXBean.getStartTime());
+        devMonitorJvmInfo.setJvmStartTime(DateUtil.formatDateTime(startTime));
+        devMonitorJvmInfo.setJvmRunTime(DateUtil.formatBetween(startTime, DateTime.now()));
+        devMonitorJvmInfo.setJavaVersion(SystemUtil.get("java.version", false));
+        devMonitorJvmInfo.setJavaPath(SystemUtil.get("java.home", false));
+        devMonitorServerResult.setDevMonitorJvmInfo(devMonitorJvmInfo);
+        return devMonitorServerResult;
+    }
+}

+ 4 - 4
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java

@@ -62,26 +62,26 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
             throw new ServiceException(TRExcCode.USER_ERROR_A0202);
         }
         StpLogic stpUtil = SaTokenUtils.getStpUtil();
-        stpUtil.login(user.getUserId());
+        stpUtil.login(user.getId());
         Date loginTime = new Date();
         //更新最后登录信息
         String ip = ServletUtils.getClientIP();
         String cityInfo = IpUtil.getCityInfo(ip);
         SysUserDTO updateUser = new SysUserDTO();
-        updateUser.setUserId(user.getUserId());
+        updateUser.setId(user.getId());
         updateUser.setLastLoginDate(loginTime);
         updateUser.setLastLoginIp(ip);
         updateUser.setLastLoginAddress(cityInfo);
         sysUserService.updateSysUserById(updateUser);
         //清除缓存
-        self.delUserLoginInfoCache(user.getUserId());
+        self.delUserLoginInfoCache(user.getId());
 
         UserAgent userAgent = Optional.ofNullable(UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"))).orElse(new UserAgent());
         String browser = ObjectUtil.isEmpty(userAgent.getBrowser()) ? "未知" : userAgent.getBrowser().getName();
         String os = ObjectUtil.isEmpty(userAgent.getOs()) ? "未知" : userAgent.getOs().getName();
         String tokenValue = stpUtil.getTokenValue();
         UserLoginInfoBO loginInfo = UserLoginInfoBO.builder()
-                .userId(user.getUserId())
+                .userId(user.getId())
                 .username(username)
                 .tenantId(user.getTenantId())
                 .token(tokenValue)

+ 0 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/service/CurrentUserService.java

@@ -3,14 +3,12 @@ package cn.tr.module.sys.oauth2.service;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.tr.core.strategy.LoginUserStrategy;
 import cn.tr.module.sys.tenant.service.ISysTenantService;
 import cn.tr.module.sys.user.dto.SysMenuDTO;
 import cn.tr.module.sys.user.enums.MenuEnum;
 import cn.tr.module.sys.user.service.ISysMenuService;
 import cn.tr.module.sys.user.service.ISysRoleService;
 import cn.tr.module.sys.user.vo.RouteItemVO;
-import cn.tr.plugin.security.context.LoginUserContextHolder;
 import cn.tr.plugin.security.utils.SaTokenUtils;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Component;

+ 6 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/controller/SysTenantController.java

@@ -30,7 +30,7 @@ import java.util.Collection;
 @Api(tags = "租户")
 @AllArgsConstructor
 public class SysTenantController extends BaseController {
-    private final ISysTenantService orgService;
+    private final ISysTenantService tenantService;
 
 
     @PostMapping("/query/page")
@@ -39,7 +39,7 @@ public class SysTenantController extends BaseController {
     @SaCheckPermission("sys:tenant:query")
     public TableDataInfo<SysTenantCommonDTO> selectList(@RequestBody SysTenantQueryDTO query){
         startPage();
-        return getDataTable(orgService.selectSysTenantList(query));
+        return getDataTable(tenantService.selectSysTenantList(query));
     }
 
     @GetMapping("/detail/{id}")
@@ -47,7 +47,7 @@ public class SysTenantController extends BaseController {
     @ApiOperation(value = "根据id查询租户",notes = "权限: sys:tenant:query")
     @SaCheckPermission("sys:tenant:query")
     public CommonResult<SysTenantCommonDTO> findById(@PathVariable("id") String id){
-        return CommonResult.success(orgService.selectSysTenantById(id));
+        return CommonResult.success(tenantService.selectSysTenantById(id));
     }
 
     @PostMapping("/edit")
@@ -55,7 +55,7 @@ public class SysTenantController extends BaseController {
     @SaCheckPermission("sys:tenant:edit")
     @ApiOperation(value = "根据id更新租户",notes = "权限: sys:tenant:edit")
     public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysTenantCommonDTO source){
-        return CommonResult.success(orgService.updateSysTenantById(source));
+        return CommonResult.success(tenantService.updateSysTenantById(source));
     }
 
     @PostMapping("/add")
@@ -63,7 +63,7 @@ public class SysTenantController extends BaseController {
     @SaCheckPermission("sys:tenant:add")
     @ApiOperation(value = "新增租户",notes = "权限: sys:tenant:add")
     public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysTenantAddDTO source){
-        return CommonResult.success(orgService.insertSysTenant(source));
+        return CommonResult.success(tenantService.insertSysTenant(source));
     }
 
     @PostMapping("/deleteByIds")
@@ -71,7 +71,7 @@ public class SysTenantController extends BaseController {
     @ApiOperation(value = "删除租户",notes = "权限: sys:tenant:del")
     @SaCheckPermission("sys:tenant:del")
     public CommonResult<Integer> deleteByIds(@RequestBody Collection<String> ids){
-        return CommonResult.success(orgService.deleteSysTenantByIds(ids));
+        return CommonResult.success(tenantService.deleteSysTenantByIds(ids));
     }
     
 

+ 15 - 15
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/controller/SysTenantPackageController.java

@@ -5,12 +5,10 @@ import cn.tr.core.pojo.CommonResult;
 import cn.tr.core.pojo.TableDataInfo;
 import cn.tr.core.validation.Insert;
 import cn.tr.core.validation.Update;
-import cn.tr.module.sys.tenant.dto.SysTenantAddDTO;
-import cn.tr.module.sys.tenant.dto.SysTenantCommonDTO;
-import cn.tr.module.sys.tenant.dto.SysTenantPackageMenuDTO;
-import cn.tr.module.sys.tenant.dto.SysTenantQueryDTO;
+import cn.tr.module.sys.tenant.dto.*;
+import cn.tr.module.sys.tenant.enums.PackageEnum;
 import cn.tr.module.sys.tenant.service.ISysTenantPackageMenuService;
-import cn.tr.module.sys.tenant.service.ISysTenantService;
+import cn.tr.module.sys.tenant.service.ISysTenantPackageService;
 import cn.tr.plugin.mybatis.base.BaseController;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import io.swagger.annotations.Api;
@@ -33,7 +31,7 @@ import java.util.List;
 @Api(tags = "租户套餐")
 @AllArgsConstructor
 public class SysTenantPackageController extends BaseController {
-    private final ISysTenantService tenantService;
+    private final ISysTenantPackageService tenantPackageService;
     private final ISysTenantPackageMenuService tenantPackageMenuService;
     @PostMapping("/assign")
     @ApiOperationSupport(author = "lf")
@@ -48,33 +46,35 @@ public class SysTenantPackageController extends BaseController {
     @ApiOperationSupport(author = "lf")
     @ApiOperation(value = "根据条件查询租户套餐",notes = "权限: sys:tenantPackage:query")
     @SaCheckPermission("sys:tenantPackage:query")
-    public TableDataInfo<SysTenantCommonDTO> selectList(@RequestBody SysTenantQueryDTO query){
+    public TableDataInfo<SysTenantPackageDTO> selectList(@RequestBody SysTenantPackageQueryDTO query){
         startPage();
-        return getDataTable(tenantService.selectSysTenantList(query));
+        return getDataTable(tenantPackageService.selectSysTenantPackageList(query));
     }
 
     @GetMapping("/detail/{id}")
     @ApiOperationSupport(author = "lf")
     @ApiOperation(value = "根据id查询租户套餐",notes = "权限: sys:tenantPackage:query")
     @SaCheckPermission("sys:tenantPackage:query")
-    public CommonResult<SysTenantCommonDTO> findById(@PathVariable("id") String id){
-        return CommonResult.success(tenantService.selectSysTenantById(id));
+    public CommonResult<SysTenantPackageDTO> findById(@PathVariable("id") String id){
+        return CommonResult.success(tenantPackageService.selectSysTenantPackageById(id));
     }
 
     @PostMapping("/edit")
     @ApiOperationSupport(author = "lf")
     @SaCheckPermission("sys:tenantPackage:edit")
     @ApiOperation(value = "根据id更新租户套餐",notes = "权限: sys:tenantPackage:edit")
-    public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysTenantCommonDTO source){
-        return CommonResult.success(tenantService.updateSysTenantById(source));
+    public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysTenantPackageDTO source){
+        source.setType(PackageEnum.custom.name());
+        return CommonResult.success(tenantPackageService.updateSysTenantPackageById(source));
     }
 
     @PostMapping("/add")
     @ApiOperationSupport(author = "lf")
     @SaCheckPermission("sys:tenantPackage:add")
     @ApiOperation(value = "新增租户套餐",notes = "权限: sys:tenantPackage:add")
-    public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysTenantAddDTO source){
-        return CommonResult.success(tenantService.insertSysTenant(source));
+    public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysTenantPackageDTO source){
+        source.setType(PackageEnum.custom.name());
+        return CommonResult.success(tenantPackageService.insertSysTenantPackage(source));
     }
 
     @PostMapping("/deleteByIds")
@@ -82,7 +82,7 @@ public class SysTenantPackageController extends BaseController {
     @ApiOperation(value = "删除租户套餐",notes = "权限: sys:tenantPackage:del")
     @SaCheckPermission("sys:tenantPackage:del")
     public CommonResult<Integer> deleteByIds(@RequestBody Collection<String> ids){
-        return CommonResult.success(tenantService.deleteSysTenantByIds(ids));
+        return CommonResult.success(tenantPackageService.deleteSysTenantPackageByIds(ids));
     }
     
 

+ 15 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/enums/PackageEnum.java

@@ -0,0 +1,15 @@
+package cn.tr.module.sys.tenant.enums;
+
+/**
+ * @ClassName : PackageEnum
+ * @Description : 套餐类型
+ * @Author : LF
+ * @Date: 2023年04月05日
+ */
+
+public enum PackageEnum {
+    //系统类型
+    sys,
+    //自定义类型
+    custom
+}

+ 2 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/ISysTenantPackageMenuService.java

@@ -1,6 +1,7 @@
 package cn.tr.module.sys.tenant.service;
 
 import cn.tr.module.sys.tenant.dto.SysTenantPackageMenuDTO;
+import cn.tr.module.sys.user.dto.SysMenuDTO;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
 
@@ -38,5 +39,5 @@ public interface ISysTenantPackageMenuService {
      * @return
      */
     @Cacheable(value = "menu:package:",key = "#packageId")
-    Set<String> findMenuIdByPackageId(String packageId);
+    Set<SysMenuDTO> findMenuIdByPackageId(String packageId);
 }

+ 12 - 13
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantPackageMenuServiceImpl.java

@@ -1,5 +1,6 @@
 package cn.tr.module.sys.tenant.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.module.sys.mapper.tenant.SysTenantPackageMenuMapper;
 import cn.tr.module.sys.tenant.dto.SysTenantPackageDTO;
@@ -58,7 +59,7 @@ public class SysTenantPackageMenuServiceImpl  extends ServiceImpl<SysTenantPacka
             );
             self.delCacheMenuIdByPackageId(packageId);
         });
-        //todo
+        //todo 可优化
         sysRoles.forEach(role->menuService.delRoleMenusCache(role.getId()));
         this.saveBatch(packageMenus);
     }
@@ -82,25 +83,23 @@ public class SysTenantPackageMenuServiceImpl  extends ServiceImpl<SysTenantPacka
     }
 
     @Override
-    public Set<String> findMenuIdByPackageId(String packageId) {
+    public Set<SysMenuDTO> findMenuIdByPackageId(String packageId) {
+        Set<SysMenuDTO> result = new HashSet<>();
         Set<String> menuIds = this.list(new LambdaQueryWrapper<SysTenantPackageMenuPO>().eq(SysTenantPackageMenuPO::getPackageId, packageId))
                 .stream()
                 .map(SysTenantPackageMenuPO::getMenuId)
                 .collect(Collectors.toSet());
+        if(CollectionUtil.isNotEmpty(menuIds)){
+            List<SysMenuDTO> menus = menuService.selectBatchIds(menuIds);
+            result.addAll(menus);
+        }
+
         SysTenantPackageDTO packageDTO = tenantPackageService.selectSysTenantPackageById(packageId);
         if(packageDTO!=null&&StrUtil.equals(packageDTO.getType(),"sys")){
             //所有目录id
-            menuIds.addAll(
-                    menuService.findAllMenu()
-                    .stream()
-                    .filter(Objects::nonNull)
-                    .map(SysMenuDTO::getId)
-                    .collect(Collectors.toSet())
-            );
+            List<SysMenuDTO> menus = menuService.findAllMenu();
+            result.addAll(menus);
         }
-        return this.list(new LambdaQueryWrapper<SysTenantPackageMenuPO>().eq(SysTenantPackageMenuPO::getPackageId, packageId))
-                .stream()
-                .map(SysTenantPackageMenuPO::getMenuId)
-                .collect(Collectors.toSet());
+        return result;
     }
 }

+ 15 - 4
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantPackageServiceImpl.java

@@ -9,6 +9,7 @@ import cn.tr.core.utils.JsonUtils;
 import cn.tr.module.sys.mapper.tenant.SysTenantPackageMapper;
 import cn.tr.module.sys.tenant.dto.SysTenantPackageDTO;
 import cn.tr.module.sys.tenant.dto.SysTenantPackageQueryDTO;
+import cn.tr.module.sys.tenant.enums.PackageEnum;
 import cn.tr.module.sys.tenant.po.SysTenantPO;
 import cn.tr.module.sys.tenant.po.SysTenantPackagePO;
 import cn.tr.module.sys.tenant.repository.SysTenantPackageRepository;
@@ -18,9 +19,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -54,6 +53,7 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
 
     @Override
     public boolean updateSysTenantPackageById(SysTenantPackageDTO source) {
+        validatePackageSource(Collections.singleton(source.getId()));
         SysTenantPackagePO exitPackage = tenantPackageRepository.selectOne(new LambdaQueryWrapper<SysTenantPackagePO>()
                 .eq(SysTenantPackagePO::getPackageCode, source.getPackageCode())
                 .ne(SysTenantPackagePO::getId,source.getId())
@@ -77,6 +77,7 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
 
     @Override
     public int deleteSysTenantPackageByIds(Collection<String> ids) {
+        validatePackageSource(ids);
         List<SysTenantPO> tenants = tenantRepository.selectList(new LambdaQueryWrapper<SysTenantPO>()
                 .in(SysTenantPO::getPackageId, ids));
         if(CollectionUtil.isNotEmpty(tenants)){
@@ -95,6 +96,16 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
     @Override
     public Collection<SysTenantPackageDTO> findAllSysPackages() {
         return SysTenantPackageMapper.INSTANCE.toDTOList(tenantPackageRepository.selectList(new LambdaQueryWrapper<SysTenantPackagePO>()
-                .eq(SysTenantPackagePO::getType,"sys")));
+                .eq(SysTenantPackagePO::getType, PackageEnum.sys.name())));
+    }
+
+    private void validatePackageSource(Collection<String> packageIds){
+        List<SysTenantPackagePO> packages = tenantPackageRepository.selectList(new LambdaQueryWrapper<SysTenantPackagePO>()
+                .in(SysTenantPackagePO::getId, packageIds));
+        for (SysTenantPackagePO aPackage : packages) {
+            if(StrUtil.equals(aPackage.getType(),PackageEnum.sys.name())){
+                throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"无法对系统级别套餐进行操作");
+            }
+        }
     }
 }

+ 3 - 8
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/tenant/service/impl/SysTenantServiceImpl.java

@@ -1,10 +1,9 @@
 package cn.tr.module.sys.tenant.service.impl;
 
-import cn.hutool.core.collection.CollectionUtil;
+
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.module.sys.mapper.tenant.SysTenantMapper;
-import cn.tr.module.sys.mapper.user.SysMenuMapper;
 import cn.tr.module.sys.tenant.dto.SysTenantAddDTO;
 import cn.tr.module.sys.tenant.dto.SysTenantCommonDTO;
 import cn.tr.module.sys.tenant.dto.SysTenantQueryDTO;
@@ -110,11 +109,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
     @Override
     public Set<SysMenuDTO> getTenantMenus(String tenantId) {
         SysTenantPO tenant = tenantRepository.selectById(tenantId);
-        Set<String> menuIds = tenantPackageMenuService.findMenuIdByPackageId(tenant.getPackageId());
-        if(CollectionUtil.isEmpty(menuIds)){
-            return new HashSet<>();
-        }
-        return new HashSet<>(SysMenuMapper.INSTANCE.toSysMenuDTOList( menuRepository.selectBatchIds(menuIds)));
+        return  tenantPackageMenuService.findMenuIdByPackageId(tenant.getPackageId());
     }
 
     private SysOrgDTO buildOrg(String orgId,String tenantName){
@@ -142,7 +137,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
 
     private SysUserDTO buildUser(String userId,String roleId,String orgId,String username,String password,String tenantName){
         SysUserDTO user = new SysUserDTO();
-        user.setUserId(userId);
+        user.setId(userId);
         user.setOrgId(orgId);
         user.setUsername(username);
         user.setPassword(password);

+ 2 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysMenuController.java

@@ -3,8 +3,10 @@ package cn.tr.module.sys.user.controller;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.tr.core.pojo.CommonResult;
 import cn.tr.core.pojo.TableDataInfo;
+import cn.tr.core.utils.TreeUtil;
 import cn.tr.core.validation.Insert;
 import cn.tr.core.validation.Update;
+import cn.tr.module.sys.tenant.service.ISysTenantService;
 import cn.tr.module.sys.user.dto.SysMenuDTO;
 import cn.tr.module.sys.user.dto.SysMenuQueryDTO;
 import cn.tr.module.sys.user.service.ISysMenuService;

+ 5 - 7
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysRoleController.java

@@ -10,6 +10,7 @@ import cn.tr.module.sys.user.dto.SysMenuDTO;
 import cn.tr.module.sys.user.dto.SysRoleDTO;
 import cn.tr.module.sys.user.dto.SysRoleMenuDTO;
 import cn.tr.module.sys.user.dto.SysRoleQueryDTO;
+import cn.tr.module.sys.user.enums.RoleEnum;
 import cn.tr.module.sys.user.service.ISysMenuService;
 import cn.tr.module.sys.user.service.ISysRoleMenuService;
 import cn.tr.module.sys.user.service.ISysRoleService;
@@ -43,13 +44,8 @@ public class SysRoleController extends BaseController {
 
     @GetMapping("/menu/tree/{roleId}")
     @ApiOperation(value = "查询角色下的权限信息",notes = "权限: 无")
-    public CommonResult<List<RouteItemVO>> listMenu(@PathVariable("roleId") String roleId) {
-        return CommonResult.success(TreeUtil.buildTree(
-                menuService.findAllMenuByRoleId(roleId)
-                        .stream()
-                        .map(menuService::convertToRoute)
-                        .collect(Collectors.toList())
-        ));
+    public CommonResult<List<SysMenuDTO>> listMenu(@PathVariable("roleId") String roleId) {
+        return CommonResult.success(menuService.findAllMenuByRoleId(roleId));
     }
 
     @PostMapping("/query/page")
@@ -83,6 +79,7 @@ public class SysRoleController extends BaseController {
     @SaCheckPermission("sys:role:edit")
     @ApiOperation(value = "根据id更新角色",notes = "权限: sys:role:edit")
     public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysRoleDTO source){
+        source.setType(RoleEnum.custom.name());
         return CommonResult.success(roleService.updateSysRoleById(source));
     }
 
@@ -91,6 +88,7 @@ public class SysRoleController extends BaseController {
     @SaCheckPermission("sys:role:add")
     @ApiOperation(value = "新增角色",notes = "权限: sys:role:add")
     public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysRoleDTO source){
+        source.setType(RoleEnum.custom.name());
         return CommonResult.success(roleService.insertSysRole(source));
     }
 

+ 15 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuDTO.java

@@ -12,6 +12,7 @@ import lombok.ToString;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.util.Date;
+import java.util.Objects;
 
 /**
  * 菜单对象 sys_menu
@@ -21,7 +22,6 @@ import java.util.Date;
  */
 @Data
 @ToString
-@EqualsAndHashCode(callSuper = true)
 public class SysMenuDTO extends TreeNode<String> {
 
     private static final long serialVersionUID = 1L;
@@ -94,4 +94,18 @@ public class SysMenuDTO extends TreeNode<String> {
      */
     @JsonIgnoreProperties(allowGetters = true)
     private Date updateTime;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        SysMenuDTO that = (SysMenuDTO) o;
+        return Objects.equals(getId(), that.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), getId());
+    }
 }

+ 42 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysPortalDTO.java

@@ -0,0 +1,42 @@
+package cn.tr.module.sys.user.dto;
+
+import cn.tr.core.validation.Update;
+import cn.tr.plugin.mybatis.pojo.BaseDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @ClassName : SysRolePO
+ * @Description : 门户
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+public class SysPortalDTO  extends BaseDTO {
+    @ApiModelProperty("门户id")
+    @NotNull(message = "门户id不能为空",groups = {Update.class})
+    private String id;
+
+    @ApiModelProperty(value = "门户编码",required = true)
+    private String code;
+
+    @ApiModelProperty(value = "门户名称",required = true)
+    private String name;
+
+    /**
+     * {@link cn.tr.module.sys.user.enums.RoleEnum}
+     */
+    @ApiModelProperty(value = "门户类型 sys、系统门户 custom、自定义门户",readOnly = true)
+    private String type;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty(value = "排序",required = true)
+    private Integer sort;
+
+    @ApiModelProperty(value = "是否启用 0、启用 1、关闭",required = true)
+    private Boolean disable;
+}

+ 7 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysRoleDTO.java

@@ -3,14 +3,12 @@ package cn.tr.module.sys.user.dto;
 import cn.tr.core.validation.Insert;
 import cn.tr.core.validation.Update;
 import cn.tr.plugin.mybatis.pojo.BaseDTO;
-import cn.tr.plugin.mybatis.pojo.TenantPO;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-
+import java.util.*;
 import javax.validation.constraints.NotEmpty;
-import java.io.Serializable;
+import javax.validation.constraints.NotNull;
 
 /**
  * @ClassName : SysRolePO
@@ -38,6 +36,9 @@ public class SysRoleDTO extends BaseDTO {
     @NotEmpty(message = "数据范围不能为空",groups = {Insert.class, Update.class})
     private String dataScope;
 
+    @ApiModelProperty("数据组织id")
+    private List<String> orgIds;
+
     /**
      * {@link cn.tr.module.sys.user.enums.RoleEnum}
      */
@@ -46,11 +47,11 @@ public class SysRoleDTO extends BaseDTO {
     private String type;
 
     @ApiModelProperty(value = "排序",required = true)
-    @NotEmpty(message = "排序不能为空",groups = {Insert.class, Update.class})
+    @NotNull(message = "排序不能为空",groups = {Insert.class, Update.class})
     private Integer sort;
 
     @ApiModelProperty(value = "是否启用 0、启用 1、关闭",required = true)
-    @NotEmpty(message = "启用状态 不能为空",groups = {Insert.class, Update.class})
+    @NotNull(message = "启用状态 不能为空",groups = {Insert.class, Update.class})
     private Boolean disable;
 
 

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserDTO.java

@@ -27,7 +27,7 @@ public class SysUserDTO extends BaseDTO {
      * 用户主键Id
      */
     @ApiModelProperty(value = "用户id")
-    private String userId;
+    private String id;
 
     /**
      * 用户名

+ 47 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysPortalPO.java

@@ -0,0 +1,47 @@
+package cn.tr.module.sys.user.po;
+
+import cn.tr.core.annotation.Comment;
+import cn.tr.plugin.mybatis.config.handler.StringListTypeHandler;
+import cn.tr.plugin.mybatis.pojo.TenantPO;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import org.apache.ibatis.type.JdbcType;
+
+import java.util.List;
+
+/**
+ * @ClassName : SysRolePO
+ * @Description : 门户
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+@TableName("sys_protal")
+public class SysPortalPO extends TenantPO {
+    @TableId
+    @Comment("门户id")
+    private String id;
+
+    @Comment("门户编码")
+    private String code;
+
+    @Comment("门户名称")
+    private String name;
+
+    /**
+     * {@link cn.tr.module.sys.user.enums.RoleEnum}
+     */
+    @Comment("门户类型 sys、系统门户 custom、自定义门户")
+    private String type;
+
+    @Comment("备注")
+    private String remark;
+
+    @Comment("排序")
+    private Integer sort;
+
+    @Comment("是否启用 0、启用 1、关闭")
+    private Boolean disable;
+}

+ 8 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysRolePO.java

@@ -1,11 +1,15 @@
 package cn.tr.module.sys.user.po;
 
 import cn.tr.core.annotation.Comment;
+import cn.tr.plugin.mybatis.config.handler.StringListTypeHandler;
 import cn.tr.plugin.mybatis.pojo.TenantPO;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
+import org.apache.ibatis.type.JdbcType;
 
+import java.util.*;
 /**
  * @ClassName : SysRolePO
  * @Description : 系统角色
@@ -28,6 +32,10 @@ public class SysRolePO extends TenantPO {
     @Comment("数据范围 1、全部数据权限;2、自定义数据权限;3、本部门数据权限;4、本部门及以下数据权限")
     private String dataScope;
 
+    @Comment("数据组织id")
+    @TableField(typeHandler = StringListTypeHandler.class,jdbcType = JdbcType.VARCHAR)
+    private List<String> orgIds;
+
     /**
      * {@link cn.tr.module.sys.user.enums.RoleEnum}
      */

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysUserPO.java

@@ -23,7 +23,7 @@ public class SysUserPO extends TenantPO {
     private static final long serialVersionUID = -588007107794525494L;
     @Comment("用户主键Id")
     @TableId
-    private String userId;
+    private String id;
 
     @Comment("用户名")
     @TableField(updateStrategy = FieldStrategy.NEVER)

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysRoleRepository.java

@@ -23,5 +23,5 @@ public interface SysRoleRepository extends BaseMapper<SysRolePO> {
      * @param userId 用户id
      * @return
      */
-    List<SysRolePO> findAllRoleByUserId(@Param("userId") String userId);
+    List<SysRolePO> findAllRoleByUserId(@Param("id") String userId);
 }

+ 3 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysMenuService.java

@@ -15,6 +15,7 @@ import org.springframework.cache.annotation.Cacheable;
 import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * @ClassName : ISysMenuService
@@ -134,4 +135,6 @@ public interface ISysMenuService extends ITreeService {
         node.setMeta(routeMetoVO);
         return node;
     }
+
+    List<SysMenuDTO> selectBatchIds(Set<String> menuIds);
 }

+ 16 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysMenuServiceImpl.java

@@ -23,7 +23,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
-import java.util.stream.Stream;
 
 /**
  * @ClassName : SysMenuServiceImpl
@@ -56,11 +55,17 @@ public class SysMenuServiceImpl implements ISysMenuService {
     private ISysMenuService self;
     @Override
     public List<SysMenuDTO> selectSysMenuList(SysMenuQueryDTO query) {
-        return SysMenuMapper.INSTANCE.toSysMenuDTOList(menuRepository.selectList(new LambdaQueryWrapper<SysMenuPO>()
-                .like(StrUtil.isNotEmpty(query.getName()),SysMenuPO::getName,query.getName())
-                .eq(ObjectUtil.isNotNull(query.getDisable()),SysMenuPO::getDisable,query.getDisable())
-                .eq(ObjectUtil.isNotNull(query.getParentId()),SysMenuPO::getParentId,query.getParentId()))
-        );
+        List<SysMenuDTO> selectResult =
+        SysMenuMapper.INSTANCE.toSysMenuDTOList( menuRepository.selectList(new LambdaQueryWrapper<SysMenuPO>()
+                .like(StrUtil.isNotEmpty(query.getName()), SysMenuPO::getName, query.getName())
+                .eq(ObjectUtil.isNotNull(query.getDisable()), SysMenuPO::getDisable, query.getDisable())
+                .eq(ObjectUtil.isNotNull(query.getParentId()), SysMenuPO::getParentId, query.getParentId())));
+        if(CollectionUtil.isNotEmpty(selectResult)){
+            //取与当前租户菜单交集
+            Set<SysMenuDTO> tenantMenus = tenantService.currentTenantMenus();
+            return new ArrayList<>(CollectionUtil.intersection(tenantMenus,selectResult));
+        }
+        return selectResult;
     }
 
     @Override
@@ -123,6 +128,11 @@ public class SysMenuServiceImpl implements ISysMenuService {
         return SysMenuMapper.INSTANCE.toSysMenuDTOList(menuRepository.findAllMenuByRoleId(roleId));
     }
 
+    @Override
+    public List<SysMenuDTO> selectBatchIds(Set<String> menuIds) {
+        return SysMenuMapper.INSTANCE.toSysMenuDTOList(menuRepository.selectBatchIds(menuIds));
+    }
+
     private void refreshCache(Collection<String> source){
         Set<String> roleIds = roleMenuService.findRoleByMenuId(source,true);
         roleIds.parallelStream().forEach(self::delRoleMenusCache);

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysRoleServiceImpl.java

@@ -67,7 +67,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
             return new HashSet<>();
         }
         for (SysRoleDTO role : roles) {
-            if(StrUtil.equals(role.getType(),"sys")){
+            if(StrUtil.equals(role.getType(),RoleEnum.sys.name())){
                 return tenantService.currentTenantMenus();
             }
         }
@@ -84,7 +84,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
     @Override
     public Collection<SysRoleDTO> findAllSysRoles() {
         return SysRoleMapper.INSTANCE.toSysRoleDTOList( roleRepository.selectList(new LambdaQueryWrapper<SysRolePO>()
-                .eq(SysRolePO::getType,"sys")));
+                .eq(SysRolePO::getType,RoleEnum.sys.name())));
     }
 
     ;

+ 3 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java

@@ -61,7 +61,7 @@ public class SysUserServiceImpl implements ISysUserService {
     public boolean updateSysUserById(SysUserDTO source) {
         boolean result=userRepository.updateById(SysUserMapper.INSTANCE.toUserPO(source))!=0;
         if(result){
-            assignUserRole(source.getUserId(),source.getRoleIds());
+            assignUserRole(source.getId(),source.getRoleIds());
         }
         return result;
     }
@@ -86,7 +86,7 @@ public class SysUserServiceImpl implements ISysUserService {
             throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"旧密码错误");
         }
         SysUserPO updateUser = new SysUserPO();
-        updateUser.setUserId(user.getUserId());
+        updateUser.setId(user.getId());
         updateUser.setPassword(PswUtils.encryptPassword(newPsw));
         return  userRepository.updateById(updateUser) != 0;
     }
@@ -115,7 +115,7 @@ public class SysUserServiceImpl implements ISysUserService {
             }
         }
         if(result){
-            assignUserRole(source.getUserId(),source.getRoleIds());
+            assignUserRole(source.getId(),source.getRoleIds());
         }
         return result;
     }

+ 0 - 6
tr-plugins/tr-spring-boot-starter-plugin-biz-excel/pom.xml

@@ -54,12 +54,6 @@
             <artifactId>poi-ooxml</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>com.deepoove</groupId>
-            <artifactId>poi-tl</artifactId>
-            <version>1.12.0</version>
-        </dependency>
-
 
     </dependencies>
 </project>

+ 0 - 1487
tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/test/java/cn/tr/plugin/excel/WordTest.java

@@ -1,1487 +0,0 @@
-package cn.tr.plugin.excel;
-
-import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.codec.Base64;
-import cn.hutool.core.io.FastByteArrayOutputStream;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.json.JSONArray;
-import cn.hutool.json.JSONObject;
-import cn.hutool.json.JSONUtil;
-import cn.tr.core.utils.JsonUtils;
-import cn.tr.plugin.dict.config.cache.DictManager;
-import cn.tr.plugin.excel.config.ExcelHelperFactory;
-import cn.tr.plugin.test.ut.BaseMockitoUnitTest;
-import com.deepoove.poi.XWPFTemplate;
-import com.deepoove.poi.config.Configure;
-import com.deepoove.poi.data.PictureType;
-import com.deepoove.poi.data.Pictures;
-import com.deepoove.poi.plugin.table.LoopColumnTableRenderPolicy;
-import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
-import com.deepoove.poi.policy.ListRenderPolicy;
-import com.deepoove.poi.util.ByteUtils;
-import com.deepoove.poi.util.PoitlIOUtils;
-import com.deepoove.poi.xwpf.NiceXWPFDocument;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-import org.apache.poi.xwpf.usermodel.BreakType;
-import org.apache.poi.xwpf.usermodel.Document;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFRun;
-import org.apache.xmlgraphics.image.loader.util.ImageUtil;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.util.Base64Utils;
-
-import java.io.*;
-import java.math.BigDecimal;
-import java.nio.charset.Charset;
-import java.util.*;
-import java.util.Map;
-
-/**
- * @ClassName : WordTest
- * @Description :
- * @Author : LF
- * @Date: 2023年03月25日
- */
-
-public class WordTest extends BaseMockitoUnitTest {
-    private DictManager dictManager;
-    String str="[\n" +
-            "  {\n" +
-            "    \"id\": \"1634418903713304577\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:07\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418903650390020\",\n" +
-            "    \"dataNumber\": 3,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 0,\n" +
-            "    \"inputDose\": 5,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 93,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418903902048257\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418903650390020\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 0,\n" +
-            "        \"inputDose\": 5,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418903713304577\",\n" +
-            "        \"modifyTime\": \"2023-03-01 16:29:31\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 0,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 16:29:34\",\n" +
-            "    \"startTime\": \"2023-03-01 16:29:31\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418901553238018\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418901486129156\",\n" +
-            "    \"dataNumber\": 4,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 0.6,\n" +
-            "    \"inputDose\": 4.4,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 93,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418901741981697\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418901486129156\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 3.2,\n" +
-            "        \"inputDose\": 1.8,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418901553238018\",\n" +
-            "        \"modifyTime\": \"2023-03-01 16:27:37\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 16:29:12\",\n" +
-            "    \"startTime\": \"2023-03-01 16:27:37\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418900785680386\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418900722765827\",\n" +
-            "    \"dataNumber\": 1,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 4.1,\n" +
-            "    \"inputDose\": 0.9,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 94,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418900974424065\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418900722765827\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 4.1,\n" +
-            "        \"inputDose\": 0.9,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418900785680386\",\n" +
-            "        \"modifyTime\": \"2023-03-01 16:27:06\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 16:27:06\",\n" +
-            "    \"startTime\": \"2023-03-01 16:27:06\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418900022317058\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418899959402501\",\n" +
-            "    \"dataNumber\": 1,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 5,\n" +
-            "    \"inputDose\": 0,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 95,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418900211060738\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:07\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418899959402501\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 5,\n" +
-            "        \"inputDose\": 0,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418900022317058\",\n" +
-            "        \"modifyTime\": \"2023-03-01 16:26:34\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 16:26:34\",\n" +
-            "    \"startTime\": \"2023-03-01 16:26:34\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418899019878402\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:06\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418898956963843\",\n" +
-            "    \"dataNumber\": 1,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 0,\n" +
-            "    \"inputDose\": 5,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 95,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418899204427778\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:06\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:06\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418898956963843\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 0,\n" +
-            "        \"inputDose\": 5,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418899019878402\",\n" +
-            "        \"modifyTime\": \"2023-03-01 16:26:32\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 16:26:32\",\n" +
-            "    \"startTime\": \"2023-03-01 16:26:32\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418881059868674\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:02\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:02\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418880996954114\",\n" +
-            "    \"dataNumber\": 9,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 0,\n" +
-            "    \"inputDose\": 5,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 92,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418881252806657\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:02\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:02\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418880996954114\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 4.1,\n" +
-            "        \"inputDose\": 0.9,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418881059868674\",\n" +
-            "        \"modifyTime\": \"2023-03-01 11:11:12\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 11:13:43\",\n" +
-            "    \"startTime\": \"2023-03-01 11:11:12\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418879591862274\",\n" +
-            "    \"createTime\": \"2023-03-11 13:00:01\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 13:00:01\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418879528947716\",\n" +
-            "    \"dataNumber\": 2,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 5,\n" +
-            "    \"inputDose\": 0,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 92,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418879784800257\",\n" +
-            "        \"createTime\": \"2023-03-11 13:00:02\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 13:00:02\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418879528947716\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 5,\n" +
-            "        \"inputDose\": 0,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418879591862274\",\n" +
-            "        \"modifyTime\": \"2023-03-01 11:10:39\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 11:10:41\",\n" +
-            "    \"startTime\": \"2023-03-01 11:10:39\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418827611852803\",\n" +
-            "    \"createTime\": \"2023-03-11 12:59:49\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 12:59:49\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418827611852802\",\n" +
-            "    \"dataNumber\": 7,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 0,\n" +
-            "    \"inputDose\": 5,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 83,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418827867705345\",\n" +
-            "        \"createTime\": \"2023-03-11 12:59:49\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 12:59:49\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418827611852802\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 1.8,\n" +
-            "        \"inputDose\": 3.2,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418827611852803\",\n" +
-            "        \"modifyTime\": \"2023-03-01 10:27:25\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 10:28:34\",\n" +
-            "    \"startTime\": \"2023-03-01 10:27:25\"\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1634418824780697601\",\n" +
-            "    \"createTime\": \"2023-03-11 12:59:48\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": null,\n" +
-            "    \"updateTime\": \"2023-03-11 12:59:49\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"classification\": \"1634418824403210243\",\n" +
-            "    \"dataNumber\": 5,\n" +
-            "    \"type\": {\n" +
-            "      \"value\": 1,\n" +
-            "      \"text\": \"持续型\"\n" +
-            "    },\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"ward\": \"\",\n" +
-            "    \"bedNo\": \"\",\n" +
-            "    \"totalDose\": 5,\n" +
-            "    \"firstDose\": 5,\n" +
-            "    \"remainDose\": 2.7,\n" +
-            "    \"inputDose\": 2.3,\n" +
-            "    \"appendDose\": 0,\n" +
-            "    \"maxDose\": 90,\n" +
-            "    \"selfControlLockTime\": 0,\n" +
-            "    \"selfControlCount\": null,\n" +
-            "    \"pcaValidCount\": 0,\n" +
-            "    \"pcaInvalidCount\": 0,\n" +
-            "    \"pcaTotalCount\": 0,\n" +
-            "    \"continueDose\": 50,\n" +
-            "    \"pulseDose\": null,\n" +
-            "    \"pulseLockTime\": null,\n" +
-            "    \"pulseFirstLockTime\": null,\n" +
-            "    \"flowUpCycle\": null,\n" +
-            "    \"flowDownCycle\": null,\n" +
-            "    \"flowCount\": null,\n" +
-            "    \"flowUpLimit\": null,\n" +
-            "    \"flowDownLimit\": null,\n" +
-            "    \"flowAdjustRate\": null,\n" +
-            "    \"electricQuantity\": 94,\n" +
-            "    \"snr\": null,\n" +
-            "    \"rssi\": null,\n" +
-            "    \"rsrq\": null,\n" +
-            "    \"rsrp\": null,\n" +
-            "    \"modifies\": [\n" +
-            "      {\n" +
-            "        \"id\": \"1634418825099464705\",\n" +
-            "        \"createTime\": \"2023-03-11 12:59:49\",\n" +
-            "        \"createBy\": \"1\",\n" +
-            "        \"updateBy\": \"1\",\n" +
-            "        \"updateTime\": \"2023-03-11 12:59:49\",\n" +
-            "        \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "        \"deviceId\": \"43207937393702B0\",\n" +
-            "        \"classification\": \"1634418824403210243\",\n" +
-            "        \"dataNumber\": 1,\n" +
-            "        \"type\": {\n" +
-            "          \"value\": 1,\n" +
-            "          \"text\": \"持续型\"\n" +
-            "        },\n" +
-            "        \"patientCode\": null,\n" +
-            "        \"ward\": null,\n" +
-            "        \"bedNo\": null,\n" +
-            "        \"totalDose\": 5,\n" +
-            "        \"firstDose\": 5,\n" +
-            "        \"remainDose\": 5,\n" +
-            "        \"inputDose\": 0,\n" +
-            "        \"appendDose\": 0,\n" +
-            "        \"maxDose\": 90,\n" +
-            "        \"selfControlLockTime\": 0,\n" +
-            "        \"selfControlCount\": null,\n" +
-            "        \"pcaValidCount\": 0,\n" +
-            "        \"pcaInvalidCount\": 0,\n" +
-            "        \"pcaTotalCount\": 0,\n" +
-            "        \"continueDose\": 50,\n" +
-            "        \"pulseDose\": null,\n" +
-            "        \"pulseLockTime\": null,\n" +
-            "        \"pulseFirstLockTime\": null,\n" +
-            "        \"flowUpCycle\": null,\n" +
-            "        \"flowDownCycle\": null,\n" +
-            "        \"flowCount\": null,\n" +
-            "        \"flowUpLimit\": null,\n" +
-            "        \"flowDownLimit\": null,\n" +
-            "        \"flowAdjustRate\": null,\n" +
-            "        \"electricQuantity\": null,\n" +
-            "        \"snr\": null,\n" +
-            "        \"rssi\": null,\n" +
-            "        \"rsrq\": null,\n" +
-            "        \"rsrp\": null,\n" +
-            "        \"infusionId\": \"1634418824780697601\",\n" +
-            "        \"modifyTime\": \"2023-03-01 10:25:22\",\n" +
-            "        \"print\": true\n" +
-            "      }\n" +
-            "    ],\n" +
-            "    \"alias\": null,\n" +
-            "    \"print\": true,\n" +
-            "    \"finished\": 1,\n" +
-            "    \"lastUploadTime\": \"2023-03-01 10:26:54\",\n" +
-            "    \"startTime\": \"2023-03-01 10:25:22\"\n" +
-            "  }\n" +
-            "]";
-    private ExcelHelperFactory excelHelperFactory;
-
-    private String pathPrefix="C:\\Users\\JR\\Desktop\\icon\\";
-
-    String evalStr="[\n" +
-            "  {\n" +
-            "    \"id\": \"1639553833044062209\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 5,\n" +
-            "    \"activity\": 4,\n" +
-            "    \"calm\": 2,\n" +
-            "    \"leftArm\": 2,\n" +
-            "    \"leftLeg\": 3,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 3,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 2,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 0,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:01\",\n" +
-            "    \"evaluator\": \"测试人员\",\n" +
-            "    \"shrinkPressure\": 123,\n" +
-            "    \"diastensPressure\": 150,\n" +
-            "    \"heartRate\": 80,\n" +
-            "    \"fetalHeartRate\": 1,\n" +
-            "    \"breathRate\": 12,\n" +
-            "    \"bloodOxygenSaturation\": 1\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1639553955723259905\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 4,\n" +
-            "    \"activity\": 3,\n" +
-            "    \"calm\": 1,\n" +
-            "    \"leftArm\": 3,\n" +
-            "    \"leftLeg\": 2,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 2,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 1,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 2,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:31\",\n" +
-            "    \"evaluator\": \"第二次\",\n" +
-            "    \"shrinkPressure\": 15,\n" +
-            "    \"diastensPressure\": 200,\n" +
-            "    \"heartRate\": 15,\n" +
-            "    \"fetalHeartRate\": 24,\n" +
-            "    \"breathRate\": 156,\n" +
-            "    \"bloodOxygenSaturation\": 23\n" +
-            "  },\n" +
-            "{\n" +
-            "    \"id\": \"1639553833044062209\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 5,\n" +
-            "    \"activity\": 4,\n" +
-            "    \"calm\": 2,\n" +
-            "    \"leftArm\": 2,\n" +
-            "    \"leftLeg\": 3,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 3,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 2,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 0,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:01\",\n" +
-            "    \"evaluator\": \"测试人员\",\n" +
-            "    \"shrinkPressure\": 123,\n" +
-            "    \"diastensPressure\": 150,\n" +
-            "    \"heartRate\": 80,\n" +
-            "    \"fetalHeartRate\": 1,\n" +
-            "    \"breathRate\": 12,\n" +
-            "    \"bloodOxygenSaturation\": 1\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1639553955723259905\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 4,\n" +
-            "    \"activity\": 3,\n" +
-            "    \"calm\": 1,\n" +
-            "    \"leftArm\": 3,\n" +
-            "    \"leftLeg\": 2,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 2,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 1,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 2,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:31\",\n" +
-            "    \"evaluator\": \"第二次\",\n" +
-            "    \"shrinkPressure\": 15,\n" +
-            "    \"diastensPressure\": 200,\n" +
-            "    \"heartRate\": 15,\n" +
-            "    \"fetalHeartRate\": 24,\n" +
-            "    \"breathRate\": 156,\n" +
-            "    \"bloodOxygenSaturation\": 23\n" +
-            "  },\n" +
-            "{\n" +
-            "    \"id\": \"1639553833044062209\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 5,\n" +
-            "    \"activity\": 4,\n" +
-            "    \"calm\": 2,\n" +
-            "    \"leftArm\": 2,\n" +
-            "    \"leftLeg\": 3,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 3,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 2,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 0,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:01\",\n" +
-            "    \"evaluator\": \"测试人员\",\n" +
-            "    \"shrinkPressure\": 123,\n" +
-            "    \"diastensPressure\": 150,\n" +
-            "    \"heartRate\": 80,\n" +
-            "    \"fetalHeartRate\": 1,\n" +
-            "    \"breathRate\": 12,\n" +
-            "    \"bloodOxygenSaturation\": 1\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1639553955723259905\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 4,\n" +
-            "    \"activity\": 3,\n" +
-            "    \"calm\": 1,\n" +
-            "    \"leftArm\": 3,\n" +
-            "    \"leftLeg\": 2,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 2,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 1,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 2,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:31\",\n" +
-            "    \"evaluator\": \"第二次\",\n" +
-            "    \"shrinkPressure\": 15,\n" +
-            "    \"diastensPressure\": 200,\n" +
-            "    \"heartRate\": 15,\n" +
-            "    \"fetalHeartRate\": 24,\n" +
-            "    \"breathRate\": 156,\n" +
-            "    \"bloodOxygenSaturation\": 23\n" +
-            "  },{\n" +
-            "    \"id\": \"1639553833044062209\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:29\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 5,\n" +
-            "    \"activity\": 4,\n" +
-            "    \"calm\": 2,\n" +
-            "    \"leftArm\": 2,\n" +
-            "    \"leftLeg\": 3,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 3,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 2,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 0,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:01\",\n" +
-            "    \"evaluator\": \"测试人员\",\n" +
-            "    \"shrinkPressure\": 123,\n" +
-            "    \"diastensPressure\": 150,\n" +
-            "    \"heartRate\": 80,\n" +
-            "    \"fetalHeartRate\": 1,\n" +
-            "    \"breathRate\": 12,\n" +
-            "    \"bloodOxygenSaturation\": 1\n" +
-            "  },\n" +
-            "  {\n" +
-            "    \"id\": \"1639553955723259905\",\n" +
-            "    \"createTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"createBy\": \"1\",\n" +
-            "    \"updateBy\": \"1\",\n" +
-            "    \"updateTime\": \"2023-03-25 17:04:59\",\n" +
-            "    \"tenantId\": \"43332553109747f3857e1e434e1e2ef3\",\n" +
-            "    \"patientId\": \"1634418824659062786\",\n" +
-            "    \"patientCode\": \"9000000000000\",\n" +
-            "    \"infusionId\": \"1634418903713304577\",\n" +
-            "    \"clinicId\": \"1634418824659062787\",\n" +
-            "    \"deviceId\": \"43207937393702B0\",\n" +
-            "    \"statics\": 4,\n" +
-            "    \"activity\": 3,\n" +
-            "    \"calm\": 1,\n" +
-            "    \"leftArm\": 3,\n" +
-            "    \"leftLeg\": 2,\n" +
-            "    \"rightArm\": 3,\n" +
-            "    \"rightLeg\": 2,\n" +
-            "    \"nauseaVomit\": 2,\n" +
-            "    \"itch\": 3,\n" +
-            "    \"vertigo\": 2,\n" +
-            "    \"soreThroat\": 2,\n" +
-            "    \"uroschesis\": 1,\n" +
-            "    \"breathDepression\": 1,\n" +
-            "    \"hoarseness\": 1,\n" +
-            "    \"cognitionObstacle\": 1,\n" +
-            "    \"other\": null,\n" +
-            "    \"satisfaction\": 2,\n" +
-            "    \"evaluateTime\": \"2023-03-25 17:04:31\",\n" +
-            "    \"evaluator\": \"第二次\",\n" +
-            "    \"shrinkPressure\": 15,\n" +
-            "    \"diastensPressure\": 200,\n" +
-            "    \"heartRate\": 15,\n" +
-            "    \"fetalHeartRate\": 24,\n" +
-            "    \"breathRate\": 156,\n" +
-            "    \"bloodOxygenSaturation\": 23\n" +
-            "  }\n" +
-            "]";
-    @BeforeEach
-    public void setUp(){
-        ObjectMapper objectMapper = new ObjectMapper();
-        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
-        JsonUtils.init(objectMapper);
-    }
-    @Test
-    public void patientInfo() throws Exception {
-
-
-        File file= FileUtil.touch(pathPrefix+"patientTmp.docx");
-        BusClinicEntity clinic = BusClinicEntity
-                .builder()
-                .patientName("张三")
-                .patientCode("100546231")
-                .bedNo("10号床")
-                .patientAge(29)
-                .height("175")
-                .weight("120")
-                .ward("2号病区")
-                .asa("Ⅲ")
-                .anaDoctor("张俊")
-                .anaType("全麻")
-                .surgeryName("股骨骨折切开复位钢板内固定术")
-                .build();
-//        Map<String, Object> exampleData = JsonUtils.parseMap(JsonUtils.toJsonString(clinic));
-        Map<String, Object> exampleData = new HashMap<>();
-        Configure config = Configure.builder()
-                .bind("modifies", new LoopRowTableRenderPolicy())
-                .bind("evaluations",new LoopColumnTableRenderPolicy())
-                .build();
-        String base64= FileUtil.readString("E:\\Project\\tr-footstone\\tr-plugins\\tr-spring-boot-starter-plugin-biz-excel\\src\\main\\resources\\base64", Charset.defaultCharset());
-        exampleData.put("clinic",clinic);
-        exampleData.put("infusionRecords",JSONUtil.parseArray(str));
-        exampleData.put("evaluations",JSONUtil.parseArray(evalStr));
-        exampleData.put("image",Pictures.ofBase64(base64,PictureType.PNG)
-                .size(687, 500).create());
-        NiceXWPFDocument  document=XWPFTemplate.compile(new FileInputStream(file),config)
-                .render(exampleData)
-                .getXWPFDocument();
-//        document=infusionInfo(document);
-//        document=eval(document);
-//        document=image(document,encode);
-        //文件输出流
-        FileOutputStream out = new FileOutputStream(pathPrefix+"patient.docx");
-        BufferedOutputStream bos = new BufferedOutputStream(out);
-        document.write(bos);
-        bos.flush();
-        out.flush();
-        out.close();
-
-        //模板名称
-        //病人信息
-    }
-
-    @Test
-    public NiceXWPFDocument image(NiceXWPFDocument document,String base64) throws Exception {
-        document.createParagraph().createRun().addBreak(BreakType.PAGE);
-        XWPFRun run = document.createParagraph().createRun();
-        base64= FileUtil.readString("E:\\Project\\tr-footstone\\tr-plugins\\tr-spring-boot-starter-plugin-biz-excel\\src\\main\\resources\\base64", Charset.defaultCharset());
-//
-//        run.addPicture(new FileInputStream(pathPrefix+"EXXT.jpg"), XWPFDocument.PICTURE_TYPE_PNG,"输注统计分析图",687,500);
-        byte[] image = Base64.decode(base64);
-        document=document.merge(XWPFTemplate.compile(new FileInputStream(pathPrefix+"imageTmp.docx"))
-                .render(MapUtil.builder()
-                        . put("image", Pictures.ofBase64(base64,PictureType.PNG)
-                                .size(687, 500).create())
-                        .build())
-                .getXWPFDocument());
-        return document;
-    }
-
-
-    @Test
-    public NiceXWPFDocument eval(NiceXWPFDocument xwpfDocument) throws Exception {
-        xwpfDocument.createParagraph().createRun().addBreak(BreakType.PAGE);
-        LoopColumnTableRenderPolicy  policy  = new LoopColumnTableRenderPolicy();
-        File file= FileUtil.touch(pathPrefix+"evalTmp.docx");
-        JSONArray jsonArray = JSONUtil.parseArray(evalStr);
-        Configure config = Configure.builder()
-                .bind("evals", policy)
-                .build();
-
-        xwpfDocument=xwpfDocument.merge(XWPFTemplate.compile(new FileInputStream(file), config).render(MapUtil.builder()
-                .put("evals",jsonArray)
-                .build())
-                .getXWPFDocument());
-        return xwpfDocument;
-    }
-    @Test
-    public  NiceXWPFDocument infusionInfo(NiceXWPFDocument xwpfDocument) throws Exception {
-        xwpfDocument.createParagraph().createRun().addBreak(BreakType.PAGE);
-        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
-        File file= FileUtil.touch(pathPrefix+"infusionHistoryTmp.docx");
-        JSONArray jsonArray = JSONUtil.parseArray(str);
-        Configure config = Configure.builder()
-                .bind("modifies", policy)
-                .build();
-        HashMap<String, JSONArray> infusions = MapUtil.of("infusions", jsonArray);
-        XWPFTemplate compile = XWPFTemplate.compile(new FileInputStream(file), config);
-//        for (Object o : jsonArray) {
-            xwpfDocument=xwpfDocument.merge(compile.render(infusions).getXWPFDocument());
-//        }
-        return xwpfDocument;
-    }
-    @Data
-    @Builder
-    @Accessors(chain = true)
-    static class BusClinicEntity  {
-
-        private String patientName;
-        private String patientCode;
-        private String bedNo;
-        //        private SexEnum patientGender;
-        private Integer patientAge;
-        private String height;
-        private String weight;
-        private String ward;
-        private String asa;
-        private String anaDoctor;
-        private String anaType;
-        //        private FormulaDrugDomain formula;
-        private String surgeryName;
-    }
-
-    @Data
-    @NoArgsConstructor
-    static class ClinicAnalInfusionRecord extends DeviceProperties<String,String> {
-        private List<ClinicAnalInfusionModify> modifies;
-
-        private String alias;
-
-        private boolean print;
-
-        private Boolean finished;
-
-        private Date lastUploadTime;
-
-        private Date startTime;
-    }
-
-    @Data
-    static class ClinicAnalInfusionModify extends DeviceProperties<String,String> {
-        private String infusionId;
-
-        private Date modifyTime;
-
-        private boolean print;
-    }
-
-
-
-
-
-    @Data
-    static class DeviceProperties<K,T>  {
-        private String deviceId;
-
-        private String classification;
-
-        private Integer dataNumber;
-
-
-        private String patientCode;
-
-        private String ward;
-
-        private String bedNo;
-
-        private Integer totalDose;
-
-        private Integer firstDose;
-
-
-        private BigDecimal remainDose;
-
-        private BigDecimal inputDose;
-
-        private BigDecimal appendDose;
-
-//    @ApiModelProperty(value = "公共参数-追加锁时",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
-//    @DecimalMax(value = "99",message = "PCA追加量最大值不得超过99")
-//    @DecimalMin(value = "1",message ="PCA追加量最小值不得低于0" )
-//    private BigDecimal appendLockTime;
-
-        private BigDecimal maxDose;
-
-        private BigDecimal selfControlLockTime;
-
-        private Integer selfControlCount;
-
-        private Integer pcaValidCount;
-
-        private Integer pcaInvalidCount;
-
-        private Integer pcaTotalCount;
-
-        private BigDecimal continueDose;
-
-        private Integer pulseDose;
-
-        private Integer pulseLockTime;
-
-        private Integer pulseFirstLockTime;
-
-        private BigDecimal flowUpCycle;
-
-
-        private BigDecimal flowDownCycle;
-
-        private BigDecimal flowCount;
-
-        private BigDecimal flowUpLimit;
-
-        private BigDecimal flowDownLimit;
-
-        private BigDecimal flowAdjustRate;
-
-        private Integer electricQuantity;
-
-
-        public Integer getPcaTotalCount() {
-            return getPcaInvalidCount()+getPcaValidCount();
-        }
-
-
-        public Integer getPcaValidCount() {
-            return Optional.ofNullable(pcaValidCount).orElse(0);
-        }
-
-
-        public Integer getPcaInvalidCount() {
-            return Optional.ofNullable(pcaInvalidCount).orElse(0);
-        }
-    }
-
-}

+ 55 - 0
tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/handler/ListTypeHandler.java

@@ -0,0 +1,55 @@
+package cn.tr.plugin.mybatis.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.utils.JsonUtils;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+@MappedJdbcTypes(JdbcType.VARCHAR)
+@MappedTypes({List.class})
+@EqualsAndHashCode(callSuper = true)
+public abstract class ListTypeHandler<T> extends BaseTypeHandler<List<T>> {
+ 
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
+        String content = CollUtil.isEmpty(parameter) ? null : JsonUtils.toJsonString(parameter);
+        ps.setString(i, content);
+    }
+ 
+    @Override
+    public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        return this.getListByJsonArrayString(rs.getString(columnName));
+    }
+ 
+    @Override
+    public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return this.getListByJsonArrayString(rs.getString(columnIndex));
+    }
+ 
+    @Override
+    public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return this.getListByJsonArrayString(cs.getString(columnIndex));
+    } 
+ 
+    private List<T> getListByJsonArrayString(String content) {
+        return StrUtil.isBlank(content) ? new ArrayList<>() : JsonUtils.parseArray(content, this.specificType());
+    }
+ 
+    /**
+     * 具体类型,由子类提供
+     *
+     * @return 具体类型
+     */
+    protected abstract Class specificType();
+}

+ 15 - 0
tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/handler/StringListTypeHandler.java

@@ -0,0 +1,15 @@
+package cn.tr.plugin.mybatis.handler;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName StringListTypeHandler.java
+ * @Description TODO
+ * @createTime 2022年08月20日 14:32:00
+ */
+public class StringListTypeHandler extends ListTypeHandler<String> {
+    @Override
+    protected Class specificType() {
+        return String.class;
+    }
+}

+ 1 - 5
tr-test/pom.xml

@@ -58,11 +58,6 @@
             <artifactId>tr-spring-boot-starter-plugin-dict</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-operatelog</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>cn.tr</groupId>
             <artifactId>tr-spring-boot-starter-plugin-doc</artifactId>
@@ -110,6 +105,7 @@
 
 
     <build>
+        <defaultGoal>compile</defaultGoal>
         <finalName>${project.name}</finalName>
         <resources>
             <resource>

+ 1 - 0
tr-test/src/main/resources/application-doc.yml

@@ -16,6 +16,7 @@ knife4j:
       gen:
         group-name: 代码生成器
         api-rule: package
+
         api-rule-resources:
           - cn.tr.module.gen.modular.basic
           - cn.tr.module.gen.modular.config

+ 4 - 1
tr-test/src/main/resources/application.yml

@@ -42,7 +42,10 @@ spring:
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         max-wait: -1ms
   cache:
-    type: caffeine
+    type: redis
+    redis:
+#      7天
+      time-to-live: 604800000
   profiles:
     include: doc
   jackson: