Parcourir la source

Merge branch 'dev' of http://219.151.181.73:3000/zhuwei/bladex into dev

laibulaizheli il y a 2 mois
Parent
commit
2d5648a9d3
65 fichiers modifiés avec 2601 ajouts et 621 suppressions
  1. 1 0
      blade-common/src/main/java/org/springblade/common/constant/ClientIdConstant.java
  2. 2 0
      blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java
  3. 2 1
      blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java
  4. 2 0
      blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java
  5. 4 1
      blade-ops/blade-swagger/src/main/resources/application-dev.yml
  6. 1 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PreviewNodeNameDTO.java
  7. 2 0
      blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PreviewNodeNameDTO1.java
  8. 23 0
      blade-service-api/blade-dingding-api/pom.xml
  9. 14 0
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingSchedule.java
  10. 23 0
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingVo.java
  11. 18 0
      blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/ScheduleItem.java
  12. 126 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/util/DataStructureFormatUtils.java
  13. 6 0
      blade-service-api/blade-websocket-api/pom.xml
  14. 7 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java
  15. 12 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/DingDingMsg.java
  16. 5 0
      blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java
  17. 3 2
      blade-service/blade-business/src/main/java/org/springblade/business/controller/ContractLogController.java
  18. 98 25
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  19. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/NeiWaiYeProgressController.java
  20. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  21. 0 2
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialSummaryController.java
  22. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogMapper.java
  23. 2 2
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogMapper.xml
  24. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.java
  25. 17 3
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml
  26. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/IContractLogService.java
  27. 2 2
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ContractLogServiceImpl.java
  28. 2 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java
  29. 47 0
      blade-service/blade-dingding/pom.xml
  30. 23 0
      blade-service/blade-dingding/src/main/java/org/springblade/DingDingApplication.java
  31. 42 0
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/controller/MeetingController.java
  32. 10 0
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/MeetingService.java
  33. 797 0
      blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/impl/MeetingServiceImpl.java
  34. 15 0
      blade-service/blade-dingding/src/main/resources/application-dev.yml
  35. 15 0
      blade-service/blade-dingding/src/main/resources/application-prod.yml
  36. 15 0
      blade-service/blade-dingding/src/main/resources/application-test.yml
  37. 1 1
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVController.java
  38. 10 20
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java
  39. 286 26
      blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/ScrDataServiceImpl.java
  40. 53 6
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java
  41. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExctabCellController.java
  42. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FirstController.java
  43. 50 4
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/NodeBaseInfoController.java
  44. 1 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TrialSummaryClassificationConfigurationController.java
  45. 4 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java
  46. 2 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ExcelTabClientImpl.java
  47. 5 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ExcelTabMapper.xml
  48. 3 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml
  49. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java
  50. 223 159
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java
  51. 5 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
  52. 3 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ServicePlanServiceImpl.java
  53. 169 192
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java
  54. 1 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsParamServiceImpl.java
  55. 102 117
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsSynchronousServiceImpl.java
  56. 103 24
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java
  57. 13 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeServiceImpl.java
  58. 8 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/PdfAddimgUtil.java
  59. 12 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/RandomNumberHolder.java
  60. 114 11
      blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java
  61. 2 2
      blade-service/blade-repair/src/main/java/org/springblade/repair/controller/CheckAndRepairController.java
  62. 9 0
      blade-service/blade-websocket/pom.xml
  63. 12 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java
  64. 62 0
      blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java
  65. 2 0
      pom.xml

+ 1 - 0
blade-common/src/main/java/org/springblade/common/constant/ClientIdConstant.java

@@ -10,4 +10,5 @@ public interface ClientIdConstant {
     String METER_ID = "measure";
     String CLIENT_ID = "client";
     String ARCHIVE_ID = "archives";
+    String DINGDING_ID = "dingding";
 }

+ 2 - 0
blade-common/src/main/java/org/springblade/common/constant/LauncherConstant.java

@@ -80,6 +80,8 @@ public interface LauncherConstant {
 
     String  APPLICATION_REPAIR_NAME = APPLICATION_NAME_PREFIX + "repair";
 
+    String  APPLICATION_DingDing_NAME = APPLICATION_NAME_PREFIX + "dingding";
+
 
     /**
      * nacos dev 地址 215==172.31.222.127   192.168.0.109     127.0.0.1  210-=-172.30.224.81

+ 2 - 1
blade-common/src/main/java/org/springblade/common/constant/WebsocketMsgConstant.java

@@ -18,7 +18,8 @@ public interface WebsocketMsgConstant {
     String MSG_COUNT_DOWN = "msgCountDown";
     //客户端从服务器获取公告
     String GET_MSG = "getMsg";
-
+    //获取会议列表
+    String MSG_MEETING_LIST = "meetingList";
     /**
      * 单个系统标识
      */

+ 2 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java

@@ -66,6 +66,8 @@ public class AuthProvider {
         DEFAULT_SKIP_URL.add("/getPk"); //成渝第三方登录获取公钥
         DEFAULT_SKIP_URL.add("/getQualityTestingToken"); //成渝第三方登录获取质检系统tokne
         DEFAULT_SKIP_URL.add("/getArchiveToken"); //成渝第三方登录获取档案系统tokne
+        DEFAULT_SKIP_URL.add("/meeting/**");//DingDing会议接口
+
     }
 
     /**

+ 4 - 1
blade-ops/blade-swagger/src/main/resources/application-dev.yml

@@ -30,4 +30,7 @@ knife4j:
         location: /blade-land/v2/api-docs
       - name: 计量接口
         uri: 127.0.0.1:8090
-        location: /blade-meter/v2/api-docs
+        location: /blade-meter/v2/api-docs
+      - name: 钉钉接口
+        uri: 127.0.0.1:8090
+        location: /blade-dingding/v2/api-docs

+ 1 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PreviewNodeNameDTO.java

@@ -4,6 +4,7 @@ import lombok.Data;
 
 @Data
 public class PreviewNodeNameDTO {
+    private Long id;
     private Long wbsId;
     private Long projectId;
 }

+ 2 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/dto/PreviewNodeNameDTO1.java

@@ -4,6 +4,8 @@ import lombok.Data;
 
 @Data
 public class PreviewNodeNameDTO1 {
+    private Long id;
     private String wbsId;
     private String nameRule;
+    private Long projectId;
 }

+ 23 - 0
blade-service-api/blade-dingding-api/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>blade-service-api</artifactId>
+        <groupId>org.springblade</groupId>
+        <version>2.9.1.RELEASE</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>blade-dingding-api</artifactId>
+    <name>${project.artifactId}</name>
+    <version>${bladex.project.version}</version>
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+        </dependency>
+    </dependencies>
+    <packaging>jar</packaging>
+
+</project>

+ 14 - 0
blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingSchedule.java

@@ -0,0 +1,14 @@
+package org.springblade.dingding.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MeetingSchedule {
+    private String meetingId;
+    private String reservationTime; //预约时间
+    private String reservationDept;
+}

+ 23 - 0
blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/MeetingVo.java

@@ -0,0 +1,23 @@
+package org.springblade.dingding.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class MeetingVo {
+    private String roomId;
+    private String fixedData; //固定数据
+    private String floor; //楼层
+    private String meetingTheme; //会议主题
+    private String meetingDept;  //召开部门
+    private String meetingBooker;//会议预定者,主持人
+    private String participants; //参会人员
+    private String meetingTime; //会议时间
+    private Integer status; //会议时间 1空闲中 2会议中
+    private Integer meetingSession; //今日会议场次
+    private List<MeetingSchedule> meetings; //今日预定会议场次详情
+}

+ 18 - 0
blade-service-api/blade-dingding-api/src/main/java/org/springblade/dingding/vo/ScheduleItem.java

@@ -0,0 +1,18 @@
+package org.springblade.dingding.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ScheduleItem {
+    private String eventId;
+    private String status;
+    private String organizerId;
+    private String startDateTime;
+    private String startTimeZone;
+    private String endDateTime;
+    private String endTimeZone;
+}

+ 126 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/util/DataStructureFormatUtils.java

@@ -0,0 +1,126 @@
+package org.springblade.manager.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * key:value$$key:value$$key:value
+ * 简单数据结构转换工具类
+ */
+public class DataStructureFormatUtils {
+
+    /**
+     * 将Map转换为自定义字符串格式
+     * @param map 输入的键值对映射
+     * @return 格式化后的字符串
+     */
+    public static String buildData(Map<String, String> map) {
+        if (map == null || map.isEmpty()) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            // 转义特殊字符以避免解析错误
+            String key = escapeSpecialChars(entry.getKey());
+            String value = escapeSpecialChars(entry.getValue());
+            sb.append(key).append(":").append(value).append("$$");
+        }
+        // 移除最后的分隔符
+        if (sb.length() > 0) {
+            sb.setLength(sb.length() - 2);
+        }
+        return sb.toString();
+    }
+
+    public static String buildDataObject(Map<String, Object> map) {
+        if (map == null || map.isEmpty()) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            // 转义特殊字符以避免解析错误
+            String key = escapeSpecialChars(entry.getKey());
+            Object obj = entry.getValue();
+            if (obj == null) {
+                continue;
+            }
+            String value = escapeSpecialChars(obj + "");
+            sb.append(key).append(":").append(value).append("$$");
+        }
+        // 移除最后的分隔符
+        if (sb.length() > 0) {
+            sb.setLength(sb.length() - 2);
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * 将自定义字符串格式解析为Map
+     * @param dataStr 格式化字符串
+     * @return 键值对映射
+     */
+    public static Map<String, String> parseDataByKey(String dataStr) {
+        Map<String, String> map = new HashMap<>();
+        if (dataStr == null || dataStr.isEmpty()) {
+            return map;
+        }
+        String[] pairs = dataStr.split("\\$\\$");
+        if (pairs.length == 1 && !pairs[0].contains(":")) {
+            map.put("key_201", pairs[0]);
+            return map;
+        }
+        for (String pair : pairs) {
+            int index = pair.indexOf(':');
+            if (index > 0) {
+                String key = unescapeSpecialChars(pair.substring(0, index));
+                String value = unescapeSpecialChars(pair.substring(index + 1));
+                map.put(key, value);
+            }
+        }
+        return map;
+    }
+
+
+    /**
+     * 解析Map中 key_201 的自定义字符串格式,添加到Map中,并移除原有的key_201
+     * @param map 输入的键值对映射
+     * @return 键值对映射
+     */
+    public static void parseDataByKey(Map<String, Object> map) {
+        if (map == null || map.isEmpty() || !map.containsKey("key_201")) {
+            return ;
+        }
+        Object obj = map.get("key_201");
+        if (obj instanceof String) {
+            Map<String, String> map1 = parseDataByKey((String) obj);
+            map.remove("key_201");
+            map.putAll(map1);
+        }
+    }
+
+    public static void parseDataByKey(List<Map<String, Object>> map) {
+        if (map == null || map.isEmpty()) {
+            return ;
+        }
+        for (Map<String, Object> map1 : map) {
+            parseDataByKey(map1);
+        }
+    }
+    
+    /**
+     * 转义特殊字符
+     */
+    private static String escapeSpecialChars(String str) {
+        if (str == null) return null;
+        return str.replace("\\", "\\\\").replace(":", "\\:").replace("$$", "\\$\\$");
+    }
+    
+    /**
+     * 恢复转义的字符
+     */
+    private static String unescapeSpecialChars(String str) {
+        if (str == null) return null;
+        return str.replace("\\$\\$", "$$").replace("\\:", ":").replace("\\\\", "\\");
+    }
+}

+ 6 - 0
blade-service-api/blade-websocket-api/pom.xml

@@ -20,6 +20,12 @@
             <groupId>org.springblade</groupId>
             <artifactId>blade-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <properties>

+ 7 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/feign/WebSocketClient.java

@@ -1,11 +1,15 @@
 package org.springblade.websocket.feign;
 
 import org.springblade.common.constant.LauncherConstant;
+import org.springblade.dingding.vo.MeetingVo;
+import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 /**
  * @Param
  * @Author wangwl
@@ -25,4 +29,7 @@ public interface WebSocketClient {
      */
     @PostMapping(value = "/socket/sendSystemMsg")
     void sendSystemMsg(@RequestBody SystMsgVO vo);
+
+    @PostMapping(value = "/socket/sendDingDingMsg")
+    void sendDingDingMsg(@RequestBody UserInfoVO vo);
 }

+ 12 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/DingDingMsg.java

@@ -0,0 +1,12 @@
+package org.springblade.websocket.vo;
+
+import lombok.Data;
+import org.springblade.dingding.vo.MeetingVo;
+
+import java.util.List;
+
+@Data
+public class DingDingMsg {
+    private String msgType;
+    private List<MeetingVo> data;
+}

+ 5 - 0
blade-service-api/blade-websocket-api/src/main/java/org/springblade/websocket/vo/UserInfoVO.java

@@ -2,8 +2,10 @@ package org.springblade.websocket.vo;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import org.springblade.dingding.vo.MeetingVo;
 
 import java.io.Serializable;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -32,6 +34,9 @@ public class UserInfoVO implements Serializable {
     @ApiModelProperty("公告类型1维护2普通,拼接字符串")
     private String msgType;
 
+    @ApiModelProperty("传输数据信息")
+    private List<MeetingVo> object;
+
     public UserInfoVO() {
     }
 

+ 3 - 2
blade-service/blade-business/src/main/java/org/springblade/business/controller/ContractLogController.java

@@ -28,6 +28,7 @@ import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.boot.ctrl.BladeController;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.AuthUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
@@ -396,8 +397,8 @@ public class ContractLogController extends BladeController {
     @PostMapping("/getSubmitLogDateList")
     @ApiOperationSupport(order = 6)
     @ApiOperation(value = "获取合同段当前日志节点下的填报日期记录")
-    public R<List<String>> getSubmitLogDateList(@RequestParam String contractId, @RequestParam String primaryKeyId, @RequestParam String year) {
-        return R.data(this.contractLogService.getSubmitLogDateList(contractId, primaryKeyId, year));
+    public R<List<String>> getSubmitLogDateList(@RequestParam String contractId, @RequestParam String primaryKeyId, @RequestParam String year, BladeUser user) {
+        return R.data(this.contractLogService.getSubmitLogDateList(contractId, primaryKeyId, year, user.getUserId()+""));
     }
 
     /**

+ 98 - 25
blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java

@@ -62,6 +62,7 @@ import org.springblade.manager.dto.RangeInfo;
 import org.springblade.manager.dto.RangeJson;
 import org.springblade.manager.entity.*;
 import org.springblade.manager.feign.*;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.vo.NameRuleVo;
 import org.springblade.manager.vo.WbsTreeContractTreeVOS;
 import org.springblade.manager.vo.WbsTreeContractVO8;
@@ -234,16 +235,7 @@ public class InformationWriteQueryController extends BladeController {
                 String sql="select * from m_wbs_tree_contract where p_key_id="+query.getWbsId()+" and is_deleted=0";
                 WbsTreeContract contract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
                 if(dto.getType()==1){
-                    R<List<String>>  nameRuleList = wbsParamClient.getNameRuleByPkeyId(contract.getPKeyId(), Long.valueOf(contract.getProjectId()));
-                    String nameRule = "";
-                    if (nameRuleList != null && nameRuleList.getData() != null && !nameRuleList.getData().isEmpty()) {
-                        nameRule = String.join("-", nameRuleList.getData());
-                    }
-                    if(projectInfos.get(0)!=null&&projectInfos.get(0).getTemplateType()==2){
-                        result  = nodeBaseInfoServiceClient.getNameRuleByRule(nameRule, contract.getPKeyId()+"");
-                    }else {
-                        result=wbsParamClient.createFileTitle(contract);
-                    }
+                    result=wbsParamClient.createFileTitle(contract);
                 }else {
                     result=nodeNameMap.get(query.getId());
                     //同时修改工程划分节点命名规则
@@ -252,13 +244,20 @@ public class InformationWriteQueryController extends BladeController {
                     }
                 }
                 if(contract!=null&&contract.getMajorDataType()!=null&&contract.getMajorDataType()==4){
+                    if(result==null){
+                        result="";
+                    }
                     if(query.getClassify()!=null&&query.getClassify()==1&&StringUtils.isNotEmpty(sgSuffix)){
-                        result=result+sgSuffix;
+                        if(!result.contains(sgSuffix)){
+                            result=result+sgSuffix;
+                        }
                         if(!query.getName().equals(result)){
                             query.setName(result);
                         }
                     }else if(query.getClassify()!=null&&query.getClassify()==2&&StringUtils.isNotEmpty(jlSuffix)){
-                        result=result+jlSuffix;
+                        if(!result.contains(jlSuffix)){
+                            result=result+jlSuffix;
+                        }
                         if(!query.getName().equals(result)){
                             query.setName(result);
                         }
@@ -405,17 +404,37 @@ public class InformationWriteQueryController extends BladeController {
     })
     public R<List<PreviewNodeNameVO1>> previewNodeName(@RequestBody List<PreviewNodeNameDTO1>dtos){
         List<PreviewNodeNameVO1> list = new ArrayList<>();
+        String sql1="Select sg_suffix,jl_suffix,template_type from m_project_info where id="+dtos.get(0).getProjectId()+" and is_deleted=0";
+        List<ProjectInfo> projectInfos = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(ProjectInfo.class));
+        String sgSuffix="";
+        String jlSuffix="";
+        if(projectInfos.size()>0){
+            sgSuffix=projectInfos.get(0).getSgSuffix()==null?"":projectInfos.get(0).getSgSuffix();
+            jlSuffix=projectInfos.get(0).getJlSuffix()==null?"":projectInfos.get(0).getJlSuffix();
+        }
         for (PreviewNodeNameDTO1 dto1 : dtos) {
             if(StringUtils.isEmpty(dto1.getNameRule())){
                 throw new ServiceException("请输入题名规则");
             }
-           String result=nodeBaseInfoServiceClient.getNameRuleByRule(dto1.getNameRule(),dto1.getWbsId());
-//            String sql="select p_key_id,ancestors_p_id from m_wbs_tree_contract where p_key_id="+dto1.getWbsId()+" and is_deleted=0";
-//            WbsTreeContract contract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
-//            String result="";
-//            if(contract!=null){
-//                result= createFileTitle(contract, dto1.getNameRule());
-//            }
+//           String result=nodeBaseInfoServiceClient.getNameRuleByRule(dto1.getNameRule(),dto1.getWbsId());
+            String sql="select p_key_id,ancestors_p_id,major_data_type,table_owner from m_wbs_tree_contract where p_key_id="+dto1.getWbsId()+" and is_deleted=0";
+            WbsTreeContract contract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            String sql2="select IFNULL(classify,0) from u_information_query where id="+dto1.getId();
+            Integer classify = jdbcTemplate.queryForObject(sql2, Integer.class);
+            String result="";
+           if(contract!=null){
+                result= createFileTitle(contract, dto1.getNameRule());
+               if(contract!=null&&contract.getMajorDataType()!=null&&contract.getMajorDataType()==4){
+                   if(result==null){
+                       result="";
+                   }
+                   if(classify==1&&StringUtils.isNotEmpty(sgSuffix)){
+                       result=result+sgSuffix;
+                   }else if(classify==2&&StringUtils.isNotEmpty(jlSuffix)){
+                       result=result+jlSuffix;
+                   }
+               }
+            }
             list.add(new PreviewNodeNameVO1(dto1.getWbsId(),result.toString()));
         }
         return R.data(list);
@@ -427,11 +446,34 @@ public class InformationWriteQueryController extends BladeController {
         List<PreviewNodeNameVO>list=new ArrayList<>();
         for (PreviewNodeNameDTO dto : dtos) {
             List<String> nameRules = getNameRuleByPkeyId(dto.getWbsId(), dto.getProjectId());
-            String sql="select p_key_id,ancestors_p_id from m_wbs_tree_contract where p_key_id="+dto.getWbsId()+" and is_deleted=0";
+            String sql="select p_key_id,ancestors_p_id,major_data_type from m_wbs_tree_contract where p_key_id="+dto.getWbsId()+" and is_deleted=0";
             WbsTreeContract contract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            String sql2="select IFNULL(classify,0) from u_information_query where id="+dto.getId();
+            Integer classify = jdbcTemplate.queryForObject(sql2, Integer.class);
             String result="";
             if(nameRules!=null){
-                result = nodeBaseInfoServiceClient.getNameRuleByRule(String.join("-", nameRules), contract.getPKeyId() + "");
+                result= createFileTitle(contract, String.join("-", nameRules));
+                //result = nodeBaseInfoServiceClient.getNameRuleByRule(String.join("-", nameRules), contract.getPKeyId() + "");
+                if(contract!=null){
+                    String sql1="Select sg_suffix,jl_suffix,template_type from m_project_info where id="+dtos.get(0).getProjectId()+" and is_deleted=0";
+                    List<ProjectInfo> projectInfos = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(ProjectInfo.class));
+                    String sgSuffix="";
+                    String jlSuffix="";
+                    if(projectInfos.size()>0){
+                        sgSuffix=projectInfos.get(0).getSgSuffix()==null?"":projectInfos.get(0).getSgSuffix();
+                        jlSuffix=projectInfos.get(0).getJlSuffix()==null?"":projectInfos.get(0).getJlSuffix();
+                    }
+                    if(contract!=null&&contract.getMajorDataType()!=null&&contract.getMajorDataType()==4){
+                        if(result==null){
+                            result="";
+                        }
+                        if(classify==1&&StringUtils.isNotEmpty(sgSuffix)){
+                            result=result+sgSuffix;
+                        }else if(classify==2&&StringUtils.isNotEmpty(jlSuffix)){
+                            result=result+jlSuffix;
+                        }
+                    }
+                }
             }
             list.add(new PreviewNodeNameVO(dto.getWbsId(),result,nameRules));
         }
@@ -1249,6 +1291,9 @@ public class InformationWriteQueryController extends BladeController {
                             oldHtml.setId(SnowFlakeUtil.getId());
                             oldHtml.setCreateUser(getUser().getUserId());
                             String htmlUrl = wbsTreeContract.getHtmlUrl();
+                            if (htmlUrl ==  null || htmlUrl.isEmpty()|| "null".equals(htmlUrl)) {
+                                continue;
+                            }
                             // 获取或下载文件
                             Path sourcePath = FileUtils.getOrDownloadFile(htmlUrl);
                             // 生成副本路径
@@ -2727,6 +2772,30 @@ private String reviseCols(Map<String, String> p2, String cols, Long pkeyId, Stri
                 Map<String, Object> origin = listMaps.get(0);
                 List<String> target = Arrays.stream(cols.split(",")).collect(Collectors.toList());
                 List<String> colsList = target.stream().filter(k -> k.startsWith("key")).collect(Collectors.toList());
+                Object key201 = origin.get("key_201");
+                if (key201 instanceof String) {
+                    Map<String, String> map = DataStructureFormatUtils.parseDataByKey(key201.toString());
+                    origin.remove("key_201");
+                    Map<String, Object> map1 = new HashMap<>();
+                    for (String k : colsList) {
+                        if (p2.containsKey(k)) {
+                            Object value = reviseValue(p2, k, map.get(k), pkeyId);
+                            if (value != null) {
+                                if (value.toString().contains("_^_")) {
+                                    map1.put(k, value);
+                                } else {
+                                    map1.put(k, StringPool.NULL);
+                                }
+                            }
+                        }
+                    }
+                    if (!map1.isEmpty()) {
+                        int i = target.indexOf("key_201");
+                        if (i >= 0) {
+                            target.set(i, " '" + DataStructureFormatUtils.buildDataObject(map1) + "' ");
+                        }
+                    }
+                }
                 for (String k : colsList) {
                     if (p2.containsKey(k)) {
 //                        Object value = reviseValue(p2, k, origin.get(k));
@@ -2741,6 +2810,7 @@ private String reviseCols(Map<String, String> p2, String cols, Long pkeyId, Stri
                         }
                     }
                 }
+
                 cols = String.join(",", target);
             }
         }
@@ -4091,11 +4161,11 @@ public R<Boolean> saveContractTreeNode(@RequestBody AddContractTreeNodeVO vo) {
                 WbsTreeContract newData = new WbsTreeContract();
                 BeanUtils.copyProperties(half, newData);
 
-            //重塑pKeyId、id和parentId
-            newData.setPKeyId(OldPKeyIdToNewPKeyIdMap.get(half.getPKeyId()));
-            if (new Integer("1").equals(half.getType())) {
+              //重塑pKeyId、id和parentId
+              newData.setPKeyId(OldPKeyIdToNewPKeyIdMap.get(half.getPKeyId()));
+              if (new Integer("1").equals(half.getType())) {
                 newData.setId(OldIdToNewIdMap.containsKey(half.getId()) ? OldIdToNewIdMap.get(half.getId()) : SnowFlakeUtil.getId());
-            }
+              }
 
                 //设置父级id
                 boolean var = true;
@@ -4391,6 +4461,9 @@ public void updateTextDictInfos(List<WbsTreeContract> nowTabs, List<Long> oldTab
                 nowTab.setExcelId(tab.getExcelId());
                 nowTab.setIsTypePrivatePid(tab.getPKeyId());
                 nowTab.setInitTableName(tab.getInitTableName());
+                if(nowTab.getHtmlUrl()==null||nowTab.getHtmlUrl().equals("null")){
+                    nowTab.setHtmlUrl("");
+                }
                 String updateSql = "update m_wbs_tree_contract set html_url = '" + nowTab.getHtmlUrl() + "',excel_id = " + nowTab.getExcelId() + ",init_table_name = '" + nowTab.getInitTableName() + "',is_type_private_pid = " + nowTab.getIsTypePrivatePid() + " where p_key_id = " + nowTab.getPKeyId();
                 resultSQL.add(updateSql);
             }

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/NeiWaiYeProgressController.java

@@ -76,7 +76,7 @@ public class NeiWaiYeProgressController {
                     queryProcessDataVOList.addAll(this.informationQueryService.queryProcessDataByParentIdAndContractId2(contract.getId().toString(), classFy, contractId));
                 }
 
-            } else if (!new Integer("6").equals(node.getNodeType()) && !Arrays.asList("1,2,3,4".split(",")).contains(node.getMajorDataType().toString())) {
+            } else if (!new Integer("6").equals(node.getNodeType()) &&(node.getMajorDataType() == null || !Arrays.asList("1,2,3,4".split(",")).contains(node.getMajorDataType().toString()))) {
                 //查询出节点下所有填报节点
 //                List<WbsTreeContract> list = this.wbsTreeContractClient.getAllChildren(node.getId(), Long.parseLong(node.getContractId()));
 //                List<Long> keys = list.stream().map(l -> l.getPKeyId()).collect(Collectors.toList());

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java

@@ -1884,7 +1884,7 @@ public class TaskController extends BladeController {
             for (TaskParallel taskParallel : taskApproveUserNamesList) {
                 String eVisaContent = taskParallel.getEVisaContent();
                 if(ObjectUtil.isNotEmpty(eVisaContent) && eVisaContent.contains("当前等待电签的批次较多")){
-                    String sql = "INSERT INTO  `u_task_batch` (id,json_data,create_user,update_user,nick_name)VALUES("+i+",'{\"approvalFileList\":[],\"approvalType\":"+businessTaskPageVO.getApprovalType()+",\"comment\":\"OK\",\"flag\":\"OK\",\"formDataId\":\""+businessTaskPageVO.getFormDataId()+"\",\"parallelProcessInstanceId\":\""+taskParallel.getParallelProcessInstanceId()+"\",\"pass\":true,\"taskId\":\""+businessTaskPageVO.getTaskId()+"\"}',"+taskParallel.getTaskUser()+","+taskParallel.getTaskUser()+",'"+taskParallel.getTaskUserName()+"')";
+                    String sql = "INSERT INTO  `u_task_batch` (id,json_data,create_user,update_user,nick_name,update_time)VALUES("+i+",'{\"approvalFileList\":[],\"approvalType\":"+businessTaskPageVO.getApprovalType()+",\"comment\":\"OK\",\"flag\":\"OK\",\"formDataId\":\""+businessTaskPageVO.getFormDataId()+"\",\"parallelProcessInstanceId\":\""+taskParallel.getParallelProcessInstanceId()+"\",\"pass\":true,\"taskId\":\""+businessTaskPageVO.getTaskId()+"\"}',"+taskParallel.getTaskUser()+","+taskParallel.getTaskUser()+",'"+taskParallel.getTaskUserName()+"',SYSDATE())";
                     jdbcTemplate.execute(sql);
                     i++;
                 }

+ 0 - 2
blade-service/blade-business/src/main/java/org/springblade/business/controller/TrialSummaryController.java

@@ -321,8 +321,6 @@ public class TrialSummaryController {
                  }
              }
 
-
-
             String htmlString = this.html(classC.getHtmlUrl());
             Map<String, String> indexMap = this.indexMap(htmlString, map2);
 

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogMapper.java

@@ -34,7 +34,7 @@ public interface ContractLogMapper extends BaseMapper<ContractLog> {
 
     List<String> queryReportLogTimeTree(@Param("contractId") String contractId, @Param("nodePrimaryKeyId") String nodePrimaryKeyId);
 
-    List<String> getSubmitLogDateList(@Param("contractId") String contractId, @Param("primaryKeyId") String primaryKeyId, @Param("year") String year);
+    List<String> getSubmitLogDateList(@Param("contractId") String contractId, @Param("primaryKeyId") String primaryKeyId, @Param("year") String year,@Param("userId") String userId);
 
     List<ContractLog> queryFillUser(@Param("vo") ContractLogVO vo);
 

+ 2 - 2
blade-service/blade-business/src/main/java/org/springblade/business/mapper/ContractLogMapper.xml

@@ -72,8 +72,8 @@
         from u_contract_log
         where is_deleted = 0
           and wbs_node_id = #{primaryKeyId}
-          and contract_id =
-              #{contractId}
+          and contract_id = #{contractId}
+          and create_user = #{userId}
           and record_time like concat('%', #{year}, '%')
         group by record_time
         order by record_time DESC

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.java

@@ -151,5 +151,5 @@ public interface InformationQueryMapper extends BaseMapper<InformationQuery> {
 
     int addCheckPdfInfoByIds(@Param("ids") List<String> ids,@Param("classify") String classify);
 
-    ChekPdfPaceVo getCheckPdfPaceInfo(@Param("contractId") String contractI, @Param("classify") String classify);
+    ChekPdfPaceVo getCheckPdfPaceInfo(@Param("contractId") String contractId, @Param("classify") String classify);
 }

+ 17 - 3
blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml

@@ -1024,10 +1024,24 @@
     </update>
 
 
+<!--    <select id="getCheckPdfPaceInfo" resultType="org.springblade.business.vo.ChekPdfPaceVo">-->
+<!--          SELECT c.TotalCount,c.finishCount, IF(FLOOR(finishCount/TotalCount),null,0) as pace from (-->
+<!--             SELECT COUNT(1) as TotalCount,IF(SUM(IF(status = 'chek_status', 1, 0)),null,0) AS finishCount from u_information_query where contract_id=#{contractId} and classify=#{classify} and chek_status in(1,2,3)-->
+<!--          ) c-->
+<!--    </select>-->
+
     <select id="getCheckPdfPaceInfo" resultType="org.springblade.business.vo.ChekPdfPaceVo">
-        SELECT c.TotalCount,c.finishCount, IF(FLOOR(finishCount/TotalCount),null,0) as pace from (
-           SELECT COUNT(1) as TotalCount,IF(SUM(IF(status = 'chek_status', 1, 0)),null,0) AS finishCount from u_information_query where contract_id=#{contractId} and classify=#{classify} and chek_status in(1,2,3)
-        ) c
+        SELECT
+            COUNT(1) as totalCount,
+            SUM(CASE WHEN chek_status IN (1,2,3) THEN 1 ELSE 0 END) as finishCount,
+            CASE
+                WHEN COUNT(1) = 0 THEN 0
+                ELSE ROUND(SUM(CASE WHEN chek_status IN (1,2,3) THEN 1 ELSE 0 END) * 100.0 / COUNT(1), 2)
+                END as pace
+        FROM u_information_query
+        WHERE contract_id = #{contractId,jdbcType=VARCHAR}
+          AND classify = #{classify,jdbcType=VARCHAR}
+          AND chek_status IN (0,1,2,3)
     </select>
 
 </mapper>

+ 1 - 1
blade-service/blade-business/src/main/java/org/springblade/business/service/IContractLogService.java

@@ -38,7 +38,7 @@ public interface IContractLogService extends BaseService<ContractLog> {
 
     List<FileUserVO> queryFillUser(ContractLogVO logVO);
 
-    List<String> getSubmitLogDateList(String contractId, String primaryKeyId, String year);
+    List<String> getSubmitLogDateList(String contractId, String primaryKeyId, String year,String userId);
 
     /**
      * 施工日志分页

+ 2 - 2
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ContractLogServiceImpl.java

@@ -95,8 +95,8 @@ public class ContractLogServiceImpl extends BaseServiceImpl<ContractLogMapper, C
     }
 
     @Override
-    public List<String> getSubmitLogDateList(String contractId, String primaryKeyId, String year) {
-        return this.baseMapper.getSubmitLogDateList(contractId, primaryKeyId, year);
+    public List<String> getSubmitLogDateList(String contractId, String primaryKeyId, String year,String userId) {
+        return this.baseMapper.getSubmitLogDateList(contractId, primaryKeyId, year,userId);
     }
 
     @Override

+ 2 - 1
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/TaskServiceImpl.java

@@ -656,6 +656,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
                     }
                     taskBatch.setNickName(nickName);
                     taskBatch.setCreateTime(new Date());
+                    taskBatch.setUpdateTime(new Date());
                     taskList.add(taskBatch);
                     //设置委托单的状态
                     try {
@@ -2260,7 +2261,7 @@ public class TaskServiceImpl extends BaseServiceImpl<TaskMapper, Task> implement
         String sqlForTaskPall = "UPDATE u_task_parallel a  set a.`status`=2 , a.e_visa_status=1 ,a.e_visa_content='电签成功' where a.process_instance_id in(select process_instance_id  from u_task b  where b.form_data_id in( " + ids2 + ") and b.status in(0,1,2) and b.is_deleted = 0)  and a.`status` in(0,1)";
 
         String taskBtech = "insert into u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name,sign_format,sign_type)  " +
-                " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.approval_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,a.update_time,1 as status,0 as is_deleted,a.task_user_name as nick_name ,1 as sign_format,1 as sign_type from u_task_parallel a,u_task b where b.`status` in(1,2) and a.`status` in(2)  and   a.process_instance_id=b.process_instance_id " +
+                " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.approval_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,SYSDATE(),1 as status,0 as is_deleted,a.task_user_name as nick_name ,1 as sign_format,1 as sign_type from u_task_parallel a,u_task b where b.`status` in(1,2) and a.`status` in(2)  and   a.process_instance_id=b.process_instance_id " +
                 " and b.form_data_id in( " + ids2 + ") and a.parallel_process_instance_id not in(SELECT JSON_EXTRACT(c.json_data, '$.parallelProcessInstanceId') from u_task_batch c)";
 
         if(userIds!=null && userIds.length()>=1){

+ 47 - 0
blade-service/blade-dingding/pom.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springblade</groupId>
+        <artifactId>BladeX</artifactId>
+        <version>2.9.1.RELEASE</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>blade-dingding</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-boot</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-swagger</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-websocket-api</artifactId>
+            <version>2.9.1.RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+</project>

+ 23 - 0
blade-service/blade-dingding/src/main/java/org/springblade/DingDingApplication.java

@@ -0,0 +1,23 @@
+package org.springblade;
+
+
+import org.springblade.common.constant.LauncherConstant;
+import org.springblade.core.cloud.feign.EnableBladeFeign;
+import org.springblade.core.launch.BladeApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.client.SpringCloudApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+
+/**
+ * 客户端启动类
+ */
+@EnableBladeFeign
+@SpringCloudApplication
+@EnableAsync
+@EnableCaching
+public class DingDingApplication {
+    public static void main(String[] args) {
+        BladeApplication.run(LauncherConstant.APPLICATION_DingDing_NAME, DingDingApplication.class, args);
+    }
+}

+ 42 - 0
blade-service/blade-dingding/src/main/java/org/springblade/dingding/controller/MeetingController.java

@@ -0,0 +1,42 @@
+package org.springblade.dingding.controller;
+
+import io.swagger.annotations.Api;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.tool.api.R;
+import org.springblade.dingding.service.MeetingService;
+import org.springblade.dingding.vo.MeetingVo;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@AllArgsConstructor
+@RequestMapping("/meeting")
+@Api(value = "钉钉会议接口", tags = "钉钉会议接口")
+public class MeetingController extends BladeController {
+
+  private final MeetingService meetingService;
+
+
+
+
+  @Scheduled(cron = "0 * * * * ?")
+  public void scheduledMeetingInfo() {
+    try {
+      meetingService.getMeetingInfo();
+      System.out.println("定时任务执行完成");
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  @GetMapping("/getMeetingInfo")
+  public R<List<MeetingVo>> getMeetingInfo(){
+    return R.data(meetingService.getMeetingInfo());
+  }
+
+}

+ 10 - 0
blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/MeetingService.java

@@ -0,0 +1,10 @@
+package org.springblade.dingding.service;
+
+import org.springblade.core.tool.api.R;
+import org.springblade.dingding.vo.MeetingVo;
+
+import java.util.List;
+
+public interface MeetingService {
+    List<MeetingVo> getMeetingInfo();
+}

+ 797 - 0
blade-service/blade-dingding/src/main/java/org/springblade/dingding/service/impl/MeetingServiceImpl.java

@@ -0,0 +1,797 @@
+package org.springblade.dingding.service.impl;
+
+import cn.hutool.system.UserInfo;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.nacos.shaded.com.google.gson.JsonElement;
+import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
+import com.alibaba.nacos.shaded.com.google.gson.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.springblade.common.constant.WebsocketMsgConstant;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.dingding.service.MeetingService;
+import org.springblade.dingding.vo.MeetingSchedule;
+import org.springblade.dingding.vo.MeetingVo;
+import org.springblade.dingding.vo.ScheduleItem;
+import org.springblade.websocket.feign.WebSocketClient;
+import org.springblade.websocket.vo.MsgVO;
+import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.TextStyle;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Service
+public class MeetingServiceImpl implements MeetingService {
+
+    private static final String DINGTALK_API_BASE = "https://api.dingtalk.com/v1.0/";
+    private static final String APP_KEY = "ding6mvrzcxcbdggel0h";
+    private static final String APP_SECRET = "TctTp-Qmyh9r20bdeHcLWZ8qfxSEP8R29qo53GZH2elWV-yDZMqgqFKEjp5PtlXZ";
+    private static final String USER_ID = "01141506681633389467";
+    @Autowired
+    private  WebSocketClient webSocketClient;
+
+    // 缓存用户信息,避免重复调用
+    private final Map<String, Object> userInfoCache = new ConcurrentHashMap<>();
+    private final Map<String, String> departmentCache = new ConcurrentHashMap<>();
+
+    // 创建带超时配置的HttpClient
+    private CloseableHttpClient createHttpClientWithTimeout() {
+        RequestConfig config = RequestConfig.custom()
+                .setConnectTimeout(10000) // 10秒连接超时
+                .setSocketTimeout(15000)   // 15秒socket超时
+                .build();
+
+        return HttpClientBuilder.create()
+                .setDefaultRequestConfig(config)
+                .build();
+    }
+
+
+
+    @Override
+    public  List<MeetingVo> getMeetingInfo() {
+        long startTime = System.currentTimeMillis();
+        try {
+            String accessToken = getAccessToken();
+            String unionId = (String) getUserInfo(accessToken, "unionid", USER_ID);
+            String meetingsJson = getMeetings(accessToken, unionId);
+
+            List<MeetingVo> vos = parseMeetingRooms(meetingsJson);
+            if (vos.isEmpty()) {
+                return vos;
+            }
+
+            // 准备时间范围参数
+            String[] timeRange = getTodayTimeRange();
+
+            // 并行处理每个会议室
+            List<CompletableFuture<Void>> futures = vos.stream()
+                    .map(vo -> processMeetingRoomAsync(vo, accessToken, unionId, timeRange[0], timeRange[1]))
+                    .collect(Collectors.toList());
+
+            // 等待所有完成,设置超时
+            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                    .get(25, TimeUnit.SECONDS);
+            // 25秒总超时
+            if(!vos.isEmpty()){
+                vos.sort((vo1, vo2) -> {
+                    String fixedData1 = vo1.getFixedData();
+                    String fixedData2 = vo2.getFixedData();
+
+                    // 提取会议室编号(去除"会议室"字符,只保留前面的中文数字)
+                    String number1 = extractChineseNumber(fixedData1);
+                    String number2 = extractChineseNumber(fixedData2);
+
+                    return compareChineseNumbers(number1, number2);
+                });
+                for (MeetingVo vo : vos) {
+                    if("一会议室".equals(vo.getFixedData())){
+                        vo.setFloor("6楼");
+                    } else if ("二会议室".equals(vo.getFixedData())) {
+                        vo.setFloor("6楼");
+                    }else if ("三会议室".equals(vo.getFixedData())) {
+                        vo.setFloor("4楼");
+                    }else if ("四会议室".equals(vo.getFixedData())) {
+                        vo.setFloor("3楼");
+                    }else if ("五会议室".equals(vo.getFixedData())) {
+                        vo.setFloor("2楼");
+                    }
+                }
+                UserInfoVO vo = new UserInfoVO();
+                vo.setSystem("dingding");
+                vo.setContractId(1L);
+                vo.setMsgType("dingding");
+                vo.setUserId(1L);
+                vo.setProjectId(1L);
+                vo.setObject( vos);
+                webSocketClient.sendDingDingMsg(vo);
+            }
+            return vos;
+        } catch (Exception e) {
+            throw new ServiceException("获取会议室信息失败: " + e.getMessage());
+        } finally {
+            long duration = System.currentTimeMillis() - startTime;
+            System.out.println("getMeetingInfo执行耗时: " + duration + "ms");
+        }
+    }
+
+    // 提取会议室名称中的中文数字部分
+    private String extractChineseNumber(String roomName) {
+        // 假设格式为 "一会议室"、"二会议室" 等,提取前面的中文数字
+        if (roomName != null && roomName.endsWith("会议室")) {
+            return roomName.substring(0, roomName.length() - 3); // 去掉"会议室"三个字
+        }
+        return roomName;
+    }
+
+    // 中文数字比较器
+    private int compareChineseNumbers(String chineseNum1, String chineseNum2) {
+        // 定义中文数字映射表
+        Map<String, Integer> chineseNumberMap = new HashMap<>();
+        chineseNumberMap.put("一", 1);
+        chineseNumberMap.put("二", 2);
+        chineseNumberMap.put("三", 3);
+        chineseNumberMap.put("四", 4);
+        chineseNumberMap.put("五", 5);
+        chineseNumberMap.put("六", 6);
+        chineseNumberMap.put("七", 7);
+        chineseNumberMap.put("八", 8);
+        chineseNumberMap.put("九", 9);
+        chineseNumberMap.put("十", 10);
+        chineseNumberMap.put("十一", 11);
+        chineseNumberMap.put("十二", 12);
+        chineseNumberMap.put("十三", 13);
+        chineseNumberMap.put("十四", 14);
+        chineseNumberMap.put("十五", 15);
+        chineseNumberMap.put("十六", 16);
+        chineseNumberMap.put("十七", 17);
+        chineseNumberMap.put("十八", 18);
+        chineseNumberMap.put("十九", 19);
+        chineseNumberMap.put("二十", 20);
+        // 可以根据需要继续添加更多数字
+
+        Integer num1 = chineseNumberMap.getOrDefault(chineseNum1, Integer.MAX_VALUE);
+        Integer num2 = chineseNumberMap.getOrDefault(chineseNum2, Integer.MAX_VALUE);
+
+        return num1.compareTo(num2);
+    }
+
+    private String[] getTodayTimeRange() {
+        LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIDNIGHT);
+        ZonedDateTime startOfDayZoned = startOfDay.atZone(ZoneId.systemDefault());
+        String startTime = startOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
+        ZonedDateTime endOfDayZoned = endOfDay.atZone(ZoneId.systemDefault());
+        String endTime = endOfDayZoned.withZoneSameInstant(ZoneId.of("UTC"))
+                .format(DateTimeFormatter.ISO_INSTANT);
+
+        return new String[]{startTime, endTime};
+    }
+    private List<MeetingVo> parseMeetingRooms(String meetingsJson) {
+        List<MeetingVo> vos = new ArrayList<>();
+        try {
+            JSONObject jsonObject = JSON.parseObject(meetingsJson);
+            JSONArray resultArray = jsonObject.getJSONArray("result");
+
+            for (int i = 0; i < resultArray.size(); i++) {
+                JSONObject roomObject = resultArray.getJSONObject(i);
+                MeetingVo vo = new MeetingVo();
+                vo.setRoomId(roomObject.getString("roomId"));
+                vo.setFixedData(roomObject.getString("roomName"));
+                vo.setStatus(1); // 默认状态
+                vos.add(vo);
+            }
+        } catch (Exception e) {
+            System.err.println("解析会议室列表失败: " + e.getMessage());
+        }
+        return vos;
+    }
+    @Async
+    protected CompletableFuture<Void> processMeetingRoomAsync(MeetingVo vo, String accessToken,
+                                                              String unionId, String startTime, String endTime) {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                processMeetingRoom(vo, accessToken, unionId, startTime, endTime);
+            } catch (Exception e) {
+                System.err.println("处理会议室 " + vo.getFixedData() + " 失败: " + e.getMessage());
+                // 设置默认值,避免影响其他会议室
+                vo.setStatus(1);
+                vo.setMeetings(new ArrayList<>());
+                vo.setMeetingSession(0);
+            }
+        });
+    }
+    private void processMeetingRoom(MeetingVo vo, String accessToken, String unionId,
+                                    String startTime, String endTime) {
+        String[] roomIds = new String[]{vo.getRoomId()};
+        String meetingHistory = getMeetingHistory(accessToken, unionId, roomIds, startTime, endTime);
+        List<ScheduleItem> scheduleItems = parseScheduleItemsWithStream(meetingHistory);
+
+        List<MeetingSchedule> meetings = new ArrayList<>();
+        boolean hasOngoingMeeting = false;
+
+        for (ScheduleItem item : scheduleItems) {
+            if (hasOngoingMeeting) {
+                break; // 如果已经有进行中的会议,跳过后续处理
+            }
+
+            if (isCurrentTimeInRange(item.getStartDateTime(), item.getEndDateTime())) {
+                // 处理进行中的会议
+                processOngoingMeeting(vo, item, accessToken);
+                hasOngoingMeeting = true;
+            } else {
+                // 处理预约的会议
+                MeetingSchedule schedule = processScheduledMeeting(item, accessToken);
+                if (schedule != null) {
+                    meetings.add(schedule);
+                }
+            }
+        }
+
+        vo.setMeetings(meetings);
+        vo.setMeetingSession(meetings.size());
+        if (!hasOngoingMeeting) {
+            vo.setStatus(1);
+        }
+    }
+
+    private void processOngoingMeeting(MeetingVo vo, ScheduleItem item, String accessToken) {
+        try {
+            vo.setStatus(2);
+
+            String meetingList = getMeetingList(item.getOrganizerId(), accessToken);
+            JSONObject meetingListJson = JSON.parseObject(meetingList);
+            JSONArray onGoingConfIdList = meetingListJson.getJSONArray("onGoingConfIdList");
+
+            if (onGoingConfIdList != null && !onGoingConfIdList.isEmpty()) {
+                String conferenceId = onGoingConfIdList.getString(0);
+                String meetingTitle = getMeetingDetail(accessToken, conferenceId);
+                vo.setMeetingTheme(meetingTitle);
+
+                String allUsers = getAllUser(conferenceId, accessToken);
+                vo.setParticipants(allUsers);
+            }
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            String userName = (String) getUserInfo(accessToken, "name", userId);
+            vo.setMeetingBooker(userName);
+
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+                    vo.setMeetingDept(departmentName);
+                }
+            }
+
+            vo.setMeetingTime(formatDateTimeRangeWithFormatter(item.getStartDateTime(), item.getEndDateTime()));
+
+        } catch (Exception e) {
+            System.err.println("处理进行中会议失败: " + e.getMessage());
+            vo.setStatus(1); // 出错时回退到预约状态
+        }
+    }
+    private MeetingSchedule processScheduledMeeting(ScheduleItem item, String accessToken) {
+        try {
+            String startTime = extractTimeFromDateTime(item.getStartDateTime());
+            String endTime = extractTimeFromDateTime(item.getEndDateTime());
+
+            String userId = getUserID(accessToken, item.getOrganizerId());
+            Object deptInfo = getUserInfo(accessToken, "dept_id_list", userId);
+
+            if (deptInfo != null) {
+                List<String> deptIdList = JSON.parseArray(deptInfo.toString(), String.class);
+                if (!deptIdList.isEmpty()) {
+                    String departmentName = getDepartmentInfo(accessToken, deptIdList.get(0));
+
+                    MeetingSchedule schedule = new MeetingSchedule();
+                    schedule.setReservationTime(startTime + "~" + endTime);
+                    schedule.setReservationDept(departmentName);
+                    return schedule;
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("处理预约会议失败: " + e.getMessage());
+        }
+        return null;
+    }
+
+    public String getAllUser(String CONFERENCE_ID,String ACCESS_TOKEN){
+       try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
+           // 构建请求 URL
+           StringBuilder urlBuilder = new StringBuilder("https://api.dingtalk.com/v1.0/conference/videoConferences/")
+                   .append(CONFERENCE_ID)
+                   .append("/members");
+           HttpGet httpGet = new HttpGet(new URI(urlBuilder.toString()));
+           // 设置 Header 参数
+           httpGet.setHeader("x-acs-dingtalk-access-token", ACCESS_TOKEN);
+           httpGet.setHeader("Content-Type", "application/json");
+           // 发送请求并获取响应
+           CloseableHttpResponse response = httpClient.execute(httpGet);
+           try {
+               // 解析响应实体为字符串
+               String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+               JSONObject jsonObject = JSON.parseObject(responseString);
+               // 获取memberModelMap
+               JSONArray memberModels = jsonObject.getJSONArray("memberModels");
+               Set<String> set=new HashSet<>();
+               if(memberModels!=null&&!memberModels.isEmpty()){
+                   for (int i = 0; i < memberModels.size(); i++) {
+                       JSONObject memberModel = memberModels.getJSONObject(i);
+                       if((int)memberModel.get("attendStatus")<=3){
+                           String userNick = memberModel.getString("userNick");
+                           set.add(userNick);
+                       }
+
+                   }
+                   return String.join("、",set);
+               }else {
+                   return "";
+               }
+
+           } finally {
+               response.close();
+           }
+       } catch (IOException | URISyntaxException e) {
+          return "";
+       }
+   }
+
+    public String formatDateTimeRangeWithFormatter(String startDateTime, String endDateTime) {
+        try {
+            ZonedDateTime startTime = ZonedDateTime.parse(startDateTime);
+            ZonedDateTime endTime = ZonedDateTime.parse(endDateTime);
+
+            // 手动构建格式
+            String startFormatted = String.format("%d年%d月%d日 %s %02d:%02d",
+                    startTime.getYear(),
+                    startTime.getMonthValue(),
+                    startTime.getDayOfMonth(),
+                    startTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINESE),
+                    startTime.getHour(),
+                    startTime.getMinute());
+
+            String endFormatted = String.format("%d年%d月%d日 %s %02d:%02d",
+                    endTime.getYear(),
+                    endTime.getMonthValue(),
+                    endTime.getDayOfMonth(),
+                    endTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINESE),
+                    endTime.getHour(),
+                    endTime.getMinute());
+
+            return startFormatted + " ~ " + endFormatted;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "时间格式错误";
+        }
+    }
+
+    public boolean isCurrentTimeInRange(String startDateTime, String endDateTime) {
+        try {
+            // 解析开始时间和结束时间
+            ZonedDateTime startTime = ZonedDateTime.parse(startDateTime);
+            ZonedDateTime endTime = ZonedDateTime.parse(endDateTime);
+
+            // 获取当前时间(使用相同时区)
+            ZonedDateTime now = ZonedDateTime.now(startTime.getZone());
+
+            // 检查当前时间是否在范围内(包含边界)
+            return !now.isBefore(startTime) && !now.isAfter(endTime);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    public String getMeetingList(String UNION_ID, String ACCESS_TOKEN){
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
+            // 构建请求 URL
+            String url = "https://api.dingtalk.com/v1.0/conference/users/lists?unionId=" + UNION_ID;
+            HttpGet httpGet = new HttpGet(url);
+            // 设置请求头中的 access token
+            httpGet.setHeader("x-acs-dingtalk-access-token", ACCESS_TOKEN);
+            httpGet.setHeader("Content-Type", "application/json");
+
+            // 发送请求并获取响应
+            CloseableHttpResponse response = httpClient.execute(httpGet);
+            try {
+                org.apache.http.HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    // 将响应实体转换为字符串
+                    return EntityUtils.toString(entity, "UTF-8");
+                }
+            } finally {
+                response.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String getMeetingDetail(String ACCESS_TOKEN,String CONFERENCE_ID){
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
+            // 构建请求 URL,包含会议 ID
+            String url = "https://api.dingtalk.com/v1.0/conference/videoConferences/" + CONFERENCE_ID;
+            HttpGet httpGet = new HttpGet(url);
+
+            // 设置 Header 参数
+            httpGet.setHeader("x-acs-dingtalk-access-token", ACCESS_TOKEN);
+            httpGet.setHeader("Content-Type", "application/json");
+
+            // 发送请求并获取响应
+            CloseableHttpResponse response = httpClient.execute(httpGet);
+            try {
+                // 解析响应实体为字符串
+                String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+                JSONObject jsonObject = JSON.parseObject(responseString);
+                JSONObject confInfo = jsonObject.getJSONObject("confInfo");
+                if (confInfo != null) {
+                    return confInfo.getString("title");
+                }
+            } finally {
+                response.close();
+            }
+        } catch (IOException e) {
+
+        }
+        return null;
+    }
+
+    public  String getUserID(String ACCESS_TOKEN,String UNION_ID) throws Exception {
+        try(CloseableHttpClient httpClient = createHttpClientWithTimeout()) {
+            // 构建请求 URL,包含 access_token 和 unionid 参数
+            String url = "https://oapi.dingtalk.com/user/getUseridByUnionid?access_token=" + ACCESS_TOKEN + "&unionid=" + UNION_ID;
+            HttpGet httpGet = new HttpGet(url);
+
+            // 发送请求并获取响应
+            CloseableHttpResponse response = httpClient.execute(httpGet);
+            try {
+                // 解析响应实体为字符串
+                String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
+                // 解析 JSON 响应
+                JSONObject jsonObject = JSONObject.parseObject(responseString);
+
+                // 检查是否调用成功(errcode 为 0 表示成功)
+                if (jsonObject.getInteger("errcode") == 0) {
+                    // 获取 userId
+                    String userId = jsonObject.getString("userid");
+                    return userId;
+                } else {
+                   throw new Exception("获取userId失败");
+                }
+            } finally {
+                response.close();
+            }
+        } catch (Exception e) {
+            throw new Exception("获取userId失败");
+        }
+    }
+
+    public  int compareDateTimeWithNow(String stringStartDateTime) {
+        try {
+            // 解析输入的时间字符串
+            ZonedDateTime inputTime = ZonedDateTime.parse(stringStartDateTime);
+
+            // 获取当前时间(使用相同时区)
+            ZonedDateTime now = ZonedDateTime.now(inputTime.getZone());
+
+            // 比较时间
+            if (inputTime.isAfter(now)) {
+                return 1; // 输入时间大于当前时间
+            } else {
+                return 2; // 输入时间小于或等于当前时间
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 2; // 默认返回2(过去时间)
+        }
+    }
+
+    /**
+     * 查询部门信息
+     */
+    public String getDepartmentInfo(String accessToken, String deptId) throws Exception {
+        CloseableHttpClient httpClient = createHttpClientWithTimeout();
+        String url = "https://oapi.dingtalk.com/topapi/v2/department/get?access_token=" + accessToken;
+
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
+
+        // 构建请求体
+        JSONObject requestBody = new JSONObject();
+        requestBody.put("dept_id", deptId);
+        httpPost.setEntity(new StringEntity(requestBody.toString(), "UTF-8"));
+
+        // 发送请求并获取响应
+        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+            // 使用Apache HttpClient的HttpEntity
+            org.apache.http.HttpEntity entity = response.getEntity();  // 不要强制转换
+            if (entity != null) {
+                String string = EntityUtils.toString(entity, "UTF-8");
+                JSONObject jsonObject = JSON.parseObject(string);
+                JSONObject resultObj = jsonObject.getJSONObject("result");
+                return resultObj.getString("name");  // 使用getString更安全
+            }
+        } finally {
+            httpClient.close();
+        }
+        return null;
+    }
+    public  String extractTimeFromDateTime(String dateTimeString) {
+        try {
+            // 解析带时区的时间字符串
+            ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeString);
+
+            // 只提取小时和分钟
+            DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
+            return zonedDateTime.format(timeFormatter);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "00:00"; // 返回默认值如果解析失败
+        }
+    }
+
+    public  List<ScheduleItem> parseScheduleItemsWithStream(String meetingHistoryJson) {
+        try {
+            JSONObject jsonObject = JSON.parseObject(meetingHistoryJson);
+            JSONArray scheduleInfoArray = jsonObject.getJSONArray("scheduleInformation");
+
+            if (scheduleInfoArray != null) {
+                return scheduleInfoArray.stream()
+                        .map(obj -> (JSONObject) obj)
+                        .flatMap(scheduleInfo -> {
+                            JSONArray items = scheduleInfo.getJSONArray("scheduleItems");
+                            return items != null ? items.stream().map(item -> (JSONObject) item) : java.util.stream.Stream.empty();
+                        })
+                        .map(this::convertToScheduleItem)
+                        .collect(java.util.stream.Collectors.toList());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return new ArrayList<>();
+    }
+
+    private  ScheduleItem convertToScheduleItem(JSONObject scheduleItemObj) {
+        ScheduleItem item = new ScheduleItem();
+
+        item.setEventId(scheduleItemObj.getString("eventId"));
+        item.setStatus(scheduleItemObj.getString("status"));
+
+        JSONObject organizerObj = scheduleItemObj.getJSONObject("organizer");
+        if (organizerObj != null) {
+            item.setOrganizerId(organizerObj.getString("id"));
+        }
+
+        JSONObject startObj = scheduleItemObj.getJSONObject("start");
+        if (startObj != null) {
+            item.setStartDateTime(startObj.getString("dateTime"));
+            item.setStartTimeZone(startObj.getString("timeZone"));
+        }
+
+        JSONObject endObj = scheduleItemObj.getJSONObject("end");
+        if (endObj != null) {
+            item.setEndDateTime(endObj.getString("dateTime"));
+            item.setEndTimeZone(endObj.getString("timeZone"));
+        }
+
+        return item;
+    }
+
+    //解析json字符串
+    private  String parseFromJson(String json,String key) {
+        try {
+            JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
+            JsonElement result = jsonObject.get("result");
+            return result.getAsJsonObject().get(key).getAsString();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    //获取AccessToken
+    public  String getAccessToken() {
+        // 实现获取AccessToken逻辑
+        String url = DINGTALK_API_BASE + "oauth2/accessToken";
+        RestTemplate restTemplate = new RestTemplate();
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        // 构造请求体
+        String requestBody = "{\n" +
+                "    \"appKey\": \"" + APP_KEY + "\",\n" +
+                "    \"appSecret\": \"" + APP_SECRET + "\"\n" +
+                "}";
+        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
+        try {
+            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
+            JSONObject jsonObject = JSON.parseObject(response.getBody());
+            return jsonObject.getString("accessToken");
+        } catch (Exception e) {
+            throw new ServiceException("获取AccessToken失败");
+        }
+    }
+
+    /**
+     * 获取unionId 操作人id
+     * @return
+     */
+    public  Object getUserInfo(String accessToken,String key,String userid){
+        String url = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken;
+        RestTemplate restTemplate = new RestTemplate();
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        Map<String, String> requestBody = new HashMap<>();
+        requestBody.put("language", "zh_CN");
+        requestBody.put("userid", userid);
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            String jsonString = objectMapper.writeValueAsString(requestBody);
+            HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);
+            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
+            JSONObject jsonObject = JSON.parseObject(response.getBody());
+            JSONObject result = jsonObject.getJSONObject("result");
+            return result.get(key);
+        } catch (Exception e) {
+            throw new ServiceException("获取用户信息失败");
+        }
+    }
+
+    //获取会议室列表
+    public  String getMeetings(String accessToken,String unionId) {
+        if (accessToken == null || accessToken.isEmpty()) {
+            System.out.println("获取accessToken失败");
+            return null;
+        }
+        // 构建请求URL,包含必要的查询参数
+        String baseUrl = DINGTALK_API_BASE + "rooms/meetingRoomLists";
+        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl)
+                .queryParam("unionId", unionId);
+        RestTemplate restTemplate = new RestTemplate();
+        HttpHeaders headers = new HttpHeaders();
+        // 设置必要的请求头
+        headers.set("x-acs-dingtalk-access-token", accessToken);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        HttpEntity<?> entity = new HttpEntity<>(headers);
+        try {
+            // 使用GET方法发送请求
+            ResponseEntity<String> response = restTemplate.exchange(
+                    uriBuilder.toUriString(),
+                    HttpMethod.GET,
+                    entity,
+                    String.class
+            );
+            if (response.getStatusCode().is2xxSuccessful()) {
+                return response.getBody();
+            } else {
+                throw new SecurityException("获取会议室列表异常");
+            }
+        } catch (Exception e) {
+            throw new SecurityException("获取会议室列表异常");
+        }
+    }
+
+//    //获取会议室详情
+//    public  String getMeetingDetail(String accessToken,String roomId,String unionId) {
+//        // 构建请求URL(注意是meetingRooms单个资源路径,不是列表接口)
+//        String baseUrl = DINGTALK_API_BASE + "rooms/meetingRooms/" + roomId;
+//        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl)
+//                .queryParam("unionId", unionId);
+//
+//        // 创建REST模板并设置请求头
+//        RestTemplate restTemplate = new RestTemplate();
+//        HttpHeaders headers = new HttpHeaders();
+//        headers.set("x-acs-dingtalk-access-token", accessToken);
+//        headers.setContentType(MediaType.APPLICATION_JSON);
+//        // 添加User-Agent头,模拟浏览器请求
+//        headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
+//        HttpEntity<?> entity = new HttpEntity<>(headers);
+//        try {
+//            // 发送GET请求
+//            ResponseEntity<String> response = restTemplate.exchange(
+//                    uriBuilder.toUriString(),
+//                    HttpMethod.GET,
+//                    entity,
+//                    String.class
+//            );
+//            // 处理响应
+//            if (response.getStatusCode().is2xxSuccessful()) {
+//                return response.getBody();
+//            } else {
+//                throw new ServiceException("获取会议室详情异常");
+//            }
+//        } catch (Exception e) {
+//           throw new ServiceException("获取会议室详情失败");
+//        }
+//    }
+
+
+    public  String getMeetingHistory(String accessToken, String unionId,String[] roomIds, String startTime, String endTime) {
+        // 构建请求 URL,包含 Path 参数 userId
+        String baseUrl = DINGTALK_API_BASE + "calendar/users/{userId}/meetingRooms/schedules/query";
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put("userId", unionId);
+        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl)
+                .uriVariables(paramMap);
+        RestTemplate restTemplate = new RestTemplate();
+        HttpHeaders headers = new HttpHeaders();
+        // 设置请求头
+        headers.set("x-acs-dingtalk-access-token", accessToken);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        // 构建请求体参数(Body 参数)
+        Map<String, Object> requestBody = new HashMap<>();
+        // 替换为实际的会议室 roomId 列表,建议不超过 5 个
+        requestBody.put("roomIds", roomIds);
+        // 替换为实际的查询开始时间,需符合 iso8601 格式,如 "2025-08-30T00:00:00Z"
+        requestBody.put("startTime", startTime);
+        // 替换为实际的查询结束时间,需符合 iso8601 格式,如 "2025-08-31T00:00:00Z"
+        requestBody.put("endTime", endTime);
+        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
+        try {
+            // 使用 POST 方法发送请求
+            ResponseEntity<String> response = restTemplate.exchange(
+                    uriBuilder.toUriString(),
+                    HttpMethod.POST,
+                    entity,
+                    String.class
+            );
+            if (response.getStatusCode().is2xxSuccessful()) {
+                return response.getBody();
+            } else {
+                throw new ServiceException("获取会议室历史异常");
+            }
+        } catch (Exception e) {
+            throw new ServiceException("获取会议室历史异常");
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}

+ 15 - 0
blade-service/blade-dingding/src/main/resources/application-dev.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 9120
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.dev.url}
+    username: ${blade.datasource.dev.username}
+    password: ${blade.datasource.dev.password}

+ 15 - 0
blade-service/blade-dingding/src/main/resources/application-prod.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 9120
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.dev.url}
+    username: ${blade.datasource.dev.username}
+    password: ${blade.datasource.dev.password}

+ 15 - 0
blade-service/blade-dingding/src/main/resources/application-test.yml

@@ -0,0 +1,15 @@
+#服务器端口
+server:
+  port: 9120
+  task:
+    execution:
+      pool:
+        core-size: 10
+        max-size: 20
+        queue-capacity: 100
+#数据源配置
+spring:
+  datasource:
+    url: ${blade.datasource.dev.url}
+    username: ${blade.datasource.dev.username}
+    password: ${blade.datasource.dev.password}

+ 1 - 1
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/controller/EVController.java

@@ -58,7 +58,7 @@ public class EVController {
     @Resource(name = "taskExecutor1")
     private ThreadPoolExecutor executor;
 
-    //@Scheduled(cron = "0/10 * * * * ?")
+    @Scheduled(cron = "0/10 * * * * ?")
     public void SignInfo() {
         //执行代码
 

+ 10 - 20
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/EVDataServiceImpl.java

@@ -190,7 +190,7 @@ public class EVDataServiceImpl implements EVDataService {
                 }
 
                 String sql2 = "INSERT into u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name,sign_format,sign_type)" +
-                        "SELECT " + id + " as id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name,sign_format,2 as sign_type from u_task_batch where id=" + batchId + "";
+                        "SELECT " + id + " as id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,SYSDATE(),status,is_deleted,nick_name,sign_format,2 as sign_type from u_task_batch where id=" + batchId + "";
                 jdbcTemplate.execute(sql2);
             }
         }
@@ -445,24 +445,14 @@ public class EVDataServiceImpl implements EVDataService {
 
             } else if (taskApp.getApprovalType() == 5) {
                 map = this.jdbcTemplate.queryForMap("select * from s_interim_pay_certificate where  is_deleted=0 and contract_period_id = " + taskApp.getFormDataId());
-                String pdfUrl=map.get("raw_url") + "";
+                String pdfUrl = "";
                 //中间计量用逗号拼接pagePdfUrl
-               /* String pageUrl = map.get("page_pdf_url")+"";
-                if(StringUtils.isNotEmpty(pageUrl) && pageUrl.length()>=20 ){
-                    String jsonStr=map.get("page_pdf_url")+"";
-                    ObjectMapper mapper = new ObjectMapper();
-                    JsonNode jsonNode = mapper.readTree(jsonStr);
-                    StringBuilder result = new StringBuilder();
-                    Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
-                    while (fields.hasNext()) {
-                        Map.Entry<String, JsonNode> entry = fields.next();
-                        result.append(entry.getValue().asText());
-                        if (fields.hasNext()) {
-                            result.append(",");
-                        }
-                    }
-                    pdfUrl=result.toString();
-                }*/
+                String pageUrl = map.get("page_pdf_url")+"";
+                if(StringUtils.isNotEmpty(pageUrl) && pageUrl.length()>=20 ) {
+                    pageUrl = pageUrl.replaceAll(" ", "");
+                }else{
+                    pdfUrl=map.get("raw_url") + "";
+                }
                 taskApp.setSignPdfUrl(pdfUrl);
             } else if (taskApp.getApprovalType() == 6 || taskApp.getApprovalType() == 7) {
                 map = this.jdbcTemplate.queryForMap("select * from  s_material_start_statement where is_deleted=0 and meter_period_id = " + taskApp.getFormDataId());
@@ -906,7 +896,7 @@ public class EVDataServiceImpl implements EVDataService {
             int i = SignFtpUtil.uploadFile(locPdfUrl, inputStream);
             if (i == 1) {
                  result = eVisaService.signPdfByAXQZ(pdfVO, locPdfUrl, OutPdfUrl);
-                if(result!=null){
+                if(result!=null && result[0]!=null){
                     int i1 = SignFtpUtil.downloadFile(dataFileUrl, OutPdfUrl);
                     fileUrl = dataFileUrl;
                     SignFtpUtil.FTPDeleteDir(locPdfUrl);
@@ -921,7 +911,7 @@ public class EVDataServiceImpl implements EVDataService {
         } else {
             result = eVisaService.signPdfByAXQZ(pdfVO, fileByte);
             //执行电签
-            if (result != null) {
+            if(result!=null && result[0]!=null){
                 try {
                     //对文件流做判断
                     byte[] bytes = (byte[]) result[0];

+ 286 - 26
blade-service/blade-e-visa/src/main/java/org/springblade/evisa/service/impl/ScrDataServiceImpl.java

@@ -34,7 +34,7 @@ public class ScrDataServiceImpl implements ScrDataService {
     @Override
     public void sctTaskBatch(ScrSignInfoVO taskApp) throws Exception {
         // 电签检查
-        this.sctTaskBatch2(taskApp);
+        this.sctTaskBatch3(taskApp);
     }
 
 
@@ -70,7 +70,7 @@ public class ScrDataServiceImpl implements ScrDataService {
 
         if(strategyListByDFZX==null || strategyListByDFZX.size()==0){
 
-            String sql2 = "UPDATE u_information_query set chek_status=10 where id='"+taskApp.getId()+"'";
+            String sql2 = "UPDATE u_information_query set chek_status=3 where id='"+taskApp.getId()+"'";
             jdbcTemplate.execute(sql2);
 
             RedisTemplate.delete("chek-" + taskApp.getId());
@@ -242,7 +242,7 @@ public class ScrDataServiceImpl implements ScrDataService {
                     total = Func.toInt(map.get("total"));
                     pCount = Func.toInt(map.get("pCount"));
                 }
-                if(map.get("initiative").equals("2") && map.get("status").equals("2")){
+                if((map.get("initiative")+"").equals("2") && (map.get("status")+"").equals("2")){
                     strArray.add(map.get("task_user").toString());
                 }
             }
@@ -271,13 +271,7 @@ public class ScrDataServiceImpl implements ScrDataService {
                 List<Map<String, Object>> maps2 = null;
                 if (dqIds.length() > 0) {
                     String sqlinfo = " SELECT * from ( SELECT a.id as keyWord,a.project_id,a.pyzbx ,a.pyzby,(SELECT acc_code from blade_user where id='" + strArray.get(i) + "' and is_deleted=0  ) as sealId from m_textdict_info a where  a.type =2 and a.id in (" + dqIds + ")  and sig_role_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id=" + task.getContractId() + " and user_id=" + strArray.get(i) + " and c.is_deleted=0 ) ) x where x.sealId is not null ";
-                    if (total==pCount) {
-                        sqlinfo = "SELECT a.id as keyWord,a.pyzbx,a.pyzby,b.certificate_number as sealId from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + dqIds + ")";
-                        System.out.println("东方中讯--签章--" + sqlinfo);
-                    } else {
-                        System.out.println("东方中讯--签字--" + sqlinfo);
-                    }
-                    maps2 = jdbcTemplate.queryForList(sqlinfo);
+                    System.out.println("东方中讯--签字--" + sqlinfo);
                     maps2 = jdbcTemplate.queryForList(sqlinfo);
                 }
                 if(CollectionUtil.isNotEmpty(maps2)) {
@@ -302,25 +296,34 @@ public class ScrDataServiceImpl implements ScrDataService {
                         }
                     }
                 }
-             /*   if (signIds.length() > 0 && task.getSigType() != 2) {
-                    String sql = "SELECT * from ( SELECT a.conf_id as keyWord,0.0 as pyzbx ,0.0 as pyzby,(SELECT acc_code from blade_user where id = " + strArray[i] + " and is_deleted=0  ) as sealId " +
-                            "from m_sign_config_relation a where a.type = 1 and a.is_deleted = 0 and a.conf_id in (" + signIds + ") " +
-                            "and a.relation_id in (SELECT DISTINCT c.role_id from m_project_assignment_user c  where c.contract_id= " + task.getContractId() + " and user_id= " + strArray[i] + " and c.is_deleted=0 ) ) x where x.sealId is not null ";
-                    List<Map<String, Object>> maps3 = jdbcTemplate.queryForList(sql);
-                    System.out.println("东方中讯--签字--key =" + sql);
-                    if (!maps3.isEmpty()) {
-                        Map<String, List<Map<String, Object>>> peopleByAge = maps2.stream()
-                                .collect(Collectors.groupingBy(hada -> (Func.toStr(hada.get("keyWord")))));
-                        for (String keyId : peopleByAge.keySet()) {
-                            List<Map<String, Object>> keyList = peopleByAge.get(keyId);
-                            if (keyList != null && !keyList.isEmpty()) {
-                                Map<String, Object> map = keyList.get(0);
-                                map.put("keyWord", "✹" + map.get("keyWord"));
-                                maps.add(map);
+            }
+
+
+
+            String sqlinfo = "SELECT a.id as keyWord,a.pyzbx,a.pyzby,b.certificate_number as sealId from m_textdict_info a ,m_sign_pfx_file b where a.sig_role_id = b.pfx_type and b.project_contract_role like '%" + task.getContractId() + "%' and a.is_deleted=0 and b.is_deleted=0 and a.type=6 and a.id in(" + dqIds + ")";
+            System.out.println("东方中讯--签章--" + sqlinfo);
+            List<Map<String, Object>> maps2 = jdbcTemplate.queryForList(sqlinfo);
+            if(CollectionUtil.isNotEmpty(maps2)) {
+                Map<String, List<Map<String, Object>>> peopleByAge = maps2.stream()
+                        .collect(Collectors.groupingBy(hada -> (Func.toStr(hada.get("keyWord")))));
+                for (String keyId : peopleByAge.keySet()) {
+                    int exId = 0;
+                    List<Map<String, Object>> keyList = peopleByAge.get(keyId);
+                    if (keyList != null && keyList.size() == 1) {
+                        maps.addAll(keyList);
+                        exId = 1;
+                    } else if (keyList != null && keyList.size() >= 2) {
+                        for (Map<String, Object> datax : keyList) {
+                            if ((datax.get("project_id") + "").equals(task.getProjectId())) {
+                                maps.add(datax);
+                                exId = 1;
                             }
                         }
                     }
-                }*/
+                    if (exId == 0) {
+                        maps.add(keyList.get(0));
+                    }
+                }
             }
         }
         return maps;
@@ -391,4 +394,261 @@ public class ScrDataServiceImpl implements ScrDataService {
         return maps;
     }
 
+    public void sctTaskBatch3(ScrSignInfoVO taskApp) throws Exception {
+        int threshold = 5;
+
+        String fileUrl = CommonUtil.replaceOssUrl(taskApp.getEVisaPdfUrl());
+        String pdfUrl = taskApp.getEVisaPdfUrl();
+        InputStream inputStream = CommonUtil.getOSSInputStream(fileUrl);
+        InputStream inputStream2 = CommonUtil.getOSSInputStream(fileUrl);
+        //转换
+        byte[] pdfData = CommonUtil.InputStreamToBytes(inputStream);
+
+        try (PDDocument document = PDDocument.load(inputStream2);) {
+            SignKeyVO pdfSignIds = PdfAddimgUtil.getPdfSignIds(pdfUrl);
+            List<String> positions = pdfSignIds.getEVisaConfigList();
+            Map<String, String> dataMap = pdfSignIds.getDataMap();
+
+            List<String> sucessUser = new ArrayList<>();
+            List<String> sucessCompan = new ArrayList<>();
+            String ids = String.join(",", positions);
+            ids = ids.replaceAll("✹", "");
+            String remarkType = taskApp.getRemarkType();
+            List<Map<String, Object>> strategyListByDFZX = new ArrayList<>();
+            if (remarkType.equals("1")) {
+                strategyListByDFZX = getStrategyListByAXQ(taskApp, ids);
+            } else if (remarkType.equals("2") || remarkType.equals("3")) {
+                strategyListByDFZX = getStrategyListByDFZX(taskApp, ids);
+            }
+
+            if (strategyListByDFZX == null || strategyListByDFZX.size() == 0) {
+
+                String sql2 = "UPDATE u_information_query set chek_status=10 where id='" + taskApp.getId() + "'";
+                jdbcTemplate.execute(sql2);
+
+                RedisTemplate.delete("chek-" + taskApp.getId());
+                System.out.println(taskApp.getProcessInstanceId() + "-" + "总共:");
+                return;
+            }
+
+            positions = strategyListByDFZX.stream().map(map -> map.get("keyWord").toString()).collect(Collectors.toList());
+            String keyWord = String.join(",", positions);
+            List<PDFIndexInfo> pdfIndexInfo = PdfAddimgUtil.findKeywordPostions(pdfData, keyWord);
+
+            //根据id分组
+            List<Map<String, Object>> list2 = strategyListByDFZX.stream().collect(
+                    Collectors.collectingAndThen(
+                            Collectors.toCollection(
+                                    () -> new TreeSet<>(Comparator.comparing(m -> m.get("keyWord").toString()))
+                            ), ArrayList::new
+                    )
+            );
+
+            Map<String, List<Map<String, Object>>> newMap = list2.stream().collect(Collectors.groupingBy(b -> Func.toStr(b.get("keyWord"))));
+
+            Map<String, List<PDFIndexInfo>> groupBy = pdfIndexInfo.stream().collect(Collectors.groupingBy(da -> Func.toStr(da.getDataInfo()[0])));
+            for (int i = 0; i < document.getPages().getCount(); i++) {
+                PDPage page = document.getPage(i);
+                List<PDAnnotation> annotations = page.getAnnotations();
+                for (PDAnnotation annotation : annotations) {
+                    if (annotation instanceof PDAnnotationWidget) {
+                        PDRectangle rect = annotation.getRectangle();
+
+                        float imgW = rect.getWidth();
+                        float imgH = rect.getHeight();
+                        float imgX = rect.getLowerLeftX() + imgW / 2;
+                        float imgY = rect.getLowerLeftY() + imgH / 2;
+                        List<PDFIndexInfo> pdfIndexInfos = groupBy.get((i + 1) + ".0");
+                        if (pdfIndexInfos != null && pdfIndexInfos.size() > 0) {
+                            for (PDFIndexInfo pdfInfo : pdfIndexInfos) {
+                                String pkeyid = pdfInfo.getPkeyid();
+
+                                float[] dataInfo = pdfInfo.getDataInfo();
+
+                                float keyX = dataInfo[1];
+                                float keyY = dataInfo[2];
+                                float pageHeight = page.getMediaBox().getHeight();
+                                float pageWidth = page.getMediaBox().getWidth();
+
+                                float keyw = keyX * pageWidth;
+                                float keyh = pageHeight - keyY * pageHeight;
+
+                                List<Map<String, Object>> mapList = newMap.get(pkeyid);
+                                String keyData = dataMap.get(pkeyid);
+                                String type = "";
+                                if (mapList != null && mapList.size() >= 0) {
+                                    Map<String, Object> map = mapList.get(0);
+                                    Float pyzbx = Func.toFloat(map.get("pyzbx"));
+                                    Float pyzby = Func.toFloat(map.get("pyzby"));
+                                    type = map.get("type") + "";
+                                    if (taskApp.getRemarkType().equals("3")) { //东方中讯
+                                        if (type.equals("1")) { //个人签字
+                                            keyw = keyw + pyzbx + 10;
+                                            keyh = keyh + pyzby;
+                                            if (keyData.contains(pkeyid + "\r")) {
+                                                if (imgX - keyw >= 30 && imgX - keyw <= 35) {
+                                                    keyw += 30;
+                                                } else if (imgX - keyw >= -35 && imgX - keyw <= -30) {
+                                                    keyw = keyw - 30;
+                                                }
+                                            } else {
+                                                if (pyzbx != 0 && Math.abs(imgX - (keyw - pyzbx)) <= 5) {
+                                                    keyw = keyw - pyzbx;
+                                                }
+                                                if (keyData.contains("*✹") || keyData.contains("||")) {
+                                                    if (keyData.contains("\r") && !keyData.contains(pkeyid + "\r")) {
+                                                        keyw = keyw - 30;
+                                                    }
+                                                    if (Math.abs(keyh - imgY) <= 2) {
+                                                        if (keyw - imgX >= -10 && keyw - imgX <= -5) {
+                                                            keyw += 10;
+                                                        } else if (keyw - imgX <= 10 && keyw - imgX >= 5) {
+                                                            keyw -= 10;
+                                                        }
+                                                    }
+                                                }
+                                            }
+
+                                        } else if (type.equals("2")) {
+                                            keyw = keyw + pyzbx - 21;
+                                            keyh = keyh + pyzby - 16;
+                                            if (keyData.contains(pkeyid + "\r")) {
+                                                keyw = keyw + 10;
+                                            } else if (keyData.contains("\r") && keyData.contains("*✹")) {
+                                                keyw = keyw - 20;
+                                            }
+                                            if (keyData.contains("||")) {
+                                                keyw = keyw + 10;
+                                            }
+                                        }
+                                    } else if (taskApp.getRemarkType().equals("2")) { //东方中讯
+                                        if (imgH >= 100) { // 签章 120 120
+                                            keyw = keyw + pyzbx - 21;
+                                            keyh = keyh + pyzby - 15;
+                                            if (keyData.indexOf("||") > 0) {
+                                                int index = keyData.length() - keyData.indexOf(pkeyid) - pkeyid.length();
+                                                if (index > 0) {
+                                                    keyw = (float) (keyw + (keyData.indexOf(pkeyid) / 42) * 10.5);
+                                                } else if (index < 0) {
+                                                    keyw = (float) (keyw - (keyData.indexOf(pkeyid) / 42) * 9.5);
+                                                }
+                                                if (Math.abs(keyh - imgY) <= 3) {
+                                                    if (keyw - imgX >= -10 && keyw - imgX <= -5) {
+                                                        keyw += 10;
+                                                    } else if (keyw - imgX <= 10 && keyw - imgX >= 5) {
+                                                        keyw -= 10;
+                                                    }
+                                                }
+                                            }
+                                        } else {
+                                            //个人签字
+                                            keyw = keyw + pyzbx + 10;
+                                            keyh = keyh + pyzby;
+                                            if (keyData.indexOf("||") > 0) {
+                                                keyw += 10;
+                                                if (keyData.length() / 19 >= 4) {
+                                                    keyw += 10;
+                                                }
+                                                if (keyData.contains(pkeyid + "\r")) {
+                                                    keyw -= 10;
+                                                }
+                                            }
+                                            if (Math.abs(keyh - imgY) <= 2) {
+                                                if (keyw - imgX >= -11 && keyw - imgX <= -5) {
+                                                    keyw += 10;
+                                                } else if (keyw - imgX <= 11 && keyw - imgX >= 5) {
+                                                    keyw -= 10;
+                                                }
+                                            }
+                                        }
+                                    } else {
+                                        keyw = keyw + pyzbx + 5;
+                                        keyh = keyh + pyzby;
+                                    }
+                                }
+                                if (pkeyid.length() < 19) {
+                                    keyw = keyw - (float) (10 - pkeyid.length() / 2.0);
+                                }
+//                                System.out.println("page = " + (i + 1) + ", type = " + type + ", keyid = " + pkeyid + ", imgX : " + imgX + ", keyw : " + keyw + ", imgY : "
+//                                        + imgY + ", keyh : " + keyh + ", keyword =" + keyData.replace("\r", "\\r") + ", remarkType = " + taskApp.getRemarkType());
+                                if (Math.abs(imgX - keyw) <= threshold && Math.abs(imgY - keyh) <= threshold) {
+                                    if (type.equals("1")) { //个人
+                                        sucessUser.add(pkeyid);
+                                    }
+                                    if (type.equals("2")) { //企业章
+                                        sucessCompan.add(pkeyid);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            Map<String, String> dataUserMap = new HashMap<>(dataMap);
+            boolean isSign = true;
+            //判断章是否签完
+            List<String> companList = strategyListByDFZX.stream().filter(item -> item.get("type").equals("2")).map(map -> map.get("keyWord").toString()).collect(Collectors.toList());
+            if (!companList.isEmpty()) {
+                Set<String> differentElements = new HashSet<>(companList);
+                sucessCompan.forEach(differentElements::remove);
+                if (!differentElements.isEmpty()) {
+                    isSign = false;
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("id = ").append(taskApp.getId()).append(", 章总共:").append(companList.size()).append(", 剩下:").append(differentElements.size());
+                    for (String element : differentElements) {
+                        sb.append(", ").append(element);
+                    }
+                    System.err.println(sb);
+                }
+            }
+
+//            boolean isSign1 = true;
+//            //判断个人是否签完
+//            List<String> userList = strategyListByDFZX.stream().filter(item -> item.get("type").equals("1")).map(map -> map.get("keyWord").toString()).collect(Collectors.toList());
+//            if (!userList.isEmpty()) {
+//                Set<String> differentElements = new HashSet<>(userList);
+//                sucessUser.forEach(differentElements::remove);
+//                if (!differentElements.isEmpty()) {
+//                    isSign1 = false;
+//                    StringBuilder sb = new StringBuilder();
+//                    sb.append("id = ").append(taskApp.getId()).append(", 人总共:").append(userList.size()).append(", 剩下:").append(differentElements.size());
+//                    for (String element : differentElements) {
+//                        sb.append(", ").append(element);
+//                    }
+//                    System.err.println(sb);
+//                }
+//            }
+            if(!sucessUser.isEmpty() && isSign){
+                for(String user:sucessUser){
+                    for(String mapkey:dataMap.keySet()){
+                        String mapval = dataMap.get(mapkey);
+                        if(mapval.contains(user)){
+                            dataUserMap.remove(mapkey) ;
+                        }
+                    }
+                }
+                for(String company:sucessCompan){
+                    for(String mapkey:dataMap.keySet()){
+                        String mapval = dataMap.get(mapkey);
+                        if(mapval != null && (mapval.equals(company) || mapval.equals(company+"\r"))){
+                            dataUserMap.remove(mapkey) ;
+                        }
+                    }
+                }
+                if(!dataUserMap.isEmpty()){
+                    isSign = false ;
+                }
+                System.out.println(taskApp.getId() +"-"+"个人总共:" + sucessUser.size() + "-剩下-" +dataUserMap.keySet().size());
+            }
+            if (isSign ) {
+                String sql2 = "UPDATE u_information_query set chek_status=2 where id='" + taskApp.getId() + "'";
+                jdbcTemplate.execute(sql2);
+            } else {
+                String sql2 = "UPDATE u_information_query set chek_status=3 where id='" + taskApp.getId() + "'";
+                jdbcTemplate.execute(sql2);
+            }
+            RedisTemplate.delete("chek-" + taskApp.getId());
+        }
+    }
 }

+ 53 - 6
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExcelTabController.java

@@ -60,6 +60,7 @@ import org.springblade.manager.mapper.ExcelTabMapper;
 import org.springblade.manager.mapper.WbsTreeContractMapper;
 import org.springblade.manager.mapper.WbsTreePrivateMapper;
 import org.springblade.manager.service.*;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.utils.*;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.*;
@@ -2007,6 +2008,48 @@ public class ExcelTabController extends BladeController {
         return pdfUrl;
     }
 
+    @GetMapping("/downBussPdf")
+    @ApiOperationSupport(order = 32)
+    @ApiOperation(value = "下载pdf数据")
+    @ApiImplicitParam(name = "id", value = "fileId")
+    public void downBussPdf(String id,HttpServletResponse response) throws Exception {
+        if (id == null || id.trim().isEmpty()) {
+            throw new ServiceException("暂无PDF数据");
+        }
+        //获取节点下的所有表单,和附件,如果表单全是隐藏的,并且没有附件,则提示暂无数据
+        String sql = "select name,pdf_url,e_visa_pdf_url,node_pdf_url from u_information_query where id = " +  id;
+        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
+        if (maps.isEmpty()) {
+            throw new ServiceException("暂无PDF数据");
+        } else  {
+            Map<String, Object> stringObjectMap = maps.get(0);
+            String pdfUrl = stringObjectMap.get("pdf_url") == null ? "" : stringObjectMap.get("pdf_url") + "";
+            String fileName = stringObjectMap.get("name") == null ? "找不到文件题名" : stringObjectMap.get("name") + "";
+            if (Func.isNotEmpty(stringObjectMap.get("node_pdf_url"))) {
+                pdfUrl = stringObjectMap.get("node_pdf_url") == null ? "" : stringObjectMap.get("node_pdf_url") + "";
+            } else if (Func.isNotEmpty(stringObjectMap.get("e_visa_pdf_url"))) {
+                //优先使用电签的pdf
+                pdfUrl = stringObjectMap.get("e_visa_pdf_url") == null ? "" : stringObjectMap.get("e_visa_pdf_url") + "";
+            }
+            if (pdfUrl.isEmpty()) {
+                throw new ServiceException("暂无PDF数据");
+            }
+//            fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
+            InputStream redio = CommonUtil.getOSSInputStream(pdfUrl);
+            byte[] buffer = IoUtil.readToByteArray(redio);
+            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
+            response.setContentType("application/pdf");
+            response.setCharacterEncoding("UTF-8");
+            fileName = fileName.replaceAll("/", "_");
+            String encode = URLEncoder.encode(fileName, "UTF-8");
+            encode = encode.replaceAll( "%2B", "+");
+            response.setHeader("Content-disposition", "attachment;filename=" + encode + ".pdf");
+            toClient.write(buffer);
+            toClient.flush();
+            toClient.close();
+        }
+    }
+
 
     /**
      * 用户端删除复制信息表
@@ -2025,8 +2068,10 @@ public class ExcelTabController extends BladeController {
     @PostMapping("/save_buss_data")
     @ApiOperationSupport(order = 13)
     @ApiOperation(value = "填报页面数据保存", notes = "填报页面数据保存")
-    public R saveBussData2(@Valid @RequestBody JSONObject dataInfo) throws Exception {
-
+    public R saveBussData2(@Valid @RequestBody JSONObject dataInfo,Boolean flag) throws Exception {
+        if(flag==null){
+            flag=true;
+        }
         ExecutionTime executionTime = new ExecutionTime();
         executionTime.info("----计划开始----");
         JSONArray dataArray = new JSONArray();
@@ -2087,7 +2132,7 @@ public class ExcelTabController extends BladeController {
         }
 
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType);
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,singnType,flag);
         RandomNumberHolder.RandomTemplateTypeclear();
         RandomNumberHolder.RandomWbsTreeContractclear();
         executionTime.info("----数据保存结束----");
@@ -2361,7 +2406,7 @@ public class ExcelTabController extends BladeController {
         //公式填充
         this.excelTabService.formulaFillData(tableInfoList, Long.parseLong(nodeId), ExecuteType.INSPECTION);
         //保存数据到数据库
-        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,"");
+        R<Object> result = this.excelTabService.saveOrUpdateInfo(tableInfoList,"",true);
         if (!result.isSuccess()) {
             R.fail(result.getMsg());
             return;
@@ -2827,6 +2872,7 @@ public class ExcelTabController extends BladeController {
                 List<Map<String, Object>> businessDataMap = this.jdbcTemplate.queryForList(querySql);
 
                 if (businessDataMap.size() > 0) {
+                    DataStructureFormatUtils.parseDataByKey(businessDataMap);
                     // 匹配关联
                     try {
                         if (tableNode2.getHtmlUrl() != null) {
@@ -3197,6 +3243,7 @@ public class ExcelTabController extends BladeController {
             List<Map<String, Object>> businessDataMap = this.jdbcTemplate.queryForList(querySql);
             Map<String, Object> reData=new HashMap<>();
             if (businessDataMap.size() > 0){
+                DataStructureFormatUtils.parseDataByKey(businessDataMap);
                 try {
                     if (tableNode2.getHtmlUrl() != null){
                         InputStream inputStreamByUrl = FileUtils.getInputStreamByUrl(tableNode2.getHtmlUrl());
@@ -3503,7 +3550,7 @@ public class ExcelTabController extends BladeController {
                         for (Map<String, Object> mysqlData : businessDataMapList) {
                             //数据结果
                             Map<String, Object> reData = new HashMap<>();
-
+                            DataStructureFormatUtils.parseDataByKey(mysqlData);
                             for (String key : mysqlData.keySet()) {
                                 String tabVal = mysqlData.get(key) + "";
                                 // 时间段处理
@@ -4731,7 +4778,7 @@ public class ExcelTabController extends BladeController {
                     js.put("signType", "1");
                 }*/
 
-                this.saveBussData2(js);
+                this.saveBussData2(js,true);
             }
         } catch (Exception e) {
             return null;

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/ExctabCellController.java

@@ -125,7 +125,7 @@ public class ExctabCellController extends BladeController {
                 continue;
             }
             if (exctabCell.getTextInfo().equals(info.getEName())
-                    && (!exctabCell.getTextElementType().equals(info.getEType()) || !exctabCell.getTextDeviation().equals(info.getEAllowDeviation()))) {
+                    && ((exctabCell.getTextElementType() != null && !exctabCell.getTextElementType().equals(info.getEType())) || (exctabCell.getTextDeviation()!= null && !exctabCell.getTextDeviation().equals(info.getEAllowDeviation())))) {
                 //修改对应关联的元素表中的元素信息
                 info.setEType(exctabCell.getTextElementType());
                 info.setEAllowDeviation(exctabCell.getTextDeviation());

+ 3 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FirstController.java

@@ -33,6 +33,7 @@ import org.springblade.manager.service.*;
 import org.springblade.manager.service.impl.ContractInfoServiceImpl;
 import org.springblade.manager.service.impl.TableInfoServiceImpl;
 import org.springblade.manager.service.impl.WbsTreePrivateServiceImpl;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.resource.feign.CommonFileClient;
 import org.springblade.resource.feign.IOSSClient;
@@ -555,6 +556,7 @@ public class FirstController extends BladeController {
                             List<Map<String, Object>> businessDataMapList = this.jdbcTemplate.queryForList("SELECT * FROM " + tableId.getTabEnName() + " WHERE group_id = " + json.getString("id"));
                             if (businessDataMapList.size() > 0) {
                                 for (Map<String, Object> mysqlData : businessDataMapList) {
+                                    DataStructureFormatUtils.parseDataByKey(mysqlData);
                                     for (String key : mysqlData.keySet()) {
                                         String tabVal = mysqlData.get(key) + "";
                                         // 时间段处理
@@ -719,6 +721,7 @@ public class FirstController extends BladeController {
                             List<Map<String, Object>> businessDataMapList = this.jdbcTemplate.queryForList("SELECT * FROM " + tableId.getTabEnName() + " WHERE group_id = " + json.getString("id"));
                             if (businessDataMapList.size() > 0) {
                                 for (Map<String, Object> mysqlData : businessDataMapList) {
+                                    DataStructureFormatUtils.parseDataByKey(mysqlData);
                                     for (String key : mysqlData.keySet()) {
                                         String tabVal = mysqlData.get(key) + "";
                                         // 时间段处理

+ 50 - 4
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/NodeBaseInfoController.java

@@ -19,6 +19,7 @@ package org.springblade.manager.controller;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.nacos.shaded.com.google.protobuf.ServiceException;
 import com.alibaba.nacos.shaded.io.opencensus.metrics.LongGauge;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.google.gson.Gson;
@@ -37,6 +38,7 @@ import org.springblade.core.tool.utils.Func;
 import org.springblade.manager.entity.WbsTreeContract;
 import org.springblade.manager.service.IExcelTabService;
 import org.springblade.manager.service.IWbsTreeContractService;
+import org.springblade.manager.utils.RandomNumberHolder;
 import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
@@ -51,6 +53,7 @@ import org.springblade.core.boot.ctrl.BladeController;
 
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  *  控制器
@@ -158,15 +161,58 @@ public class NodeBaseInfoController extends BladeController {
                 this.synPDFInfo(wbsTreeContract.get(0).getContractId(), nodeBaseInfo.getNodeId()+"", "2", wbsTreeContract.get(0).getProjectId(),dataMap2);
             }
         }
-        return R.status(update);
+        String logMessage = RandomNumberHolder.getLogMessage();
+        RandomNumberHolder.clearLogMessage();
+        if(StringUtils.isNotEmpty(logMessage)){
+            return R.success("保存成功,表单"+logMessage+" 刷新失败");
+        }
+        return R.success("保存成功");
 	}
 
 
     @GetMapping("/getNameRuleByRule")
     @ApiOperationSupport(order = 32)
     @ApiOperation(value = "节点配置根据选择的文件题名规则获取文件题名", notes = "传入规则和节点pkeyId")
-    public R getNameRuleByRule(@RequestParam String nameRule,@RequestParam Long pkeyId){
-        return R.data( nodeBaseInfoService.getNameRuleByRule(nameRule,pkeyId));
+    public R getNameRuleByRule(@RequestParam String nameRule,@RequestParam Long pkeyId) throws ServiceException {
+            String sql="select * from m_wbs_tree_contract where p_key_id="+pkeyId;
+            WbsTreeContract contract = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+            if(contract==null){
+                throw new ServiceException("节点不存在");
+            }
+            String ancestorsPId = contract.getAncestorsPId();
+            if (ancestorsPId.startsWith("0,")) {
+                ancestorsPId = ancestorsPId.substring(2);
+            }
+            ancestorsPId=ancestorsPId+","+contract.getPKeyId();
+            String sql1="select  REPLACE(REPLACE(node_name, CHAR(10), ''), CHAR(13), '') as node_name,node_type from m_wbs_tree_contract where p_key_id in ("+ancestorsPId+") and is_deleted=0";
+            List<WbsTreeContract> nodeNames = jdbcTemplate.query(sql1, new BeanPropertyRowMapper<>(WbsTreeContract.class));
+             nameRule = nameRule.trim().replaceAll("(?i:c)", "");
+            List<String> list = Arrays.asList(nameRule.split("[^.\\d]"));
+            List<Integer> index = list.stream().map(Integer::parseInt).collect(Collectors.toList());
+            Map<Integer, String> map = nodeNames.stream()
+                    .collect(Collectors.toMap(
+                            WbsTreeContract::getNodeType,
+                            WbsTreeContract::getNodeName,
+                            (existing, replacement) -> replacement // 如果键重复,保留后者
+                    ));
+            StringBuilder result = new StringBuilder("");
+            for (Integer i : index) {
+                if(i==0){
+                    if(map.containsKey(1)){
+                        result.append(map.get(1));
+                    }
+                }
+                else if(i==1){
+                    if(map.containsKey(18)){
+                        result.append(map.get(18));
+                    }
+                }else {
+                    if(map.containsKey(i)){
+                        result.append(map.get(i));
+                    }
+                }
+            }
+        return R.data(result.toString());
     }
 
     public R synPDFInfo(String contractId, String nodeId, String classify, String projectId,Map<Long,Map<String,Object>>dataMap) {
@@ -214,7 +260,7 @@ public class NodeBaseInfoController extends BladeController {
                 }
                 js2.put("orderList", array);
                 js.put("dataInfo", js2);
-                controller.saveBussData2(js);
+                controller.saveBussData2(js,false);
         } catch (Exception e) {
             return null;
         }

+ 1 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TrialSummaryClassificationConfigurationController.java

@@ -170,6 +170,7 @@ public class TrialSummaryClassificationConfigurationController extends BladeCont
                         .in(WbsTreePrivate::getParentId, ids).eq(WbsTreePrivate::getProjectId, projectId)
                         .eq(WbsTreePrivate::getWbsType, wbsType)
                         .eq(WbsTreePrivate::getType, 2)
+                        .isNull(WbsTreePrivate::getTrialTabContractId)
                         .eq(WbsTreePrivate::getWbsId, wbsId));
                 List<SelectedTabVO> list = new ArrayList<>();
                 for (WbsTreePrivate wbsTreePrivate : wbsTreePrivates) {

+ 4 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreeContractController.java

@@ -561,6 +561,10 @@ public class WbsTreeContractController extends BladeController {
                 Elements tdElements2 = tr2.select("td");
                 for (int j = 0; j < tdElements1.size(); j++) {
                     Element td1 = tdElements1.get(j);
+                    // 检查td1是否包含dqid属性,如果包含则跳过
+                    if (td1.attr("dqid").length() > 0) {
+                        continue;
+                    }
                     Element td2 = tdElements2.get(j);
                     String keyName = getKeyNameFromChildElement(td1);
                     if (StringUtils.isNotEmpty(keyName)) {

+ 2 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/ExcelTabClientImpl.java

@@ -12,8 +12,6 @@ import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.jsoup.nodes.Node;
 import org.jsoup.select.Elements;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springblade.business.dto.ReSigningEntrustDto;
 import org.springblade.business.dto.TrialSelfInspectionRecordDTO;
 import org.springblade.business.entity.ContractLog;
@@ -22,6 +20,7 @@ import org.springblade.business.feign.ContractLogClient;
 import org.springblade.business.feign.EntrustInfoServiceClient;
 import org.springblade.business.feign.InformationQueryClient;
 import org.springblade.common.utils.CommonUtil;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.tool.api.R;
@@ -38,7 +37,6 @@ import org.springblade.manager.service.IWbsTreePrivateService;
 import org.springblade.manager.utils.ExcelInfoUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.utils.RandomNumberHolder;
-import org.springblade.manager.vo.AppWbsTreeContractVO;
 import org.springblade.manager.vo.TrialSelfDataRecordVO1;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
@@ -583,6 +581,7 @@ public class ExcelTabClientImpl implements ExcelTabClient {
                 List<Map<String, Object>> businessDataMap = this.jdbcTemplate.queryForList(querySql);
 
                 if (businessDataMap.size() > 0) {
+                    DataStructureFormatUtils.parseDataByKey(businessDataMap);
                     // 匹配关联
                     try {
                         if (tableNode2.getHtmlUrl()!=null) {

+ 5 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/ExcelTabMapper.xml

@@ -169,6 +169,9 @@
         dept.parent_id,
         dept.name,
         dept.file_type,
+        dept.tab_type,
+        dept.tab_id,
+        info.table_owner as tableOwner,
         (
         SELECT
         CASE WHEN count(1) > 0 THEN 1 ELSE 0 END
@@ -179,6 +182,8 @@
         ) AS "has_children"
         FROM
         m_excel_tab dept
+        LEFT JOIN
+        m_table_info info ON dept.tab_id = info.id
         WHERE
         dept.is_deleted = 0
         <if test="param1!=null and param1!=''">

+ 3 - 3
blade-service/blade-manager/src/main/java/org/springblade/manager/mapper/WbsTreeContractMapper.xml

@@ -1057,17 +1057,17 @@
 
     </select>
     <select id="getSiblingWbsContract" resultType="org.springblade.manager.entity.WbsTreeContract">
-        select * from m_wbs_tree_contract where p_id= (select p_id from m_wbs_tree_contract where p_key_id=#{pKeyId}) and is_deleted=0;
+        select * from m_wbs_tree_contract where p_id= (select p_id from m_wbs_tree_contract where p_key_id=#{pKeyId}) and is_deleted=0 order by sort;
     </select>
     <select id="getWbsTreeContractsByPKeyIds" resultType="org.springblade.manager.entity.WbsTreeContract">
-        select p_key_id,parent_id,p_id,ancestors,ancestors_p_id from m_wbs_tree_contract where p_key_id in (
+        select p_key_id,parent_id,p_id,ancestors,ancestors_p_id,node_type from m_wbs_tree_contract where p_key_id in (
         <foreach collection="pKeyIds" item="pkeyId" separator=",">
             #{pkeyId}
         </foreach>
         ) and is_deleted=0
     </select>
     <select id="getChildWbsTreeContracts" resultType="org.springblade.manager.entity.WbsTreeContract">
-        select p_key_id,ancestors,ancestors_p_id from m_wbs_tree_contract where ancestors_p_id like #{pKeyId}  and is_deleted=0
+        select p_key_id,ancestors,ancestors_p_id from m_wbs_tree_contract where FIND_IN_SET(#{pKeyId}, ancestors_p_id)   and is_deleted=0
     </select>
 
 </mapper>

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IExcelTabService.java

@@ -107,7 +107,7 @@ public interface IExcelTabService extends BaseService<ExcelTab> {
     /**
      * 结果信息持久化
      */
-    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String singType) throws SQLException;
+    R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String singType,Boolean flag) throws SQLException;
 
     Map<String, String> getTablbCols(String pkeyid, String colkey) throws FileNotFoundException;
 

+ 223 - 159
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -18,7 +18,6 @@ import com.spire.xls.ExcelPicture;
 import com.spire.xls.FileFormat;
 import com.spire.xls.Worksheet;
 import com.spire.xls.collections.PicturesCollection;
-import io.swagger.models.auth.In;
 import lombok.AllArgsConstructor;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
@@ -45,6 +44,7 @@ import org.springblade.business.feign.TrialSelfInspectionRecordClient;
 import org.springblade.business.vo.SaveContractLogVO;
 import org.springblade.common.constant.CommonConstant;
 import org.springblade.common.utils.CommonUtil;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.common.vo.DataVO;
 import org.springblade.core.log.exception.ServiceException;
@@ -54,7 +54,6 @@ import org.springblade.core.mp.support.Query;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.secure.BladeUser;
 import org.springblade.core.secure.utils.AuthUtil;
-import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.node.ForestNodeMerger;
 import org.springblade.core.tool.utils.DateUtil;
@@ -75,12 +74,10 @@ import org.springblade.manager.vo.*;
 import org.springblade.resource.feign.NewIOSSClient;
 import org.springblade.system.cache.ParamCache;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.jdbc.core.BeanPropertyRowMapper;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowCallbackHandler;
 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
@@ -92,7 +89,6 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
 import java.io.*;
 import java.net.HttpURLConnection;
 import java.net.URL;
-import java.nio.file.Files;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
@@ -401,6 +397,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                         List<Map<String, Object>> dataMap = this.jdbcTemplate.queryForList(selSql);
                         if (dataMap.size() > 0) {
                             dataMap.forEach(map -> {
+                                DataStructureFormatUtils.parseDataByKey(map);
                                 TableInfo e = new TableInfo();
                                 e.setPkeyId(map.get("p_key_id").toString());
                                 e.setDataMap(new LinkedHashMap<>());
@@ -738,19 +735,20 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             String tabName = tableNode.getInitTableName();
 
             //拼接SQL
-            StringBuilder sql = new StringBuilder("INSERT INTO " + tabName),
-                    keySql = new StringBuilder("id, group_id"),
-                    valSql = new StringBuilder("" + tableInfo.getBusinessId() + ", " + tableInfo.getPkeyId());
+//            StringBuilder sql = new StringBuilder("INSERT INTO " + tabName),
+//                    keySql = new StringBuilder("id, group_id"),
+//                    valSql = new StringBuilder("" + tableInfo.getBusinessId() + ", " + tableInfo.getPkeyId());
 
             //参数
             LinkedHashMap<String, String> dataMap2 = tableInfo.getDataMap();
-            updateFieldLength(tabName, dataMap2);
-            for (String key : dataMap2.keySet()) {
-                keySql.append(", ").append(key);
-                valSql.append(", '").append(dataMap2.get(key)).append("'");
-            }
-
-            sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
+            dataMap2.remove("p_key_id");
+            StringBuilder sql = buildMTableInsertSql(tabName, dataMap2, tableInfo.getBusinessId(), tableInfo.getPkeyId(), null);
+//            for (String key : dataMap2.keySet()) {
+//                keySql.append(", ").append(key);
+//                valSql.append(", '").append(dataMap2.get(key)).append("'");
+//            }
+//
+//            sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
 
             //新增数据
             try {
@@ -1116,18 +1114,17 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                         for (TableInfo tableInfo : tableInfoList) {
                             //获取字段信息
                             LinkedHashMap<String, String> dataMap2 = tableInfo.getDataMap();
-                            updateFieldLength(table.getTabEnName(),dataMap2);
-                            //拼接SQL
-                            StringBuilder sql = new StringBuilder("INSERT INTO " + table.getTabEnName()),
-                                    keySql = new StringBuilder("id, group_id"),
-                                    valSql = new StringBuilder("" + SnowFlakeUtil.getId() + ", " + firstId);
-
-                            for (String key : dataMap2.keySet()) {
-                                keySql.append(", ").append(key);
-                                valSql.append(", '").append(dataMap2.get(key)).append("'");
-                            }
-
-                            sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
+                            StringBuilder sql = buildMTableInsertSql(table.getTabEnName(), dataMap2, SnowFlakeUtil.getId(), firstId, null);
+//                            // 拼接SQL
+//                            StringBuilder sql = new StringBuilder("INSERT INTO " + table.getTabEnName()),
+//                                    keySql = new StringBuilder("id, group_id"),
+//                                    valSql = new StringBuilder("" + SnowFlakeUtil.getId() + ", " + firstId);
+//                            for (String key : dataMap2.keySet()) {
+//                                keySql.append(", ").append(key);
+//                                valSql.append(", '").append(dataMap2.get(key)).append("'");
+//                            }
+//
+//                            sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
 
                             //新增数据
                             try {
@@ -1221,7 +1218,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
     }
 
     @Override
-    public R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String sigType) {
+    public R<Object> saveOrUpdateInfo(List<TableInfo> tableInfoList,String sigType,Boolean flag) {
         List<TableInfo> tableInfoList2 = new ArrayList<>();
         String fileName1="";
         if (ListUtils.isNotEmpty(tableInfoList)) {
@@ -1233,6 +1230,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 for (TableInfo tableInfo : tableInfoList) {
                     WbsTreeContract wbsTreeContract = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
                             .eq(WbsTreeContract::getPKeyId, tableInfo.getPkeyId()));
+                    StringBuilder tableName = new StringBuilder("");
                     if (wbsTreeContract == null) {
                         continue;
                     }
@@ -1244,21 +1242,21 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                     String delSql = "delete from " + tabName + " where p_key_id=" + tableInfo.getPkeyId();
                     String sqlInfo = "";
                     LinkedHashMap<String, String> dataMap2 = tableInfo.getDataMap();
-                    updateFieldLength(tabName, dataMap2);
                     /*检查发现有p_key_id缺失的情况,导致表单数据丢失,所以强制覆盖*/
                     dataMap2.put("p_key_id", tableInfo.getPkeyId());
+                    sqlInfo = buildMTableInsertSql(tabName, dataMap2, SnowFlakeUtil.getId(), null, null).toString();
                     //统计保存的字段
 
-                    sqlInfo = "INSERT INTO " + tabName + " ( ";
-                    String keyStr = "id,";
-                    String valStr = SnowFlakeUtil.getId() + ",";
-                    for (String keys : dataMap2.keySet()) {
-                        keyStr += keys + ",";
-                        valStr += "'" + dataMap2.get(keys) + "',";
-                    }
-                    keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
-                    valStr = valStr.substring(0, valStr.lastIndexOf(","));
-                    sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
+//                    sqlInfo = "INSERT INTO " + tabName + " ( ";
+//                    String keyStr = "id,";
+//                    String valStr = SnowFlakeUtil.getId() + ",";
+//                    for (String keys : dataMap2.keySet()) {
+//                        keyStr += keys + ",";
+//                        valStr += "'" + dataMap2.get(keys) + "',";
+//                    }
+//                    keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
+//                    valStr = valStr.substring(0, valStr.lastIndexOf(","));
+//                    sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
 
                     WbsTreeContract wbsTreeContractByP = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
                             .eq(WbsTreeContract::getId, wbsTreeContract.getParentId()).eq(WbsTreeContract::getContractId, tableInfo.getContractId()));
@@ -1305,13 +1303,18 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
                         transactionManager1.commit(transactionStatus);
                     } catch (Exception e) {
-                        transactionManager1.rollback(transactionStatus);
-                        log.append(e.getMessage()).append("@@");
-                        e.printStackTrace();
-                        return R.fail(reason(e.getMessage()));
+                        //是否回滚
+                        if(flag){
+                            transactionManager1.rollback(transactionStatus);
+                            log.append(e.getMessage()).append("@@");
+                            e.printStackTrace();
+                            return R.fail(reason(e.getMessage()));
+                        }else {
+                            tableName.append(wbsTreeContract.getNodeName()+",");
+                            RandomNumberHolder.setLogMessage(tableName.toString());
+                        }
                     }
                 }
-
                 //获取节点
                 WbsTreeContract wbsTreeContract = this.wbsTreeContractService.getOne(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getPKeyId, tableInfoList.get(0).getPkeyId()));
                 WbsTreeContract wbsTreeContractByP = wbsTreeContractService.getBaseMapper().selectOne(Wrappers.<WbsTreeContract>query().lambda()
@@ -1354,60 +1357,6 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
        return R.data(tableInfoList2);
        // return R.success(fileName1);
     }
-
-    public void updateFieldLength(String tableName, Map<String, String> fieldNameAndLengthMap) {
-        if (fieldNameAndLengthMap == null || fieldNameAndLengthMap.isEmpty()) {
-            return;
-        }
-        String fields = fieldNameAndLengthMap.keySet().stream().filter(key -> !key.equals("id") && !key.equals("p_key_id") && !key.equals("group_id")).map(key -> "'" + key + "'").collect(Collectors.joining(","));
-        if (fields.isEmpty()) {
-            return;
-        }
-        List<Map<String, Object>> fieldMap = jdbcTemplate.queryForList("select distinct COLUMN_NAME as fieldName, CHARACTER_MAXIMUM_LENGTH as fieldLength from information_schema.COLUMNS where  TABLE_NAME = '" + tableName +
-                "' and COLUMN_NAME in (" + fields + ")");
-        Map<String, Integer> map = fieldMap.stream().collect(toMap(k -> k.get("fieldName") + "", v -> {
-            try {
-                return Integer.parseInt(v.get("fieldLength") + "");
-            } catch (Exception e) {
-                return 0;
-            }
-        }, Math::max));
-
-        List<WbsFormElement> elementList = jdbcTemplate.query("SELECT id,e_key,e_length from m_wbs_form_element WHERE f_id = (SELECT id from m_table_info WHERE tab_en_name = '" + tableName
-                        +"' and is_deleted = 0  limit 1) and is_deleted = 0 and e_key in ( " +  fields + ")", new BeanPropertyRowMapper<>(WbsFormElement.class));
-        StringBuilder sql = new StringBuilder();
-        sql.append("alter table ").append(tableName);
-        elementList.forEach(element -> {
-            String data = fieldNameAndLengthMap.get(element.getEKey());
-            Integer fieldLength = map.get(element.getEKey());
-            if (data != null && element.getELength() != null && data.length() > fieldLength) {
-                int length = data.length();
-                // 取整
-                length = (length / 10 + 1) * 10;
-                if (length < element.getELength()) {
-                    length = element.getELength();
-                    element.setELength(null);
-                } else {
-                    element.setELength(length);
-                }
-                sql.append(" modify column ").append(element.getEKey()).append(" ").append("varchar").append("(").append(length).append("),");
-            }
-        });
-        if (sql.indexOf("modify") > 0) {
-            sql.deleteCharAt(sql.length() - 1);
-            TransactionStatus transactionStatus = this.beginTransaction(transactionManager1);
-            try {
-                jdbcTemplate.batchUpdate("update m_wbs_form_element set e_length = ? where id = ?", elementList.stream().filter(element -> element.getELength() != null).map(element -> new Object[]{element.getELength(), element.getId()}).collect(Collectors.toList()));
-                jdbcTemplate.execute(sql.toString());
-                transactionManager1.commit(transactionStatus);
-            } catch (Exception e) {
-                transactionManager1.rollback(transactionStatus);
-                log.error("更新字段长度失败, error: " + e.getMessage());
-                throw new ServiceException("字段长度超出限制, 系统无法进行扩容,请尝试缩小字段长度或者联系系统管理员处理");
-            }
-        }
-    }
-
     public String reason(String log) {
         /*保存的时候错误提示例如:字段过短提示 yangyj*/
         StringBuilder sb = new StringBuilder();
@@ -1428,6 +1377,110 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         }
         return sb.append("保存异常,请联系管理员").toString();
     }
+    public StringBuilder buildMTableInsertSql(String tabName, Map<String, String> dataMap2, Object id, Object groupId, Object pKeyId) {
+        if (dataMap2 == null || dataMap2.isEmpty() || tabName == null || tabName.isEmpty()) {
+            return new StringBuilder();
+        }
+        //拼接SQL
+        StringBuilder sql = new StringBuilder("INSERT INTO " + tabName),
+                keySql = new StringBuilder(),
+                valSql = new StringBuilder();
+        if (id == null) {
+            if (dataMap2.containsKey("id")) {
+                id = dataMap2.get("id");
+            }
+        }
+        keySql.append("id");
+        valSql.append(id == null ? SnowFlakeUtil.getId() : id);
+        if (groupId ==  null) {
+            groupId = dataMap2.get("group_id");
+        }
+        if (groupId != null) {
+            keySql.append(", group_id");
+            valSql.append(", ").append(groupId);
+        }
+        if (pKeyId == null) {
+            pKeyId = dataMap2.get("p_key_id");
+        }
+        if (pKeyId != null) {
+            keySql.append(", p_key_id");
+            valSql.append(", ").append(pKeyId);
+        }
+        //参数
+        Map<String, String> opsParamMap = new HashMap<>();
+        dataMap2.remove("id");
+        dataMap2.remove("group_id");
+        dataMap2.remove("p_key_id");
+        String key201 = dataMap2.remove("key_201");
+        String fields = dataMap2.keySet().stream().map(key -> "'" + key + "'").collect(Collectors.joining(","));
+        Map<String, Integer> map = new HashMap<>();
+        if (!fields.isEmpty()) {
+            try {
+                fields = fields + ", 'key_201'";
+                List<Map<String, Object>> fieldMap = jdbcTemplate.queryForList("select distinct COLUMN_NAME as fieldName, CHARACTER_MAXIMUM_LENGTH as fieldLength from information_schema.COLUMNS where  TABLE_NAME = '" + tabName +
+                        "' and COLUMN_NAME in (" + fields + ")");
+                map = fieldMap.stream().collect(toMap(k -> k.get("fieldName") + "", v -> {
+                    try {
+                        return Integer.parseInt(v.get("fieldLength") + "");
+                    } catch (Exception e) {
+                        return 0;
+                    }
+                }, Math::min));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        if (key201 != null) {
+            Map<String, String> map1 = DataStructureFormatUtils.parseDataByKey(key201);
+            if (!map1.isEmpty()) {
+                opsParamMap.putAll(map1);
+            }
+        }
+        for (String key : dataMap2.keySet()) {
+            String[] split = key.split("_");
+            if (split.length > 1 && Integer.parseInt(split[1]) > 80) {
+                // 大于80则保留在扩展字段中
+                opsParamMap.put(key, dataMap2.get(key));
+            } else {
+                String value = dataMap2.get(key);
+                if (value != null) {
+                    Integer i = map.get(key);
+                    // 长度超过数据库长度也保留在扩展字段中
+                    if (i != null &&  value.length() > i) {
+                        opsParamMap.put(key, dataMap2.get(key));
+                        continue;
+                    }
+                }
+                keySql.append(", ").append(key);
+                valSql.append(", '").append(value).append("'");
+            }
+        }
+        if (!opsParamMap.isEmpty()) {
+            keySql.append(", key_201");
+            String data = DataStructureFormatUtils.buildData(opsParamMap);
+            try {
+                if (!map.containsKey( "key_201")) {
+                    jdbcTemplate.execute("alter table " + tabName + " add column key_201 text");
+                } else  {
+                    Integer i = map.get("key_201");
+                    if (data.length() > i) {
+                        if (i < 10000) {
+                            // 65535 byte
+                            jdbcTemplate.execute("alter table " + tabName + " modify column key_201 text");
+                        }else {
+                            // 16777215 byte
+                            jdbcTemplate.execute("alter table " + tabName + " modify column key_201 mediumtext");
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            valSql.append(", '").append(data).append("'");
+        }
+        sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
+        return sql;
+    }
 
     // 获取用户
     @Override
@@ -1690,6 +1743,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
         if (dataIn != null && dataIn.size() >= 1) {
             Map<String, Object> mysqlData = dataIn.get(0);
+            DataStructureFormatUtils.parseDataByKey(mysqlData);
             for (String key : mysqlData.keySet()) {
                 String tabVal = mysqlData.get(key) + "";
                 // 时间段处理
@@ -1979,6 +2033,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
         if (dataIn != null && dataIn.size() >= 1) {
             Map<String, Object> mysqlData = dataIn.get(0);
+            DataStructureFormatUtils.parseDataByKey(mysqlData);
             for (String key : mysqlData.keySet()) {
                 String tabVal = mysqlData.get(key) + "";
                 // 时间段处理
@@ -2838,6 +2893,9 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         //实体数据
         String querySql = "select * from " + wbsTreePrivate.getInitTableName() + " where p_key_id=" + pkeyId + " and group_id = " + groupId;
         List<Map<String, Object>> dataIn = jdbcTemplate.queryForList(querySql);
+
+
+
         String keyNames="";
         //匹配关联
         try {
@@ -2854,6 +2912,20 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             htmlString = htmlString.replaceAll("placeholder", "placeholderxx");
             htmlString = htmlString.replaceAll("title", "titlexx");
             Document doc = Jsoup.parse(htmlString);
+
+
+            // 获取默认值
+            Elements elements = doc.getElementsByAttribute("defText");
+            if(Func.isNotEmpty(elements) && elements.size()>=1){
+                for(Element eleme: elements){
+                    String id = Func.isNull(eleme.attr("id"))?eleme.attr("keyname"):eleme.attr("id");
+                    if(Func.isNotEmpty(id)){
+
+                        reData.put(id, eleme.attr("defText"));
+                    }
+                }
+            }
+
             keyNames= getKeyNameList(doc);
             TrialSelfInspectionRecord record = jdbcTemplate.query("select * from u_trial_self_inspection_record where id = " + groupId, new BeanPropertyRowMapper<>(TrialSelfInspectionRecord.class)).stream().findAny().orElse(null);
             // 优先使用试验记录中的委托单和样品
@@ -3070,11 +3142,13 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 reData1=new HashMap<>(reData);
                 if (dataIn.size() >= 1) {
                     Map<String, Object> mysqlData = dataIn.get(0);
+                    DataStructureFormatUtils.parseDataByKey(mysqlData);
                     for (String key : mysqlData.keySet()) {
                         String tabVal = mysqlData.get(key) + "";
 
                         if ((tabVal.contains("BG-") || tabVal.contains("JL-")) && Func.isNotEmpty(contractInfo.getIsTestRecord()) && contractInfo.getIsTestRecord()==1) {
                             //重新生成自己的编号,不引用旧编号
+
                             continue;
                         }
                         // 时间段处理
@@ -3150,25 +3224,14 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                     }
                 }
             }
+
+
         } catch (Exception e) {
             e.printStackTrace();
         }
 
-        // 获取默认值
-        QueryWrapper<TextdictInfo> queryWrapper = new QueryWrapper<>();
-        queryWrapper.select("col_key", "sig_role_name");
-        queryWrapper.eq("type", 4);
-        queryWrapper.eq("tab_id", wbsTreePrivate.getPKeyId());
-        final List<TextdictInfo> textDictInfos = textdictInfoService.getBaseMapper().selectList(queryWrapper);
-        if (!textDictInfos.isEmpty()) {
-            for (TextdictInfo textdictInfo : textDictInfos) {
-                if (reData.containsKey(textdictInfo.getColKey())) {
-                    String keyVal = reData.get(textdictInfo.getColKey()) + "";
-                } else {
-                    reData.put(textdictInfo.getColKey() + "", textdictInfo.getSigRoleName());
-                }
-            }
-        }
+
+
 
         // 移除Id 和 p_key_id
         reData.remove("id");
@@ -3196,13 +3259,13 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 }
             }
         }
-        if(reData1.size()>0){
+        /*if(reData1.size()>0){
             for (Map.Entry<String, Object> entry : reData1.entrySet()) {
                 if(reData.containsKey(entry.getKey())){
                     reData.put(entry.getKey(), entry.getValue());
                 }
             }
-        }
+        }*/
         list.add(reData);
         return list;
     }
@@ -3351,6 +3414,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
         if (dataIn.size() >= 1) {
             Map<String, Object> mysqlData = dataIn.get(0);
+            DataStructureFormatUtils.parseDataByKey(mysqlData);
             for (String key : mysqlData.keySet()) {
                 String tabVal = mysqlData.get(key) + "";
 
@@ -4013,22 +4077,22 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                 //新增SQL
                 String sqlInfo = "";
                 LinkedHashMap<String, String> dataMap2 = tableInfo.getDataMap();
-                updateFieldLength(wbsTreePrivate.getInitTableName() ,dataMap2);
                 if(!dataMap2.containsKey("p_key_id")){
                     if(tableInfo.getPkeyId()!=null&&!tableInfo.getPkeyId().equals("")){
                         dataMap2.put("p_key_id",tableInfo.getPkeyId());
                     }
                 }
-                sqlInfo = "INSERT INTO " + wbsTreePrivate.getInitTableName() + " ( ";
-                String keyStr = "id,group_id,";
-                String valStr = SnowFlakeUtil.getId() + "," + groupId + ",";
-                for (String keys : dataMap2.keySet()) {
-                    keyStr += keys + ",";
-                    valStr += "'" + dataMap2.get(keys) + "',";
-                }
-                keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
-                valStr = valStr.substring(0, valStr.lastIndexOf(","));
-                sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
+                sqlInfo = buildMTableInsertSql(wbsTreePrivate.getInitTableName(), dataMap2, SnowFlakeUtil.getId(), groupId, tableInfo.getPkeyId()).toString();
+//                sqlInfo = "INSERT INTO " + wbsTreePrivate.getInitTableName() + " ( ";
+//                String keyStr = "id,group_id,";
+//                String valStr = SnowFlakeUtil.getId() + "," + groupId + ",";
+//                for (String keys : dataMap2.keySet()) {
+//                    keyStr += keys + ",";
+//                    valStr += "'" + dataMap2.get(keys) + "',";
+//                }
+//                keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
+//                valStr = valStr.substring(0, valStr.lastIndexOf(","));
+//                sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
                 TransactionStatus transactionStatus = this.beginTransaction(transactionManager1);
                 try {
                     //删除
@@ -5281,6 +5345,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
             if (dataIn.size() >= 1) {
                 Map<String, Object> mysqlData = dataIn.get(0);
+                DataStructureFormatUtils.parseDataByKey(mysqlData);
                 for (String key : mysqlData.keySet()) {
                     String tabVal = mysqlData.get(key) + "";
                     // 时间段处理
@@ -5402,6 +5467,14 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
             format= simpleDateFormat.format(mobilizationDate);
         }
+        String jingchang;
+        if(StringUtils.isNotEmpty(format)&&StringUtils.isNotEmpty(representativeCount)){
+            jingchang=format+"/"+representativeCount;
+        } else if (StringUtils.isNotEmpty(format)&&StringUtils.isEmpty(representativeCount)) {
+            jingchang=format;
+        }else {
+            jingchang=representativeCount;
+        }
         setFirstData(doc,"批号",sampleInfo.getBatchNumber(),reData,isCancelList);
         setFirstData(doc,"生产批号",sampleInfo.getBatchNumber(),reData,isCancelList);
         setFirstData(doc,"生产厂家",sampleInfo.getSupplierUnit(),reData,isCancelList);
@@ -5431,7 +5504,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
         setFirstData(doc,"用途(使用在何工程部位)",sampleInfo.getProposedPosition(),reData,isCancelList);
         setFirstData(doc,"成型日期",null,reData,isCancelList);
        // setFirstData(doc,"试件编号",sampleInfo.getSpecificationNumber(),reData,isCancel,isCancelList);
-        setFirstData(doc,"进场日期代表数量",format+"/"+representativeCount+calculationUnit,reData,isCancelList);
+        setFirstData(doc,"进场日期/ 代表数量",jingchang,reData,isCancelList);
         setFirstData(doc,"材料进场日期",format,reData,isCancelList);
 
         if(entrustInfo != null){
@@ -5509,66 +5582,56 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
      * @param reData
      */
     private static void  setFirstData(Document doc, String elementValue,Object value,Map<String, Object> reData,List<String> isCancelList) {
-
         if(value==null){
             value="";
         }
         Elements select = doc.select("[placeholderxx=" + elementValue + "]");
-
         if(select.isEmpty()){//没找到加上:继续找
             String elementValueNew = elementValue + ":";
             select = doc.select("[placeholderxx=" + elementValueNew + "]");
         }
-        if(select.isEmpty()){// 以传入的参数为结尾 继续找
-            select = doc.select("[placeholderxx$=" + elementValue + "]");
+        if(select.isEmpty()){
+            if(!elementValue.equals("代表数量")){
+                // 以传入的参数为结尾 继续找
+                select = doc.select("[placeholderxx$=" + elementValue + "]");
+            }
         }
-
         if (!select.isEmpty()) {//找到元素后  获取输入框
-
             Element textareaElement = select.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
             if( (elementValue.contains("时间") || elementValue.contains("日期")) && textareaElement == null){//特殊处理日期 没有id属性获取keyName
                 textareaElement = select.first();
                 String keyName = textareaElement.attr("keyName");
                 if(ObjectUtil.isNotEmpty(value)){
-                    reData.put(keyName, value);
+                    if(!reData.containsKey(keyName)||reData.get(keyName)==null||reData.get(keyName).equals("")){
+                        reData.put(keyName, value);
+                    }
                 }
-
                 return ;
             }
             if(textareaElement != null){//正常情况
                 String id = textareaElement.attr("id");
                 isCancelList.add(id);
                 if(ObjectUtil.isNotEmpty(value)){
-                    reData.put(id, value);
-                }
-            }
-
-        } else {// 没有找到 可能格式不同 换一种方式找
-            Elements select2 = doc.select("[titlexx$="+elementValue+"]");
-            if(select2.isEmpty()){//还是没找到  进入特殊情况
-                if(elementValue.equals("进场日期代表数量")){
-                    Elements select1 = doc.select("[titlexx=\"进场日期/ 代表数量\"]");
-                    Element textareaElement = select1.stream().filter(element -> element.tagName().equals("el-input")).findFirst().orElse(null);
-                    if(textareaElement != null){
-                        List<Node> nodes = textareaElement.childNodes();
-                        Node node = nodes.get(1);
-                        String id = node.attributes().get("id");
-                        if(ObjectUtil.isNotEmpty(value)){
-                            reData.put(id, value);
-                        }
-
+                    if(!reData.containsKey(id)||reData.get(id)==null||reData.get(id).equals("")){
+                        reData.put(id, value);
                     }
-                }else {
-                    System.out.println("没有找到[" + elementValue + "]的元素");
                 }
-            }else {
-                //另一种方式找到后 获取id的值并赋值到map
+            }
+        } else {
+            Elements select2 = null;
+            if(!elementValue.equals("代表数量")){
+                // 没有找到 可能格式不同 换一种方式找
+                select2= doc.select("[titlexx$="+elementValue+"]");
+            }
+            if(select2!=null&&!select2.isEmpty()){
                 Element textareaElement = select2.first();
                 if(textareaElement != null){//正常情况
                     String id = textareaElement.attr("id");
                     isCancelList.add(id);
                     if(ObjectUtil.isNotEmpty(value)){
-                        reData.put(id, value);
+                        if(!reData.containsKey(id)||reData.get(id)==null||reData.get(id).equals("")){
+                            reData.put(id, value);
+                        }
                     }
                 }
             }
@@ -5705,6 +5768,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
 
             if (dataIn.size() >= 1) {
                 Map<String, Object> mysqlData = dataIn.get(0);
+                DataStructureFormatUtils.parseDataByKey(mysqlData);
                 for (String key : mysqlData.keySet()) {
                     String tabVal = mysqlData.get(key) + "";
                     // 时间段处理
@@ -6363,7 +6427,7 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
             }
         }
         //表单排序
-        resultList.sort(new ExcelTabServiceImpl.WbsTreeContractComparator());
+        resultList.sort(new WbsTreeContractComparator());
         //根据规则生成编号
         List<String> numbers = generateNumbers(dto);
         //构造入库数据

+ 5 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java

@@ -49,6 +49,7 @@ import org.springblade.manager.formula.*;
 import org.springblade.manager.formula.impl.*;
 import org.springblade.manager.mapper.*;
 import org.springblade.manager.service.*;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.utils.*;
 import org.springblade.manager.vo.*;
 import org.springblade.meter.entity.*;
@@ -1109,7 +1110,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     FormData ft = tec.formDataMap.get(k.getCode());
                     if (ft.getCoordsList().size() > 5 || (k.getEName().contains("实测值") && !k.getEName().contains("设计值") && !k.getEName().contains("合格率"))) {
                         tec.checkItems.add(ft);
-                    } else if (k.getEName().contains("检验日期")) {
+                    } else if (k.getEName().contains("检验日期")||k.getEName().contains("检验时间")) {
                         tec.checkDate.add(ft);
                     }
                 });
@@ -2374,6 +2375,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                     //不为空的元素
                     if (mapsList.size() > 0) {
                         for (Map<String, Object> stringObjectMap : mapsList) {
+                            DataStructureFormatUtils.parseDataByKey(stringObjectMap);
                             for (String s : stringObjectMap.keySet()) {
                                 if (ObjectUtil.isNotEmpty(stringObjectMap.get(s)) && !s.equals("id") && !s.equals("p_key_id")) {
                                     maps.put(s, stringObjectMap.get(s));
@@ -6233,6 +6235,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
         List<Map<String, Object>> mapList = jdbcTemplate.queryForList(sql);
         Map<String, String> remap = new HashMap<>();
         for (Map<String, Object> map : mapList) {
+            DataStructureFormatUtils.parseDataByKey(map);
             for (String key : map.keySet()) {
                 String[] keyData = (map.get(key)+"").split("☆");
                 if(keyData!=null && keyData.length>=1){
@@ -6531,6 +6534,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
 
         if (dataIn != null && dataIn.size() >= 1) {
             Map<String, Object> mysqlData = dataIn.get(0);
+            DataStructureFormatUtils.parseDataByKey(mysqlData);
             for (String key : mysqlData.keySet()) {
                 String tabVal = mysqlData.get(key) + "";
                 // 时间段处理

+ 3 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ServicePlanServiceImpl.java

@@ -49,6 +49,7 @@ import org.springblade.manager.bean.TableInfo;
 import org.springblade.manager.dto.ServicePlanDTO;
 import org.springblade.manager.dto.ServiceUserDto;
 import org.springblade.manager.entity.*;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.utils.FileUtils;
 import org.springblade.manager.vo.ServicePlanVO;
 import org.springblade.manager.mapper.ServicePlanMapper;
@@ -518,6 +519,7 @@ public class ServicePlanServiceImpl extends BaseServiceImpl<ServicePlanMapper, S
         try {
             if (dataIn.size() >= 1) {
                 Map<String, Object> mysqlData = dataIn.get(0);
+                DataStructureFormatUtils.parseDataByKey(mysqlData);
                 for (String key : mysqlData.keySet()) {
                     String tabVal = mysqlData.get(key) + "";
                     // 时间段处理
@@ -801,6 +803,7 @@ public class ServicePlanServiceImpl extends BaseServiceImpl<ServicePlanMapper, S
             keyNames= getKeyNameList(doc);
                 if (dataIn.size() >= 1) {
                     Map<String, Object> mysqlData = dataIn.get(0);
+                    DataStructureFormatUtils.parseDataByKey(mysqlData);
                     for (String key : mysqlData.keySet()) {
                         String tabVal = mysqlData.get(key) + "";
                         // 时间段处理

+ 169 - 192
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java

@@ -95,9 +95,21 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
     @Override
     public Boolean initTable(List<WbsFormElement> elementList, String tableName) {
-        String sql = createSQL(elementList);
+        List<WbsFormElement> collect = elementList.stream().filter(element -> {
+            String eKey = element.getEKey();
+            String[] split = eKey.split("_");
+            if (split.length > 1 && StringUtil.isNumeric(split[1])) {
+                int i = Integer.parseInt(split[1]);
+                return i <= 80;
+            }
+            return true;
+        }).collect(Collectors.toList());
+        String sql = createSQL(collect);
         try {
             boolean b = wbsFormElementMapper.createTable(sql, tableName) >= 0;
+            if (b) {
+                alterMTableOpsFiled(tableName);
+            }
             return b;
         } catch (Exception e) {
             return true;
@@ -147,6 +159,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public WbsFormElement saveAndSyn(WbsFormElement wbsFormElement, String tableName) {
 
         String isExitSql = "select * from information_schema.TABLES where TABLE_NAME='" + tableName + "'";
@@ -164,28 +177,19 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
             tableName = tableInfo.getTabEnName();
         }
 
-
-        //当前表总字段长度
-        int sumLength = baseMapper.selectSumColumnLength(jdbcTemplate.queryForObject("SELECT DATABASE()", String.class), tableName);
-        if (sumLength + wbsFormElement.getELength() > MYSQL_MAX_COLUMN_LENGTH) {
-            updateTableFieldLength(tableName);
-            throw new ServiceException("无法添加字段,可用长度:" + (MYSQL_MAX_COLUMN_LENGTH - sumLength) + ",已自动调整其他字段长度,请重新添加");
-        }
         try {
-            // 删除 元素和实体表不匹配的字段
-            //baseMapper.deleteElementByfId2();
-
             //获取当前表单下所有元素
             List<WbsFormElement> wbsFormElements = baseMapper.selectList(Wrappers.<WbsFormElement>query().lambda().eq(WbsFormElement::getFId, wbsFormElement.getFId()));
             String substring = "";
             List<String> eKeyNum = new ArrayList<>();
+            long newFiled = 0;
             if (wbsFormElements.size() > 0) {
                 for (WbsFormElement formElement : wbsFormElements) {
                     String eKey = formElement.getEKey();
                     substring = eKey.split("_")[1];
                 }
                 if (StringUtils.isNotEmpty(substring)) {
-                    long newFiled = Long.parseLong(substring) + 1;
+                    newFiled = Long.parseLong(substring) + 1;
                     String substring1 = "key_" + newFiled;
                     eKeyNum.add(substring1);
                     if (wbsFormElement.getEType() == 4) {
@@ -201,75 +205,67 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
             StringBuilder sbr1 = new StringBuilder();
             String fieldType = WbsElementUtil.getInitTableFiledType(wbsFormElement.getEType());
-
-            if ("varchar".equals(fieldType)) {
-                if (wbsFormElement.getELength() > 1000 || wbsFormElement.getELength() < 10) {
-                    throw new ServiceException("请输入正确的长度,范围为10-1000");
-                } else {
-                    //新增
-                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                    baseMapper.insert(wbsFormElement);
-
-                    //同步
-                    //sbr1.append(" ").append(fieldType).append("(").append(wbsFormElement.getELength()).append(")");
-
-                    sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
-                    String sql = newName + " " + sbr1;
-                    baseMapper.alterAddFiled(sql, tableName);
-                    return wbsFormElement;
-                }
-
-            } else if ("bigint".equals(fieldType)) {
-                if (wbsFormElement.getELength() > 255 || wbsFormElement.getELength() < 10) {
-                    throw new ServiceException("请输入正确的长度,范围为10-255");
-                } else {
-                    //新增
-                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                    baseMapper.insert(wbsFormElement);
-
-                    //同步
-                    //sbr1.append(" ").append(fieldType).append("(").append(wbsFormElement.getELength()).append(")");
-
-                    sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
-                    String sql = newName + " " + sbr1;
-                    baseMapper.alterAddFiled(sql, tableName);
-                    return wbsFormElement;
-                }
-
-            } else if ("decimal".equals(fieldType)) {
-                if (wbsFormElement.getELength() > 65 || wbsFormElement.getELength() < 10) {
-                    throw new ServiceException("请输入正确的长度,范围为10-65");
-                } else {
-                    //新增
-                    baseMapper.insert(wbsFormElement);
-
-                    //同步
-                    //sbr1.append(" ").append(fieldType).append("(").append(wbsFormElement.getELength()).append(")");
-
-                    sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
-                    String sql = newName + " " + sbr1;
-                    baseMapper.alterAddFiled(sql, tableName);
-                    return wbsFormElement;
-                }
-            } else if ("datetime".equals(fieldType)) {
-                if (wbsFormElement.getELength() > 100 || wbsFormElement.getELength() < 0) {
-                    throw new ServiceException("请输入正确的长度,范围为0-100");
-                } else {
-                    //新增
-                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                    baseMapper.insert(wbsFormElement);
-
-                    //同步
-                    //sbr1.append(" ").append(fieldType).append("(").append(0).append(")");
-
-                    sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
-                    String sql = newName + " " + sbr1;
-                    baseMapper.alterAddFiled(sql, tableName);
-                    return wbsFormElement;
+            if (newFiled > 80) {
+                alterMTableOpsFiled(tableName);
+                baseMapper.insert(wbsFormElement);
+            } else {
+                if ("varchar".equals(fieldType)) {
+                    if (wbsFormElement.getELength() > 1000 || wbsFormElement.getELength() < 10) {
+                        throw new ServiceException("请输入正确的长度,范围为10-1000");
+                    } else {
+                        //新增
+                        wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                        baseMapper.insert(wbsFormElement);
+                        sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
+                        String sql = newName + " " + sbr1;
+                        baseMapper.alterAddFiled(sql, tableName);
+                        return wbsFormElement;
+                    }
+                } else if ("bigint".equals(fieldType)) {
+                    if (wbsFormElement.getELength() > 255 || wbsFormElement.getELength() < 10) {
+                        throw new ServiceException("请输入正确的长度,范围为10-255");
+                    } else {
+                        //新增
+                        wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                        baseMapper.insert(wbsFormElement);
+                        sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
+                        String sql = newName + " " + sbr1;
+                        baseMapper.alterAddFiled(sql, tableName);
+                        return wbsFormElement;
+                    }
+                } else if ("decimal".equals(fieldType)) {
+                    if (wbsFormElement.getELength() > 65 || wbsFormElement.getELength() < 10) {
+                        throw new ServiceException("请输入正确的长度,范围为10-65");
+                    } else {
+                        //新增
+                        baseMapper.insert(wbsFormElement);
+                        sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
+                        String sql = newName + " " + sbr1;
+                        baseMapper.alterAddFiled(sql, tableName);
+                        return wbsFormElement;
+                    }
+                } else if ("datetime".equals(fieldType)) {
+                    if (wbsFormElement.getELength() > 100 || wbsFormElement.getELength() < 0) {
+                        throw new ServiceException("请输入正确的长度,范围为0-100");
+                    } else {
+                        //新增
+                        wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                        baseMapper.insert(wbsFormElement);
+                        sbr1.append(" ").append("varchar").append("(").append(DEFAULT_ELEMENT_LENGTH_VARCHAR).append(")");
+                        String sql = newName + " " + sbr1;
+                        baseMapper.alterAddFiled(sql, tableName);
+                        return wbsFormElement;
+                    }
                 }
             }
 
         } catch (Exception e) {
+            if (e.getMessage().contains("Duplicate column name")) {
+                return wbsFormElement;
+            }
+            if (e.getMessage().contains("Row size too large")) {
+                return wbsFormElement;
+            }
             baseMapper.deleteElement(wbsFormElement);
             throw new ServiceException("同步元素字段异常,操作失败:" + e.getMessage());
         }
@@ -360,6 +356,13 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 //                } else if (eLength >= 0 && eLength <= 65) {
 //                    eLength = DEFAULT_ELEMENT_LENGTH_NUMBER;
 //                }
+                String[] split = eKey.split("_");
+                if (split.length > 1 && StringUtil.isNumeric(split[1])) {
+                    long index = Long.parseLong(split[1]);
+                    if (index > 80) {
+                        continue;
+                    }
+                }
                 Integer length = eLengthMap.get(wbsFormElement.getId());
                 if (length == null || !length.equals(eLength)) {
                     //判断是否存在该Key字段
@@ -368,6 +371,9 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                         try {
                             baseMapper.updateFiledType(initTableName, eKey, "varchar", eLength);
                         } catch (Exception e) {
+                            if (e.getMessage().contains("Row size too large")) {
+                                continue;
+                            }
                             e.printStackTrace();
                             this.updateBatchById(beforeUpdateWbsFormElements);
                             return R.fail(eName + "长度范围超出总最大限制,请尝试缩小当前字段与其他字段长度或者联系系统管理员处理");
@@ -578,18 +584,29 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
                         //String eTypeFiled = getInitTableFiledType(wbsFormElementInfo.getEType());
                         //int eLengthFiled = Integer.parseInt(setDefaultElementLength(wbsFormElementInfo.getEType()));
-
-                        //判断是否存在该Key字段
-                        int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                        if (row1 == 0) {
-                            //追加字段到实体表中
-                            wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                            //判断是否追加成功
-                            int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                            if (row2 != 1) {
-                                //追加失败,删除元素,跳过
-                                baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
-                                continue;
+                        if (newKeyNumber > 80) {
+                            //判断是否存在该Key字段
+                            int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), "key_201");
+                            if (row1 == 0) {
+                                try {
+                                    jdbcTemplate.execute("alter table " + wbsTree.getInitTableName() + " add key_201 text");
+                                } catch (Exception e) {
+                                    e.printStackTrace();
+                                }
+                            }
+                        } else {
+                            //判断是否存在该Key字段
+                            int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                            if (row1 == 0) {
+                                //追加字段到实体表中
+                                wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                                //判断是否追加成功
+                                int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                                if (row2 != 1) {
+                                    //追加失败,删除元素,跳过
+                                    baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
+                                    continue;
+                                }
                             }
                         }
                         newKeyNumber++;
@@ -654,18 +671,29 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
                     //String eTypeFiled = getInitTableFiledType(wbsFormElementInfo.getEType());
                     //int eLengthFiled = Integer.parseInt(setDefaultElementLength(wbsFormElementInfo.getEType()));
-
-                    //判断是否存在该Key字段
-                    int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                    if (row1 == 0) {
-                        //追加字段到实体表中
-                        wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                        //判断是否追加成功
-                        int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                        if (row2 != 1) {
-                            //追加失败,删除元素,跳过
-                            baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
-                            continue;
+                    if (newKeyNumber > 80) {
+                        //判断是否存在该Key字段
+                        int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), "key_201");
+                        if (row1 == 0) {
+                            try {
+                                jdbcTemplate.execute("alter table " + wbsTree.getInitTableName() + " add key_201 text");
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    } else {
+                        //判断是否存在该Key字段
+                        int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                        if (row1 == 0) {
+                            //追加字段到实体表中
+                            wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                            //判断是否追加成功
+                            int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                            if (row2 != 1) {
+                                //追加失败,删除元素,跳过
+                                baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
+                                continue;
+                            }
                         }
                     }
                     newKeyNumber++;
@@ -733,18 +761,29 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
                     //String eTypeFiled = getInitTableFiledType(wbsFormElementInfo.getEType());
                     //int eLengthFiled = Integer.parseInt(setDefaultElementLength(wbsFormElementInfo.getEType()));
-
-                    //判断是否存在该Key字段
-                    int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                    if (row1 == 0) {
-                        //追加字段到实体表中
-                        wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
-                        //判断是否追加成功
-                        int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
-                        if (row2 == 0) {
-                            //追加失败,删除元素,跳过
-                            baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
-                            continue;
+                    if (newKeyNumber > 80) {
+                        //判断是否存在该Key字段
+                        int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), "key_201");
+                        if (row1 == 0) {
+                            try {
+                                jdbcTemplate.execute("alter table " + wbsTree.getInitTableName() + " add key_201 text");
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    } else {
+                        //判断是否存在该Key字段
+                        int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                        if (row1 == 0) {
+                            //追加字段到实体表中
+                            wbsTreeMapper.alterTableFiled(wbsTree.getInitTableName(), key, "varchar", DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                            //判断是否追加成功
+                            int row2 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), key);
+                            if (row2 == 0) {
+                                //追加失败,删除元素,跳过
+                                baseMapper.deleteElementByfId2(wbsFormElementInfo.getId());
+                                continue;
+                            }
                         }
                     }
                     newKeyNumber++;
@@ -923,6 +962,14 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
             for (WbsFormElement listDatum : listData) {
                 // String initTableFiledType = getInitTableFiledType(listDatum.getEType());
                 // int elementLength = getElementLength(initTableFiledType);
+                String[] split = listDatum.getEKey().split("_");
+                if (split.length > 1 && StringUtil.isNumeric(split[1])) {
+                    long index = Long.parseLong(split[1]);
+                    if (index > 80)  {
+                        alterMTableOpsFiled(initTableName);
+                        continue;
+                    };
+                }
                 //同步
                 //判断是否存在该Key字段
                 int row1 = wbsTreeMapper.isThereAField(initTableName, listDatum.getEKey());
@@ -970,87 +1017,17 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     }
 
 
-    /**
-     * 修改当前表所有字段的长度 (只用于字段缩减)
-     * 1、字段数量超过80 表数据超过500条 把数据长度为0的旧字段长度改为50
-     * 超过:新字段的默认长度改为150,并且
-     */
-    public void updateTableFieldLength(String tableName) {
-        TableInfo tableInfo = tableInfoMapper.selectOne(Wrappers.<TableInfo>lambdaQuery()
-                .eq(TableInfo::getTabEnName, tableName)
-                .last("limit 1"));
-
-        List<WbsFormElement> wbsFormElements = baseMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery()
-                .eq(WbsFormElement::getFId, tableInfo.getId()));
-        //元素是否存在
-        if (CollectionUtil.isEmpty(wbsFormElements)) {
-            return;
-        }
-        //字段级字段长度缓存
-        Map<String, Integer> lengthMap = new HashMap<>();
-        //查询当前表的所有字段级字段长度
-        List<Map<String, Object>> filedLengths = baseMapper.selectFiledLength(tableName);
-        //表是否存在
-        if (CollectionUtil.isEmpty(filedLengths)) {
-            return;
-        }
-        for (Map<String, Object> filedLength : filedLengths) {
-            BigInteger length = (BigInteger) filedLength.get("length");
-            if (length == null) {
-                continue;
-            }
-            //记录字段与字段长度
-            lengthMap.put(filedLength.get("key").toString(), length.intValue());
-        }
-
-        //这张表是否拥有数据超过500条
-        Integer count = jdbcTemplate.queryForObject("select count(0) from " + tableName, Integer.class);
-
-
-        for (WbsFormElement wbsFormElement : wbsFormElements) {
-
-            String eKey = wbsFormElement.getEKey();
-            //字段不存在
-            if (lengthMap.get(eKey) == null) {
-                continue;
-            }
-            Integer dataLength = baseMapper.selectFiledDataMaxLength(tableName, eKey);
-
-            if (wbsFormElements.size() > 80 && count > 500) {
-                //数据长度
-                dataLength = dataLength == 0 ? 50 : lengthMap.get(eKey) + 100;
-                //如果当前需要设置的长度大于当前字段长度,则跳过
-                if (dataLength > wbsFormElement.getELength()) {
-                    continue;
-                }
-            } else if (wbsFormElements.size() > 80 && count < 500) {
-                //数据长度
-                dataLength = dataLength == 0 ? 100 : lengthMap.get(eKey) + 100;
-                //如果当前需要设置的长度大于当前字段长度,则跳过
-                if (dataLength > wbsFormElement.getELength()) {
-                    continue;
-                }
-            } else if (wbsFormElements.size() < 80 && count > 500) {
-                //数据长度
-                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
-                //如果当前需要设置的长度大于当前字段长度,则跳过
-                if (dataLength > wbsFormElement.getELength()) {
-                    continue;
-                }
-            } else {
-                //数据长度
-                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
-                //如果当前需要设置的长度大于当前字段长度,则跳过
-                if (dataLength > wbsFormElement.getELength()) {
-                    continue;
-                }
-                if (dataLength < 200) {
-                    dataLength = 200;
+    private void alterMTableOpsFiled(String initTableName) {
+        int row1 = wbsTreeMapper.isThereAField(initTableName, "key_201");
+        if (row1 == 0) {
+            //追加字段到实体表中
+            try {
+                jdbcTemplate.execute("ALTER TABLE " + initTableName + "  ADD COLUMN key_201 text");
+            } catch (Exception e) {
+                if (!e.getMessage().contains("Duplicate column name")) {
+                    log.error("新增字段异常:", e);
                 }
             }
-            baseMapper.updateFiledType(tableName, eKey, "varchar", dataLength);
-            wbsFormElement.setELength(dataLength);
-            baseMapper.updateById(wbsFormElement);
         }
     }
 }

+ 1 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsParamServiceImpl.java

@@ -246,7 +246,7 @@ public class WbsParamServiceImpl extends BaseServiceImpl<WbsParamMapper, WbsPara
                         result.add(param);
                     }
                     //如果是全局的也加进去
-                    if(param.getNameType()==1){
+                    if(param.getNameType()!=null&&param.getNameType()==1){
                         result.add(param);
                     }
                 }

+ 102 - 117
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsSynchronousServiceImpl.java

@@ -32,6 +32,7 @@ import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.rmi.ServerException;
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -634,7 +635,7 @@ public class WbsSynchronousServiceImpl {
             if (wbsTreePrivates.isEmpty()) {
                 throw new ServiceException("无法找到模板对应节点,请检查模板节点");
             }
-
+            Map<Long, WbsTreePrivate> collect1 = wbsTreePrivates.stream().collect(Collectors.toMap(WbsTreePrivate::getPKeyId, Function.identity()));
             //合同同步
             for (ContractInfo contractInfo : contractInfos) {
                 //获取合同下当前节点的数据
@@ -685,114 +686,114 @@ public class WbsSynchronousServiceImpl {
 
                     //筛选出需要更新的节点  同时做数据隔离
                     List<WbsTreeContract> editContractNodes = new ArrayList<>();
-                    for (WbsTreePrivate templateNode : wbsTreePrivates) {
-                        //更新只跟新表单
-                        for (WbsTreeContract editContractNode : wbsTreeContracts) {
-
-
-                            // 判断模板表与项目表 html是否一致
-                            if (ObjectUtils.equals(templateNode.getPKeyId(), editContractNode.getIsTypePrivatePid())) {
-                                if (templateNode.getType() == 2) {
-                                    //同步范围 当前节点是否允许修改
-                                    Boolean isSync = false;
-
-                                    //是否记录历史html
-                                    Boolean isOldHtml = false;
-
-                                    if (CollectionUtil.isNotEmpty(contractRanges)) {
-                                        switch (Integer.valueOf(wbsTreePrivate.getWbsType())) {
-                                            //质检
-                                            case 1:
-                                                //判断是否已保存
-                                                if (StringUtils.isEmpty(editContractNode.getInitTableName())) {
-                                                    throw new ServiceException(editContractNode.getNodeName() + "( " + editContractNode.getPKeyId() + ")--实体表不存在");
-                                                }
-                                                String isSave = "select count(0) from " + editContractNode.getInitTableName() + " where p_key_id = " + editContractNode.getPKeyId();
-                                                Integer i = jdbcTemplate.queryForObject(isSave, Integer.class);
 
-                                                //判断是否上报审批
-                                                Integer submit = informationQueryMap.get(editContractNode.getPId());
+                    //更新只跟新表单
+                    for (WbsTreeContract editContractNode : wbsTreeContracts) {
+                        if (editContractNode.getType() != 2 || editContractNode.getIsTypePrivatePid() == null) {
+                            continue;
+                        }
+                        WbsTreePrivate templateNode = collect1.get(editContractNode.getIsTypePrivatePid());
 
-                                                if (submit == null && contractRanges.contains(WbsSyncTypeEnum.NOT_FILLED_IN.code)) {
-                                                    //未填报 101
-                                                    isSync = true;
+                        // 判断模板表与项目表 html是否一致
+                        if (templateNode != null) {
+                            if (templateNode.getType() == 2) {
+                                //同步范围 当前节点是否允许修改
+                                Boolean isSync = false;
+
+                                //是否记录历史html
+                                Boolean isOldHtml = false;
+
+                                if (CollectionUtil.isNotEmpty(contractRanges)) {
+                                    switch (Integer.valueOf(wbsTreePrivate.getWbsType())) {
+                                        //质检
+                                        case 1:
+                                            //判断是否已保存
+                                            if (StringUtils.isEmpty(editContractNode.getInitTableName())) {
+                                                throw new ServiceException(editContractNode.getNodeName() + "( " + editContractNode.getPKeyId() + ")--实体表不存在");
+                                            }
+                                            String isSave = "select count(0) from " + editContractNode.getInitTableName() + " where p_key_id = " + editContractNode.getPKeyId();
+                                            Integer i = jdbcTemplate.queryForObject(isSave, Integer.class);
+
+                                            //判断是否上报审批
+                                            Integer submit = informationQueryMap.get(editContractNode.getPId());
+
+                                            if (submit == null && contractRanges.contains(WbsSyncTypeEnum.NOT_FILLED_IN.code)) {
+                                                //未填报 101
+                                                isSync = true;
+                                            } else {
+                                                //没有选择未填报,但是表单查不到数据,表示这个节点有问题
+                                                if (i == 0 && !contractRanges.contains(WbsSyncTypeEnum.NOT_FILLED_IN.code)) {
+                                                    errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未填报;");
                                                 } else {
-                                                    //没有选择未填报,但是表单查不到数据,表示这个节点有问题
-                                                    if (i == 0 && !contractRanges.contains(WbsSyncTypeEnum.NOT_FILLED_IN.code)) {
-                                                        errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未填报;");
+                                                    if (contractRanges.contains(WbsSyncTypeEnum.ALREADY_FILLED_IN_NOT_REPORTED.code) && (submit == null || submit == 0)) {
+                                                        //已填报-未上报 102
+                                                        isSync = true;
                                                     } else {
-                                                        if (contractRanges.contains(WbsSyncTypeEnum.ALREADY_FILLED_IN_NOT_REPORTED.code) && (submit == null || submit == 0)) {
-                                                            //已填报-未上报 102
-                                                            isSync = true;
+                                                        if (submit == null) {
+                                                            isSync = false;
+                                                            errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未上报;");
                                                         } else {
-                                                            if (submit == null) {
-                                                                isSync = false;
-                                                                errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未上报;");
-                                                            } else {
-                                                                if (submit == 1 && contractRanges.contains(WbsSyncTypeEnum.PENDING_APPROVAL.code)) {
-                                                                    //待审批 104
-                                                                    isSync = true;
-                                                                    isOldHtml = true;
-                                                                } else if (submit == 2 && contractRanges.contains(WbsSyncTypeEnum.APPROVED.code)) {
-                                                                    //已审批 105
-                                                                    isSync = true;
-                                                                    isOldHtml = true;
-                                                                }
+                                                            if (submit == 1 && contractRanges.contains(WbsSyncTypeEnum.PENDING_APPROVAL.code)) {
+                                                                //待审批 104
+                                                                isSync = true;
+                                                                isOldHtml = true;
+                                                            } else if (submit == 2 && contractRanges.contains(WbsSyncTypeEnum.APPROVED.code)) {
+                                                                //已审批 105
+                                                                isSync = true;
+                                                                isOldHtml = true;
                                                             }
                                                         }
                                                     }
                                                 }
-                                                break;
-                                            //试验
-                                            case 2:
-                                                break;
-                                            //计量
-                                            case 3:
-                                                break;
-                                            //日志
-                                            case 4:
-                                                break;
-                                            //征地拆迁
-                                            case 5:
-                                                break;
-                                            default:
-                                                break;
-                                        }
-                                    } else {
-                                        isSync = true;
+                                            }
+                                            break;
+                                        //试验
+                                        case 2:
+                                            break;
+                                        //计量
+                                        case 3:
+                                            break;
+                                        //日志
+                                        case 4:
+                                            break;
+                                        //征地拆迁
+                                        case 5:
+                                            break;
+                                        default:
+                                            break;
                                     }
+                                } else {
+                                    isOldHtml = true;
+                                    isSync = true;
+                                }
 
 
-                                    //清表 公式 元素
-                                    if (collect.contains(2) || collect.contains(3) || collect.contains(5)) {
-                                        if (collect.contains(2) && (templateNode.getHtmlUrl() == null || templateNode.getInitTableName() == null || templateNode.getExcelId() == null)) {
-                                            errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未配置清表;");
-                                        } else {
-                                            editContractNode.setExcelId(templateNode.getExcelId());
-                                            editContractNode.setInitTableName(templateNode.getInitTableName());
-                                            editContractNode.setHtmlUrl(templateNode.getHtmlUrl());
-                                            if (templateNode.getExcelId() != null) {
-                                                editContractNode.setIsLinkTable(2);
-                                            }
+                                //清表 公式 元素
+                                if (collect.contains(2) || collect.contains(3) || collect.contains(5)) {
+                                    if (collect.contains(2) && (templateNode.getHtmlUrl() == null || templateNode.getInitTableName() == null || templateNode.getExcelId() == null)) {
+                                        errorMsg.append(editContractNode.getNodeName() + "(" + editContractNode.getPKeyId() + ")").append("未配置清表;");
+                                    } else {
+                                        editContractNode.setExcelId(templateNode.getExcelId());
+                                        editContractNode.setInitTableName(templateNode.getInitTableName());
+                                        editContractNode.setHtmlUrl(templateNode.getHtmlUrl());
+                                        if (templateNode.getExcelId() != null) {
+                                            editContractNode.setIsLinkTable(2);
                                         }
                                     }
-                                    //排序
-                                    if (collect.contains(7)) {
-                                        editContractNode.setSort(templateNode.getSort());
+                                }
+                                //排序
+                                if (collect.contains(7)) {
+                                    editContractNode.setSort(templateNode.getSort());
+                                }
+                                //手动选中的表单 进行筛选
+                                if (collect.contains(2) || collect.contains(3) || collect.contains(4) || collect.contains(5) || collect.contains(6) || collect.contains(7)) {
+                                    if (isSync) {
+                                        editContractNodes.add(editContractNode);
                                     }
-                                    //手动选中的表单 进行筛选
-                                    if (collect.contains(2) || collect.contains(3) || collect.contains(4) || collect.contains(5) || collect.contains(6) || collect.contains(7)) {
-                                        if (isSync) {
-                                            editContractNodes.add(editContractNode);
-                                        }
-                                        //记录历史html
-                                        if (isOldHtml) {
-                                            oldHtml.add(editContractNode);
-                                        }
-
+                                    //记录历史html
+                                    if (isOldHtml) {
+                                        oldHtml.add(editContractNode);
                                     }
-                                    //找到了某个选中节点下与项目节点想同的节点了  提前结束循环,节省资源
-                                    break;
                                 }
                             }
                         }
@@ -800,33 +801,17 @@ public class WbsSynchronousServiceImpl {
 
                     //合同段新增节点
                     List<WbsTreeContract> addContractNode = null;
-                    if (addPrivateNodes != null) {
+                    if (addPrivateNodes != null && (CollectionUtil.isEmpty(collect) || collect.contains(1))) {
                         addContractNode = BeanUtil.copyProperties(addPrivateNodes, WbsTreeContract.class);
                     }
 
-                    //转类型排序
-                    List<Integer> integers = new ArrayList<>(collect);
-                    Collections.sort(integers);
-                    for (Integer i : integers) {
-                        switch (i) {
-                            //添加表单
-                            case 1:
-                                List<WbsTreeContract> list = insertContractForm(wbsTreeSynchronousRecord, contractInfo, wbsTreeContracts, addContractNode, errorMsg);
-                                addData.addAll(list);
-                                break;
-                            //清表配置
-                            case 2:
-                                //元素配置
-                            case 3:
-                                //公式配置
-                            case 5:
-                                //排序
-                            case 7:
-                                editData.addAll(editContractNodes);
-                                break;
-                            default:
-                                break;
-                        }
+                    if (CollectionUtil.isNotEmpty(addContractNode)) {
+                        List<WbsTreeContract> list = insertContractForm(wbsTreeSynchronousRecord, contractInfo, wbsTreeContracts, addContractNode, errorMsg);
+                        addData.addAll(list);
+                    }
+
+                    if (CollectionUtil.isNotEmpty(editContractNodes)) {
+                        editData.addAll(editContractNodes);
                     }
                 }
             }

+ 103 - 24
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeContractServiceImpl.java

@@ -52,6 +52,7 @@ import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.secure.utils.AuthUtil;
+import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.node.ForestNodeMerger;
 import org.springblade.core.tool.utils.*;
@@ -65,6 +66,7 @@ import org.springblade.manager.mapper.*;
 import org.springblade.manager.service.INodeBaseInfoService;
 import org.springblade.manager.service.ITableFileService;
 import org.springblade.manager.service.IWbsTreeContractService;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.utils.CompositeKey;
 import org.springblade.manager.vo.*;
 import org.springblade.system.cache.ParamCache;
@@ -72,6 +74,7 @@ import org.springblade.websocket.feign.WebSocketClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.ByteArrayResource;
 import org.springframework.core.io.Resource;
+import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.http.ContentDisposition;
 import org.springframework.http.HttpHeaders;
@@ -632,7 +635,23 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
 //        if(info!=null){
 //            resultTabs.forEach(tab->tab.setFileName(info.getName()));
 //        }
-
+        //同步标识
+        if (CollectionUtil.isNotEmpty(resultTabs) && SecureUtil.isAdministrator()) {
+            List<Long> collect1 = resultTabs.stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
+            List<Long> longs = null;
+            try {
+                longs = jdbcTemplate.queryForList("select p_key_id from m_wbs_tree_contract_extend where is_sync = 1 and is_deleted = 0 and p_key_id in (" + StringUtils.join(collect1, ",") + ")", Long.class);
+            } catch (DataAccessException e) {
+                //TODO 暂时忽略异常,避免表不存在报错
+                e.printStackTrace();
+            }
+            if (CollectionUtil.isNotEmpty(longs)) {
+                List<Long> finalLongs = longs;
+                resultTabs.forEach(f -> {
+                    f.setIsSync(finalLongs.contains(f.getPKeyId()) && f.getIsBussShow() != 2 ? 1 : 0);
+                });
+            }
+        }
         if (Optional.ofNullable(wbsTreeContract.getIsUseSort()).orElse(0) == 0) {
             //表单排序
             if (resultTabs.size() > 0) {
@@ -894,32 +913,32 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                     break;
                 }
             }
-
-            if (DataMap != null && DataMap.size() >= 1) {
-                String dataCol = "";
+            String dataCol = "";
+            for (int j = 0; j < dataSize; j++) {
+                if (j == dataSize - 1) {
+                    dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j];
+                } else {
+                    dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j] + "☆";
+                }
+            }
+            boolean flag = isSaveKey201(info, wbsInfo, dataCol);
+            if (!DataMap.isEmpty()) {
                 String updateSql = "update " + wbsInfo.getInitTableName() + " set " + info.getKey() + "=";
-                for (int j = 0; j < dataSize; j++) {
-                    if (j == dataSize - 1) {
-                        dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j];
-                    } else {
-                        dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j] + "☆";
-                    }
+                if (flag) {
+                    updateSql = "update " + wbsInfo.getInitTableName() + " set key_201 = concat(IFNULL(key_201,''),'$$'," + "'" + info.getKey() + ":" + dataCol + "') where p_key_id= " + wbsTreeContract.getPKeyId() + ";";
+                } else {
+                    updateSql = updateSql + "'" + dataCol + "' where p_key_id=" + wbsTreeContract.getPKeyId() + " ;";
                 }
-                updateSql = updateSql + "'" + dataCol + "' where p_key_id=" + wbsTreeContract.getPKeyId() + " ;";
                 moreData = moreData.stream().skip(excLenght.length).map(com.mixsmart.utils.StringUtils::handleNull).collect(Collectors.toList());
                 addSql.append(updateSql);
             } else {
                 long dataId = SnowFlakeUtil.getId();
                 String insertSql = "insert into " + wbsInfo.getInitTableName() + "(id,p_key_id," + info.getKey() + ") VALUES (" + dataId + "," + wbsTreeContract.getPKeyId() + ",'";
-                String dataCol = "";
-                for (int j = 0; j < dataSize; j++) {
-                    if (j == dataSize - 1) {
-                        dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j];
-                    } else {
-                        dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j] + "☆";
-                    }
+                if (flag) {
+                    insertSql = "insert into " + wbsInfo.getInitTableName() + "(id,p_key_id,key_201) values (" + dataId + "," + wbsTreeContract.getPKeyId() + ",'" + info.getKey() + ":" + dataCol + "');";
+                } else {
+                    insertSql = insertSql + dataCol + "');";
                 }
-                insertSql = insertSql + dataCol + "');";
                 moreData = moreData.stream().skip(excLenght.length).map(com.mixsmart.utils.StringUtils::handleNull).collect(Collectors.toList());
                 addSql.append(insertSql);
             }
@@ -984,7 +1003,11 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                         dataCol = dataCol + moreData.get(j) + "_^_" + excLenght[j] + "☆";
                     }
                 }
-                insertSql = insertSql + dataCol + "');";
+                if (isSaveKey201(info, wbsInfo, dataCol)) {
+                    insertSql = "insert into " + wbsInfo.getInitTableName() + "(id,p_key_id,key_201) values (" + dataId + "," + wbsTreeContract.getPKeyId() + ",'" + info.getKey() + ":" + dataCol + "');";
+                } else {
+                    insertSql = insertSql + dataCol + "');";
+                }
                 moreData = moreData.stream().skip(excLenght.length).map(com.mixsmart.utils.StringUtils::handleNull).collect(Collectors.toList());
                 addSql.append(insertSql);
             }
@@ -1003,6 +1026,31 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         return false;
     }
 
+    private boolean isSaveKey201(RangeInfo info, WbsTreeContract wbsInfo, String dataCol) {
+        boolean flag = false;
+        try {
+            String[] split = info.getKey().split("_");
+            flag = split.length > 1 && StringUtil.isNumeric(split[1]) && Integer.parseInt(split[1]) > 80;
+            if (!flag) {
+                List<Map<String, Object>> fieldMap = jdbcTemplate.queryForList("select distinct COLUMN_NAME as fieldName, CHARACTER_MAXIMUM_LENGTH as fieldLength from information_schema.COLUMNS where  TABLE_NAME = '" + wbsInfo.getInitTableName() +
+                        "' and COLUMN_NAME in ('" + info.getKey() + "', 'key_201" + "')");
+                if (!fieldMap.isEmpty()) {
+                    Map<String, Object> map1 = fieldMap.stream().filter(map -> map.get("fieldName") != null).collect(Collectors.toMap(map -> map.get("fieldName") + "", map -> map.get("fieldLength")));
+                    Object length = map1.get(info.getKey());
+                    if (length != null && Integer.parseInt(length.toString()) < dataCol.length()) {
+                        flag = true;
+                        if (map1.get("key_201") == null) {
+                            jdbcTemplate.execute("alter table " + wbsInfo.getInitTableName() + " add column key_201 text ");
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return flag;
+    }
+
     @Override
     public void syncCurrentFormToAllContract(WbsTreePrivate wbsTreePrivate) {
         baseMapper.syncCurrentFormToAllContract(wbsTreePrivate);
@@ -4506,7 +4554,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         List<WbsTreeContract> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
 
         InputStream templateStream = new FileInputStream(new File(templatePath));
-        org.apache.poi.ss.usermodel.Workbook workbook = WorkbookFactory.create(templateStream);
+        Workbook workbook = WorkbookFactory.create(templateStream);
         Sheet templateSheet = workbook.getSheetAt(0);
 
         // 移除默认的Sheet1
@@ -4730,6 +4778,33 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
         List<WbsTreeContract> list= wbsTreeContractMapper.getWbsTreeContractsByPKeyIds(dto.getLeftPkeyIds());
         WbsTreeContract moveFatherNode = this.getById(list.get(0).getPId());
         WbsTreeContract fatherContract = this.getById(dto.getRightPkeyId());
+        Integer leftNodeType = 0;
+        Integer rightNodeType =0;
+        if(list.get(0).getNodeType()!=null){
+            if(list.get(0).getNodeType()==1){
+                leftNodeType=1;
+            } else if (list.get(0).getNodeType()==18) {
+                leftNodeType=2;
+            }else {
+                leftNodeType=list.get(0).getNodeType()+1;
+            }
+        }
+        if(fatherContract.getNodeType()!=null){
+            if(fatherContract.getNodeType()==1){
+                rightNodeType=1;
+            } else if (fatherContract.getNodeType()==18) {
+                rightNodeType=2;
+            }else {
+                rightNodeType=fatherContract.getNodeType()+1;
+            }
+        }
+        if(leftNodeType==rightNodeType){
+            throw new ServiceException("请勿同级节点相互移动");
+        }
+        if(leftNodeType<rightNodeType){
+            throw new ServiceException("请勿向比自己层级低的节点移动");
+        }
+
 
         String sql="SELECT * from m_formula_data_block WHERE sw_id = "+moveFatherNode.getId()+" and contract_id ="+moveFatherNode.getContractId()+" and  type =0";
         List<FormulaDataBlock> formulaDataBlocks1 = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(FormulaDataBlock.class));
@@ -4770,13 +4845,17 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
                 for (WbsTreeContract childContract : childContracts) {
                     String ancestorsPId =  childContract.getAncestorsPId();
                     ancestorsPId=ancestorsPId.replace(oldancestorsPId,contract.getAncestorsPId());
+                    childContract.setAncestorsPId(ancestorsPId);
                     String ancestors = childContract.getAncestors();
                     ancestors=ancestors.replace(oldancestors,contract.getAncestors());
-                    wbsTreeContractMapper.updateAncestorsPid(ancestorsPId,ancestors,childContract.getPKeyId());
+                    childContract.setAncestors(ancestors);
+                    //wbsTreeContractMapper.updateAncestorsPid(ancestorsPId,ancestors,childContract.getPKeyId());
                 }
+                this.updateBatchById(childContracts);
             }
-            this.wbsTreeContractMapper.updateWbsTreeAncestors(contract);
+            //this.wbsTreeContractMapper.updateWbsTreeAncestors(contract);
         }
+        this.updateBatchById(list);
         String ids = dto.getLeftPkeyIds().stream().map(id -> id + "").collect(Collectors.joining(","));
         this.wbsTreeContractStatisticsClient.updateAncestors(ids);
         return R.success("操作成功");
@@ -5468,7 +5547,7 @@ public class WbsTreeContractServiceImpl extends BaseServiceImpl<WbsTreeContractM
     }
 
      //保存Workbook到本地文件(本地测试放开)
-    private void saveWorkbookToFile(org.apache.poi.ss.usermodel.Workbook workbook, String filePath) {
+    private void saveWorkbookToFile(Workbook workbook, String filePath) {
         try {
             File file = new File(filePath);
             File parentDir = file.getParentFile();

+ 13 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreeServiceImpl.java

@@ -308,8 +308,19 @@ public class WbsTreeServiceImpl extends BaseServiceImpl<WbsTreeMapper, WbsTree>
                             wbsFormElement.setRemark(map.get("备注"));
 
                             wbsFormElementService.save(wbsFormElement);
-
-                            baseMapper.alterTableFiled(initTableName, wbsFormElement.getEKey(), "varchar", WbsFormElementServiceImpl.DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                            if (keyNumb[0] > 80) {
+                                //判断是否存在该Key字段
+                                int row1 = wbsTreeMapper.isThereAField(wbsTree.getInitTableName(), "key_201");
+                                if (row1 == 0) {
+                                    try {
+                                        jdbcTemplate.execute("alter table " + wbsTree.getInitTableName() + " add key_201 text");
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                            } else {
+                                baseMapper.alterTableFiled(initTableName, wbsFormElement.getEKey(), "varchar", WbsFormElementServiceImpl.DEFAULT_ELEMENT_LENGTH_VARCHAR);
+                            }
                         }
 
                     });

+ 8 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/PdfAddimgUtil.java

@@ -120,8 +120,8 @@ public class PdfAddimgUtil {
         float height = pageSize.getHeight();
         float width = pageSize.getWidth();
         if(type.equals("6")){
-            x = width * x - 27+pyzbx;
-            y = height - height * y - 30+pyzby;
+            x = width * x + pyzbx;
+            y = height - height * y + pyzby - 0.5f;
             imagePath = FileUtils.getSysLocalFileUrl()+"print/ht1234567890.png";
         }else{
             x = width * x - 20+pyzbx;
@@ -140,6 +140,12 @@ public class PdfAddimgUtil {
             float newWidth = 75f; // 新的宽度
             float newHeight = image.getScaledHeight() * (newWidth / image.getScaledWidth()); // 根据宽度计算高度
             image.scaleAbsolute(newWidth, newHeight); // 设置图片的新尺寸
+        } else {
+            image.scaleAbsolute(image.getWidth() * (8 / 9f), image.getHeight() * (8 / 9f));
+            float imageWidth = image.getWidth();
+            float imageHeight = image.getHeight();
+            x = x - imageWidth / 2;
+            y = y - imageHeight / 2;
         }
         //调整图片尺寸
         image.setAbsolutePosition(x, y);

+ 12 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/RandomNumberHolder.java

@@ -9,7 +9,8 @@ public class RandomNumberHolder {
         private static final ThreadLocal<HashMap<Long,String>> randomNumberThreadLocal = new ThreadLocal<>();
         private static final ThreadLocal<Integer> randomTemplateTypeThreadLocal = new ThreadLocal<>();
         private static final ThreadLocal<List<WbsTreeContract>> randomWbsTreeContractThreadLocal = new ThreadLocal<>();
-    private static final ThreadLocal<Long> randomTrialSelfInspectionRecordGroupId = new ThreadLocal<>();
+        private static final ThreadLocal<Long> randomTrialSelfInspectionRecordGroupId = new ThreadLocal<>();
+        private static final ThreadLocal<String> LogMessage =new ThreadLocal<>();
 
     public static void setRandomNumber(HashMap<Long,String> map) {
         randomNumberThreadLocal.set(map);
@@ -57,5 +58,15 @@ public class RandomNumberHolder {
     public static void clearTrialSelfInspectionRecordGroupId() {
         randomTrialSelfInspectionRecordGroupId.remove();
     }
+
+    public static String getLogMessage() {
+    	return LogMessage.get();
+    }
+    public static void setLogMessage(String logMessage) {
+    	LogMessage.set(logMessage);
+    }
+    public static void clearLogMessage() {
+    	LogMessage.remove();
+    }
 }
 

+ 114 - 11
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/TaskController.java

@@ -64,6 +64,7 @@ import org.springblade.evisa.vo.SealStrategyVO;
 import org.springblade.feign.ArchiveFileTaskClient;
 import org.springblade.manager.entity.*;
 import org.springblade.manager.feign.*;
+import org.springblade.manager.util.DataStructureFormatUtils;
 import org.springblade.manager.vo.ExecutionTime;
 import org.springblade.manager.vo.ReportMergeCellsConfig;
 import org.springblade.manager.vo.ReportResult;
@@ -113,6 +114,8 @@ import java.util.regex.Matcher;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
+import static java.util.stream.Collectors.toMap;
+
 @RestController
 @AllArgsConstructor
 @RequestMapping("/task")
@@ -3497,16 +3500,17 @@ public class TaskController extends BladeController {
                     }
                     /*检查发现有p_key_id缺失的情况,导致表单数据丢失,所以强制覆盖*/
                     dataMap.put("p_key_id", task.getId());
-                    sqlInfo = "INSERT INTO " + aPrivate.getInitTableName() + " ( ";
-                    String keyStr = "id,";
-                    String valStr = SnowFlakeUtil.getId() + ",";
-                    for (String keys : dataMap.keySet()) {
-                        keyStr += keys + ",";
-                        valStr += "'" + dataMap.get(keys) + "',";
-                    }
-                    keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
-                    valStr = valStr.substring(0, valStr.lastIndexOf(","));
-                    sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
+                    sqlInfo = buildMTableInsertSql(aPrivate.getInitTableName(), dataMap, SnowFlakeUtil.getId(), null, null).toString();
+//                    sqlInfo = "INSERT INTO " + aPrivate.getInitTableName() + " ( ";
+//                    String keyStr = "id,";
+//                    String valStr = SnowFlakeUtil.getId() + ",";
+//                    for (String keys : dataMap.keySet()) {
+//                        keyStr += keys + ",";
+//                        valStr += "'" + dataMap.get(keys) + "',";
+//                    }
+//                    keyStr = keyStr.substring(0, keyStr.lastIndexOf(","));
+//                    valStr = valStr.substring(0, valStr.lastIndexOf(","));
+//                    sqlInfo = sqlInfo + keyStr + ") VALUES (" + valStr + ")";
                     jdbcTemplate.execute(sqlInfo);
 
                     //如果为最后审计流程则判断是否当前流程已全部审批,已经全部审批则生成电签PDF,没有全部审批则只保存数据
@@ -3556,6 +3560,104 @@ public class TaskController extends BladeController {
         }
     }
 
+    public StringBuilder buildMTableInsertSql(String tabName, Map<String, Object> dataMap2, Object id, Object groupId, Object pKeyId) {
+        if (dataMap2 == null || dataMap2.isEmpty() || tabName == null || tabName.isEmpty()) {
+            return new StringBuilder();
+        }
+        //拼接SQL
+        StringBuilder sql = new StringBuilder("INSERT INTO " + tabName),
+                keySql = new StringBuilder(),
+                valSql = new StringBuilder();
+        if (id == null) {
+            if (dataMap2.containsKey("id")) {
+                id = dataMap2.get("id");
+            }
+        }
+        keySql.append("id");
+        valSql.append(id == null ? SnowFlakeUtil.getId() : id);
+        if (groupId ==  null) {
+            groupId = dataMap2.get("group_id");
+        }
+        if (groupId != null) {
+            keySql.append(", group_id");
+            valSql.append(", ").append(groupId);
+        }
+        if (pKeyId == null) {
+            pKeyId = dataMap2.get("p_key_id");
+        }
+        if (pKeyId != null) {
+            keySql.append(", p_key_id");
+            valSql.append(", ").append(pKeyId);
+        }
+        //参数
+        Map<String, String> opsParamMap = new HashMap<>();
+        dataMap2.remove("id");
+        dataMap2.remove("group_id");
+        dataMap2.remove("p_key_id");
+        String fields = dataMap2.keySet().stream().map(key -> "'" + key + "'").collect(Collectors.joining(","));
+        Map<String, Integer> map = new HashMap<>();
+        if (!fields.isEmpty()) {
+            try {
+                fields = fields + ", 'key_201'";
+                List<Map<String, Object>> fieldMap = jdbcTemplate.queryForList("select distinct COLUMN_NAME as fieldName, CHARACTER_MAXIMUM_LENGTH as fieldLength from information_schema.COLUMNS where  TABLE_NAME = '" + tabName +
+                        "' and COLUMN_NAME in (" + fields + ")");
+                map = fieldMap.stream().collect(toMap(k -> k.get("fieldName") + "", v -> {
+                    try {
+                        return Integer.parseInt(v.get("fieldLength") + "");
+                    } catch (Exception e) {
+                        return 0;
+                    }
+                }, Math::min));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        for (String key : dataMap2.keySet()) {
+            String[] split = key.split("_");
+            if (split.length > 1 && Integer.parseInt(split[1]) > 80) {
+                // 大于80则保留在扩展字段中
+                opsParamMap.put(key, dataMap2.get(key) == null ? "" : dataMap2.get(key) + "");
+            } else {
+                String value = dataMap2.get(key) == null ? null : dataMap2.get(key) + "";
+                if (value != null) {
+                    Integer i = map.get(key);
+                    // 长度超过数据库长度也保留在扩展字段中
+                    if (i != null &&  value.length() > i) {
+                        opsParamMap.put(key, value);
+                        continue;
+                    }
+                }
+                keySql.append(", ").append(key);
+                valSql.append(", '").append(value).append("'");
+            }
+        }
+        if (!opsParamMap.isEmpty()) {
+            keySql.append(", key_201");
+            String data = DataStructureFormatUtils.buildData(opsParamMap);
+            try {
+                if (!map.containsKey( "key_201")) {
+                    jdbcTemplate.execute("alter table " + tabName + " add column key_201 text");
+                } else  {
+                    Integer i = map.get("key_201");
+                    if (data.length() > i) {
+                        if (i < 10000) {
+                            // 65535 byte
+                            jdbcTemplate.execute("alter table " + tabName + " modify column key_201 text");
+                        }else {
+                            // 16777215 byte
+                            jdbcTemplate.execute("alter table " + tabName + " modify column key_201 mediumtext");
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            valSql.append(", '").append(data).append("'");
+        }
+        sql.append("(").append(keySql).append(")").append(" values(").append(valSql).append(")");
+        return sql;
+    }
+
     public void addYuan(String key, Map<String, Object> tableData) {
         Object object2 = tableData.get(key);
         if (object2 != null) {
@@ -4667,7 +4769,7 @@ public class TaskController extends BladeController {
                 String UPSqlJL = " update u_task_parallel a set a.e_visa_status=1,e_visa_content='电签成功',initiative=2 where sort in( SELECT a.fixed_flow_branch_sort from u_task b,u_fixed_flow_link a where b.`status` in(1,2) and b.form_data_id='" + report.getPeriodId() + "' and a.fixed_flow_id=b.fixed_flow_id and a.flow_task_type=2 ) and a.process_instance_id in(SELECT process_instance_id from u_task b where b.`status` in(1,2) and b.form_data_id='" + report.getPeriodId() + "')";
                 String DeSql = "delete from u_task_batch where task_parallel_id in(select b.process_instance_id from u_task b where b.`status` in(1,2) and b.form_data_id=" + report.getPeriodId() + ")";
                 //删除以前存在的电签
-                String sql = "insert into u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name,sign_format,sign_type) " + " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.approval_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,a.update_time,1 as status,0 as is_deleted,a.task_user_name as nick_name ,1 as sign_format,1 as sign_type from u_task_parallel a,u_task b,u_fixed_flow_link c where b.`status` in(1,2) and  a.process_instance_id=b.process_instance_id and c.flow_task_type!=2 and a.sort = c.fixed_flow_branch_sort and c.fixed_flow_id=b.fixed_flow_id and b.form_data_id= '" + report.getPeriodId() + "'";
+                String sql = "insert into u_task_batch(id,task_parallel_id,json_data,create_user,create_dept,create_time,update_user,update_time,status,is_deleted,nick_name,sign_format,sign_type) " + " SELECT a.id,a.process_instance_id,json_object('approvalFileList',json_array(),'approvalType',b.approval_type,'comment','','flag','OK','formDataId',b.form_data_id,'parallelProcessInstanceId',a.parallel_process_instance_id,'pass',true,'taskId',b.id) as  json_data,a.task_user,a.create_dept,a.create_time,a.update_user,SYSDATE(),1 as status,0 as is_deleted,a.task_user_name as nick_name ,1 as sign_format,1 as sign_type from u_task_parallel a,u_task b,u_fixed_flow_link c where b.`status` in(1,2) and  a.process_instance_id=b.process_instance_id and c.flow_task_type!=2 and a.sort = c.fixed_flow_branch_sort and c.fixed_flow_id=b.fixed_flow_id and b.form_data_id= '" + report.getPeriodId() + "'";
 
                 jdbcTemplate.execute(DeSql);
                 jdbcTemplate.execute(UPSql);
@@ -5475,6 +5577,7 @@ public class TaskController extends BladeController {
 
         if (dataIn != null && dataIn.size() >= 1) {
             Map<String, Object> mysqlData = dataIn.get(0);
+            DataStructureFormatUtils.parseDataByKey(mysqlData);
             for (String key : mysqlData.keySet()) {
                 String tabVal = mysqlData.get(key) + "";
                 // 时间段处理

+ 2 - 2
blade-service/blade-repair/src/main/java/org/springblade/repair/controller/CheckAndRepairController.java

@@ -157,10 +157,10 @@ public class CheckAndRepairController {
         System.out.println("开始扫描private和contract的html");
         StringBuilder result=new StringBuilder("");
         try {
-            String sql="SELECT a.p_key_id,a.is_type_private_pid FROM m_wbs_tree_contract a,m_wbs_tree_private b WHERE a.html_url != b.html_url AND a.is_type_private_pid=b.p_key_id AND a.type=2 AND a.is_deleted=0 AND b.type=2 AND b.html_url is not NULL AND a.project_id=b.project_id";
+            String sql="SELECT a.p_key_id,a.is_type_private_pid FROM m_wbs_tree_contract a,m_wbs_tree_private b WHERE a.html_url != b.html_url AND a.is_type_private_pid=b.p_key_id AND a.type=2 AND a.is_deleted=0 AND b.type=2 AND b.html_url is not NULL AND a.html !='null' AND b.html_url !='nul' AND a.project_id=b.project_id";
             List<WbsTreeContract> contractListlist = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
             for (WbsTreeContract wbsTreeContract : contractListlist) {
-                String update=" update m_wbs_tree_contract set html_url=(select html_url from m_wbs_tree_private where p_key_id="+wbsTreeContract.getIsTypePrivatePid()+") where p_key_id="+wbsTreeContract.getPKeyId();
+                String update=" update m_wbs_tree_contract set html_url=(select html_url from m_wbs_tree_private where html !='null' and  p_key_id="+wbsTreeContract.getIsTypePrivatePid()+") where p_key_id="+wbsTreeContract.getPKeyId();
                 int i = jdbcTemplate.update(update);
                 if(i!=1){
                     result.append(wbsTreeContract.getPKeyId()+"\n");

+ 9 - 0
blade-service/blade-websocket/pom.xml

@@ -35,6 +35,11 @@
             <artifactId>blade-manager-api</artifactId>
             <version>${bladex.project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-dingding-api</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.springblade</groupId>
             <artifactId>blade-business-api</artifactId>
@@ -58,6 +63,10 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+        </dependency>
     </dependencies>
 
     <properties>

+ 12 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/feign/WebSocketClientImpl.java

@@ -1,11 +1,16 @@
 package org.springblade.websocket.feign;
 
 import lombok.AllArgsConstructor;
+import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.websocket.service.WebSocketService;
+import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * @Param
  * @Author wangwl
@@ -25,4 +30,11 @@ public class WebSocketClientImpl implements WebSocketClient{
     public void sendSystemMsg(SystMsgVO vo) {
         socketService.sendSystemMsg(vo);
     }
+
+    @Override
+    public void sendDingDingMsg(UserInfoVO vo) {
+        socketService.sendDingDingMsg(vo);
+    }
+
+
 }

+ 62 - 0
blade-service/blade-websocket/src/main/java/org/springblade/websocket/service/WebSocketService.java

@@ -2,6 +2,8 @@ package org.springblade.websocket.service;
 
 import io.undertow.websockets.jsr.UndertowSession;
 import lombok.Data;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springblade.business.feign.BusinessWebSocketClient;
@@ -9,10 +11,12 @@ import org.springblade.common.constant.ClientIdConstant;
 import org.springblade.common.constant.WebsocketMsgConstant;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.dingding.vo.MeetingVo;
 import org.springblade.feign.ArchiveWebSocketClient;
 import org.springblade.manager.feign.ManagerWebSocketClient;
 import org.springblade.meter.feign.MeterWebSocketClient;
 import org.springblade.websocket.entity.WebSocketClientInfo;
+import org.springblade.websocket.vo.DingDingMsg;
 import org.springblade.websocket.vo.MsgVO;
 import org.springblade.websocket.vo.SystMsgVO;
 import org.springblade.websocket.vo.UserInfoVO;
@@ -48,6 +52,8 @@ public class WebSocketService implements ApplicationContextAware {
     /** 后台*/
     private static ManagerWebSocketClient managerWebSocketClient;
 
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         WebSocketService.meterWebSocketClient = applicationContext.getBean(MeterWebSocketClient.class);
@@ -76,6 +82,8 @@ public class WebSocketService implements ApplicationContextAware {
     private static Set<Session> clientSystemSessions = new CopyOnWriteArraySet<>();
     /** 档案系统session集合*/
     private static Set<Session> archivesSystemSessions = new CopyOnWriteArraySet<>();
+    /** 档案系统session集合*/
+    private static Set<Session> dingdingSystemSessions = new CopyOnWriteArraySet<>();
 
 //    /** 更新公告推送记录*/
 //    private static Set<UserSingleVO> updateMsgPushUsers = new HashSet<>();
@@ -156,6 +164,9 @@ public class WebSocketService implements ApplicationContextAware {
                 case ClientIdConstant.CLIENT_ID:
                     clientSystemSessions.add(session);
                     break;
+                case ClientIdConstant.DINGDING_ID:
+                    dingdingSystemSessions.add(session);
+                    break;
                 default:
                     log.error("未知的系统登录:"+system);
             }
@@ -186,6 +197,9 @@ public class WebSocketService implements ApplicationContextAware {
                 case ClientIdConstant.ARCHIVE_ID:
                     archivesSystemSessions.remove(session);
                     break;
+                case ClientIdConstant.DINGDING_ID:
+                    dingdingSystemSessions.remove(session);
+                    break;
                 default:
                     log.error("未知的系统退出:"+system);
             }
@@ -253,6 +267,10 @@ public class WebSocketService implements ApplicationContextAware {
         }
     }
 
+
+
+
+
     /**
      *  推送指定的系统的所有在线用户
      */
@@ -401,4 +419,48 @@ public class WebSocketService implements ApplicationContextAware {
         WebSocketService.onlineLinkCount--;
     }
 
+    public void sendDingDingMsg(UserInfoVO vo) {
+        List<Session> sessions = userInfoMap.get(vo);
+        if(sessions != null && sessions.size() > 0){
+            /** 此处不能使用普通集合,否则在推送消息时,当前用户又开启一个页面,集合发生变化迭代器会报错ConcurrentModificationException*/
+            for (Session s : sessions) {
+                if (s == null){
+                    continue;
+                }
+                RemoteEndpoint.Basic basicRemote = s.getBasicRemote();
+                /** 推送消息时可能因为nginx配置的连接时间,或者用户刚好断开连接,
+                 * 导致通道关闭,但是数组中使用的是快照,还存在这个连接,此时跳过推送给这个窗口*/
+                if (basicRemote != null){
+                    try {
+                        DingDingMsg dingMsg = new DingDingMsg();
+                        dingMsg.setMsgType(vo.getMsgType());
+                        dingMsg.setData(vo.getObject());
+                        // 将对象序列化为JSON字符串再发送
+                        String message = toJsonMessage(R.data(dingMsg));
+                        basicRemote.sendText(message);
+                    } catch (Exception e) {
+                        log.error(vo.getUserId()+"推送消息失败,消息内容["+ vo.getMsg()+"],原因:"+e.getMessage());
+                    }
+                }
+            }
+        }
+    }
+    public static String toJsonMessage(Object object) {
+        if (object == null) {
+            return "";
+        }
+
+        if (object instanceof String) {
+            return (String) object;
+        }
+
+        try {
+            return objectMapper.writeValueAsString(object);
+        } catch (JsonProcessingException e) {
+            log.error("对象序列化为JSON失败: {}", e.getMessage());
+            return object.toString();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 2 - 0
pom.xml

@@ -41,6 +41,8 @@
         <module>blade-service</module>
         <module>blade-service-api</module>
         <module>blade-service/blade-repair</module>
+        <module>blade-service/blade-dingding</module>
+        <module>blade-service-api/blade-dingding-api</module>
     </modules>
 
     <dependencyManagement>