Prechádzať zdrojové kódy

电签默认信息bug

liuyc 2 rokov pred
rodič
commit
515c159471

+ 0 - 1
blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocket.java

@@ -167,7 +167,6 @@ public class WebSocket {
     @Scheduled(cron = "0 0/5 * * * ?")
     public void reSendMessage() throws IOException {
         if (webSocketMap.isEmpty() || webSocketMessageMap.isEmpty()) {
-            logger.error("定时重发消息WebSocket,reSendMessage()方法未执行,原因:客户端未建立WebSocket链接");
             return;
         }
 

+ 1 - 2
blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocketManager.java

@@ -163,10 +163,9 @@ public class WebSocketManager {
     /***
      * 定时重发任务消息WebSocket - 后管
      */
-    @Scheduled(cron = "0 0/6 * * * ?")
+    @Scheduled(cron = "0 0/5 * * * ?")
     public void reSendMessageManager() throws IOException {
         if (webSocketMap2.isEmpty() || webSocketMessageMap2.isEmpty()) {
-            logger.error("定时重发消息WebSocket,reSendMessageManager()方法未执行,原因:客户端未建立WebSocket链接");
             return;
         }
 

+ 38 - 22
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java

@@ -35,9 +35,12 @@ import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 import org.springblade.common.utils.CommonUtil;
 import org.springblade.common.utils.SnowFlakeUtil;
+import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.support.Condition;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.*;
 import org.springblade.manager.entity.*;
@@ -84,7 +87,7 @@ public class TextdictInfoController extends BladeController {
     private final WbsTreePrivateMapper wbsTreePrivateMapper;
     private final WbsTreePrivateServiceImpl wbsTreePrivateService;
     private final WbsTreeContractServiceImpl wbsTreeContractService;
-
+    private final BladeRedis bladeRedis;
     private final JdbcTemplate jdbcTemplate;
 
     /**
@@ -212,7 +215,7 @@ public class TextdictInfoController extends BladeController {
         delIds.add(ids);
         textdictInfoService.getBaseMapper().deleteBatchIds(delIds);
 
-        return R.success("成功");
+        return R.success("删除成功");
     }
 
 
@@ -339,6 +342,10 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "保存电签", notes = "保存电签")
     public R<String> saveSigInfo(@Valid @RequestBody JSONObject dataInfo) throws IOException {
+        String redisValue = bladeRedis.get("save-eVis-lock:" + SecureUtil.getUserId());
+        if (StringUtils.isNotEmpty(redisValue) && redisValue.equals("1")) {
+            throw new ServiceException("请勿重复提交,请3秒后再尝试");
+        }
         JSONArray jsonArray = dataInfo.getJSONArray("dataInfo");
         Long tableId = dataInfo.getLong("tabId");
 
@@ -352,10 +359,11 @@ public class TextdictInfoController extends BladeController {
                 .eq(WbsTreePrivate::getStatus, 1));
         List<Long> pKeyIds = wbsTreePrivatesEqual.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
         String ids = StringUtils.join(pKeyIds, ",");
-
-        //删除引用当前模板所有电签信息
-        String delSql = "delete from m_textdict_info where tab_id in(" + ids + ") and type in(2,6)";
-        jdbcTemplate.execute(delSql);
+        if (StringUtils.isNotEmpty(ids)) {
+            //删除引用当前模板所有电签信息
+            String delSql = "delete from m_textdict_info where tab_id in(" + ids + ") and type in(2,6)";
+            jdbcTemplate.execute(delSql);
+        }
 
         // 读取html页面信息
         File file1 = ResourceUtil.getFile(wbsTreePrivate.getHtmlUrl());
@@ -428,12 +436,12 @@ public class TextdictInfoController extends BladeController {
         FileUtil.writeToFile(writeFile, doc.html(), Boolean.parseBoolean("UTF-8"));
 
         String str1 = wbsTreePrivate.getHtmlUrl().replace("Desktop//privateUrl", "Desktop/privateUrl");
-
         String replace = str1.replace("\\", "\\\\");
-
-        //修改所有节点的htmlUrl
-        String updateSqlP = "update m_wbs_tree_private set html_url = '" + replace + "' where p_key_id in (" + ids + ")";
-        jdbcTemplate.execute(updateSqlP);
+        if (StringUtils.isNotEmpty(ids)){
+            //修改所有节点的htmlUrl
+            String updateSqlP = "update m_wbs_tree_private set html_url = '" + replace + "' where p_key_id in (" + ids + ")";
+            jdbcTemplate.execute(updateSqlP);
+        }
 
         //修改对应合同段的htmlUrl,当前项目下对应合同段的节点
         List<Long> cIdsList = wbsTreePrivatesEqual.stream().map(WbsTreePrivate::getId).distinct().collect(Collectors.toList());
@@ -441,12 +449,15 @@ public class TextdictInfoController extends BladeController {
                 .eq(WbsTreeContract::getProjectId, wbsTreePrivate.getProjectId())
                 .eq(WbsTreeContract::getExcelId, wbsTreePrivate.getExcelId())
                 .eq(WbsTreeContract::getStatus, 1)
-                .in(WbsTreeContract::getId, cIdsList)
-        ).stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
-
+                .in(WbsTreeContract::getId, cIdsList)).stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
         String cPkeyIdsStr = StringUtils.join(cPkeyIds, ",");
-        String updateSqlC = "update m_wbs_tree_contract set html_url = '" + replace + "' where p_key_id in (" + cPkeyIdsStr + ")";
-        jdbcTemplate.execute(updateSqlC);
+        if (StringUtils.isNotEmpty(cPkeyIdsStr)) {
+            String updateSqlC = "update m_wbs_tree_contract set html_url = '" + replace + "' where p_key_id in (" + cPkeyIdsStr + ")";
+            jdbcTemplate.execute(updateSqlC);
+        }
+
+        bladeRedis.set("save-eVis-lock:" + SecureUtil.getUserId(), "1");
+        bladeRedis.expire("save-eVis-lock:" + SecureUtil.getUserId(), 3);
 
         return R.success("操作成功");
     }
@@ -458,6 +469,7 @@ public class TextdictInfoController extends BladeController {
     @ApiOperationSupport(order = 7)
     @ApiOperation(value = "保存默认值", notes = "保存默认值")
     public R<String> saveDefaulVal(@Valid @RequestBody TextdictBy345VO textdictInfo) throws IOException, ClassNotFoundException {
+
         //当前清表信息
         WbsTreePrivate wbsTreePrivate = wbsTreePrivateMapper.getByPKeyId(textdictInfo.getTableId());
 
@@ -549,10 +561,11 @@ public class TextdictInfoController extends BladeController {
 
         String str1 = wbsTreePrivate.getHtmlUrl().replace("Desktop//privateUrl", "Desktop/privateUrl");
         String replace = str1.replace("\\", "\\\\");
-
-        //修改所有节点的htmlUrl
-        String updateSqlP = "update m_wbs_tree_private set html_url = '" + replace + "' where p_key_id in (" + ids + ")";
-        jdbcTemplate.execute(updateSqlP);
+        if (StringUtils.isNotEmpty(ids)) {
+            //修改所有节点的htmlUrl
+            String updateSqlP = "update m_wbs_tree_private set html_url = '" + replace + "' where p_key_id in (" + ids + ")";
+            jdbcTemplate.execute(updateSqlP);
+        }
 
         //修改对应合同段的htmlUrl,当前项目下对应合同段的节点
         List<Long> cIdsList = wbsTreePrivatesEqual.stream().map(WbsTreePrivate::getId).distinct().collect(Collectors.toList());
@@ -564,8 +577,11 @@ public class TextdictInfoController extends BladeController {
         ).stream().map(WbsTreeContract::getPKeyId).collect(Collectors.toList());
 
         String cPkeyIdsStr = StringUtils.join(cPkeyIds, ",");
-        String updateSqlC = "update m_wbs_tree_contract set html_url = '" + replace + "' where p_key_id in (" + cPkeyIdsStr + ")";
-        jdbcTemplate.execute(updateSqlC);
+        if (StringUtils.isNotEmpty(cPkeyIdsStr)) {
+            String updateSqlC = "update m_wbs_tree_contract set html_url = '" + replace + "' where p_key_id in (" + cPkeyIdsStr + ")";
+            jdbcTemplate.execute(updateSqlC);
+        }
+
 
         return R.success("操作成功");
     }

+ 13 - 2
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java

@@ -317,9 +317,9 @@ public class WbsTreePrivateController extends BladeController {
         List<WbsNodeTableVO> rs = wbsTreePrivateService.selectByNodeTable(parentId, wbsId, projectId);
         if (rs.size() > 0) {
             for (WbsNodeTableVO r : rs) {
-                if (StringUtil.isBlank(r.getInitTableId())){
+                if (StringUtil.isBlank(r.getInitTableId())) {
                     WbsTree wbsTree = wbsTreeService.getById(r.getId());
-                    if (wbsTree != null){
+                    if (wbsTree != null) {
                         r.setInitTableId(wbsTree.getInitTableId().toString());
                         r.setElementTotal(Math.toIntExact(wbsFormElementService.count(
                                 new LambdaQueryWrapper<WbsFormElement>().eq(WbsFormElement::getFId, r.getInitTableId()))));
@@ -609,5 +609,16 @@ public class WbsTreePrivateController extends BladeController {
         return wbsTreePrivateService.getExcelHtml(primaryKeyId);
     }
 
+    /**
+     * 解決项目电签信息重复问题接口
+     * @param pid
+     * @return
+     */
+    @PostMapping("/eVisInfoRepeatDel")
+    public R eVisInfoRepeatDel(String pid) {
+        //传入当前项目id
+        wbsTreePrivateService.eVisInfoRepeatDel(pid);
+        return R.status(true);
+    }
 
 }

+ 2 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java

@@ -76,4 +76,6 @@ public interface IWbsTreePrivateService extends BaseService<WbsTreePrivate> {
 
     boolean syncProjectEVisa(String projectId);
 
+    void eVisInfoRepeatDel(String pid);
+
 }

+ 87 - 31
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
 import lombok.AllArgsConstructor;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
@@ -20,7 +21,6 @@ import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.constant.BladeConstant;
 import org.springblade.core.tool.node.ForestNodeMerger;
 import org.springblade.core.tool.utils.*;
-import org.springblade.manager.dto.WbsTreeContractDTO;
 import org.springblade.manager.dto.WbsTreePrivateDTO2;
 import org.springblade.manager.dto.WbsTreePrivateDTO3;
 import org.springblade.manager.entity.*;
@@ -34,10 +34,16 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 @Service
@@ -46,8 +52,6 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
 
     private final WbsTreeContractMapper wbsTreeContractMapper;
     private final WbsTreeContractServiceImpl wbsTreeContractService;
-
-    // 表单主表信息
     private final ITableInfoService tableInfoService;
     private final WbsTreeMapper wbsTreeMapper;
     private final ContractInfoMapper contractInfoMapper;
@@ -59,6 +63,9 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
     private final JdbcTemplate jdbcTemplate;
     private final TextdictInfoServiceImpl textDictInfoService;
 
+    @Resource(name = "taskExecutor1")
+    private ThreadPoolExecutor executor;
+
     @Override
     public List<WbsTreePrivateVO> tree(String wbsId, String projectId) {
         WbsInfo wbsInfo = wbsInfoMapper.selectOne(Wrappers.<WbsInfo>query().lambda().eq(WbsInfo::getId, wbsId));
@@ -1631,34 +1638,41 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                 WbsTreePrivate oneRecordRoot = this.getOne(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getPKeyId, projectInfo.getReferenceWbsTemplateId()));
 
                 //获取当前项目下节点树所有节点、表、独立表
-                List<WbsTreePrivate> wbsTreePrivatesNodeAndTabNow = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, projectId).eq(WbsTreePrivate::getWbsType, 1).eq(WbsTreePrivate::getStatus, 1).and(obj -> obj.eq(WbsTreePrivate::getType, 1).or().eq(WbsTreePrivate::getType, 2)));
-                List<WbsTreePrivate> wbsTreePrivatesTableDL = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, projectId).eq(WbsTreePrivate::getType, 10).eq(WbsTreePrivate::getParentId, -10).eq(WbsTreePrivate::getStatus, 1));
-                wbsTreePrivatesNodeAndTabNow.addAll(wbsTreePrivatesTableDL);
-                //获取当前项目节点树的所有id
-                List<Long> saveIds = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList()).stream().map(WbsTreePrivate::getId).collect(Collectors.toList());
+                String sqlNodeTreeAllNow = "SELECT p_key_id,id,type,parent_id,html_url FROM m_wbs_tree_private WHERE project_id = " + projectId + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_type = 1) OR (type= 10 AND parent_id = -10 ))";
+                List<WbsTreePrivate> wbsTreePrivatesNodeAndTabNow = jdbcTemplate.query(sqlNodeTreeAllNow, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+                List<WbsTreePrivate> wbsTreePrivatesTableDL = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(10) && f.getParentId().equals(-10L)).collect(Collectors.toList());
+
+                //获取当前项目节点树
+                Map<Long, WbsTreePrivate> nowNodeTreeAll = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(1)).collect(Collectors.toList()).stream()
+                        .collect(Collectors.toMap(WbsTreePrivate::getId, Function.identity()));
 
                 //获取当前引用的节点树下所有节点、表、独立表
-                List<WbsTreePrivate> wbsTreePrivatesNodeAndTab = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, oneRecordRoot.getProjectId()).eq(WbsTreePrivate::getWbsId, oneRecordRoot.getWbsId()).eq(WbsTreePrivate::getStatus, 1).and(obj -> obj.eq(WbsTreePrivate::getType, 1).or().eq(WbsTreePrivate::getType, 2)));
-                List<WbsTreePrivate> wbsTreePrivatesTableDLOld = wbsTreePrivateMapper.selectList(Wrappers.<WbsTreePrivate>lambdaQuery().eq(WbsTreePrivate::getProjectId, oneRecordRoot.getProjectId()).eq(WbsTreePrivate::getType, 10).eq(WbsTreePrivate::getStatus, 1).eq(WbsTreePrivate::getParentId, -10).isNull(WbsTreePrivate::getWbsId));
-                wbsTreePrivatesNodeAndTab.addAll(wbsTreePrivatesTableDLOld);
+                String sqlNodeTreeAllOld = "SELECT p_key_id,id,type,parent_id FROM m_wbs_tree_private WHERE project_id = " + oneRecordRoot.getProjectId() + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_id = " + oneRecordRoot.getWbsId() + ") OR ((type= 10 OR parent_id = -10 ) AND wbs_id IS NULL))";
+                List<WbsTreePrivate> wbsTreePrivatesNodeAndTab = jdbcTemplate.query(sqlNodeTreeAllOld, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
 
                 //获取当前对应电签位置配置信息
-                List<Long> pIdsDL = wbsTreePrivatesNodeAndTab.stream().filter(f -> f.getType().equals(10) || f.getType().equals(2)).collect(Collectors.toList()).stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
-                String sql = "select * from m_textdict_info where tab_id in (" + org.apache.commons.lang.StringUtils.join(pIdsDL, ",") + ") and is_deleted = 0";
-                List<TextdictInfo> textDictInfosAll = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
+                List<WbsTreePrivate> collect1 = wbsTreePrivatesNodeAndTab.stream().filter(f -> f.getType().equals(10) || f.getType().equals(2)).collect(Collectors.toList());
+                List<Long> pKeyIds = collect1.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
+
+                //分组查询
+                List<TextdictInfo> textDictInfosAll = new ArrayList<>();
+                List<List<Long>> partition = Lists.partition(pKeyIds, 1000);
+                for (List<Long> ids : partition) {
+                    String sql = "select id,name,type,tab_id,col_key,sig_role_id,is_deleted,sig_role_name,col_name,pyzbx,pyzby from m_textdict_info where tab_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+                    List<TextdictInfo> textDictInfos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
+                    textDictInfosAll.addAll(textDictInfos);
+                }
+
+                Map<String, List<TextdictInfo>> collect3 = textDictInfosAll.stream().collect(Collectors.groupingBy(TextdictInfo::getTabId));
 
                 //构造原始电签信息
-                for (WbsTreePrivate wbsTreePrivate : wbsTreePrivatesNodeAndTab) {
+                for (WbsTreePrivate wbsTreePrivate : collect1) {
                     if (wbsTreePrivate.getType() == 2) {
-                        for (Long id : saveIds) {
-                            if (id.equals(wbsTreePrivate.getParentId())) {
-                                //根据元素表pKeyId,获取电签位置匹配信息、编辑默认信息
-                                List<TextdictInfo> textDictInfos = textDictInfosAll.stream().filter(f ->
-                                        ObjectUtils.isNotEmpty(f.getTabId()) && f.getTabId().equals(String.valueOf(wbsTreePrivate.getPKeyId()))).collect(Collectors.toList());
-                                if (textDictInfos.size() > 0) {
-                                    textDictInfoData.put(wbsTreePrivate.getPKeyId() + "," + wbsTreePrivate.getId(), textDictInfos);
-                                }
-                            }
+                        WbsTreePrivate obj = nowNodeTreeAll.get(wbsTreePrivate.getParentId());
+                        assert obj != null;
+                        List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
+                        if (textDictInfos != null && textDictInfos.size() > 0) {
+                            textDictInfoData.put(wbsTreePrivate.getPKeyId() + "," + wbsTreePrivate.getId(), textDictInfos);
                         }
                     }
 
@@ -1667,9 +1681,8 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                         List<WbsTreePrivate> collect = wbsTreePrivatesTableDL.stream().filter(f -> f.getId().equals(wbsTreePrivate.getId())).collect(Collectors.toList());
                         if (collect.size() == 0) {
                             //根据元素表pKeyId,获取电签位置匹配信息、编辑默认信息
-                            List<TextdictInfo> textDictInfos = textDictInfosAll.stream().filter(f -> ObjectUtils.isNotEmpty(f.getTabId())
-                                    && f.getTabId().equals(String.valueOf(wbsTreePrivate.getPKeyId()))).collect(Collectors.toList());
-                            if (textDictInfos.size() > 0) {
+                            List<TextdictInfo> textDictInfos = collect3.get(String.valueOf(wbsTreePrivate.getPKeyId()));
+                            if (textDictInfos != null && textDictInfos.size() > 0) {
                                 textDictInfoData.put(wbsTreePrivate.getPKeyId() + "," + wbsTreePrivate.getId(), textDictInfos);
                             }
                         }
@@ -1686,7 +1699,7 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                             for (TextdictInfo textdictInfo : v) {
                                 TextdictInfo obj = BeanUtil.copyProperties(textdictInfo, TextdictInfo.class);
                                 assert obj != null;
-                                obj.setTabId(String.valueOf(tree.getPKeyId()));
+                                obj.setTabId(String.valueOf(tree.getPKeyId())); //重新赋值绑定到对应的表上
                                 obj.setId(SnowFlakeUtil.getId());
                                 insertData.add(obj);
                             }
@@ -1695,8 +1708,10 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
                 });
 
                 //去重,删除当前表的电签信息
-                for (TextdictInfo insertDatum : insertData) {
-                    String delSql = "delete from m_textdict_info where tab_id = " + insertDatum.getTabId();
+                List<String> collect2 = insertData.stream().map(TextdictInfo::getTabId).collect(Collectors.toList());
+                List<List<String>> partitionDel = Lists.partition(collect2, 1000);
+                for (List<String> ids : partitionDel) {
+                    String delSql = "delete from m_textdict_info where tab_id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
                     jdbcTemplate.execute(delSql);
                 }
 
@@ -1705,12 +1720,53 @@ public class WbsTreePrivateServiceImpl extends BaseServiceImpl<WbsTreePrivateMap
 
                 return true;
             } else {
-                throw new ServiceException("未获取到项目的关联的私有wbs树信息");
+                throw new ServiceException("当前项目关联的wbs树不是私有关联");
             }
         }
         return false;
     }
 
+    @Override
+    public void eVisInfoRepeatDel(String pid) {
+        //获取当前项目下节点树所有节点、表、独立表
+        String sqlNodeTreeAllNow = "SELECT p_key_id,id,type,parent_id,html_url FROM m_wbs_tree_private WHERE project_id = " + pid + " AND STATUS = 1 AND is_deleted = 0 AND (((type = 1 OR type = 2) AND wbs_type = 1) OR (type= 10 AND parent_id = -10 ))";
+        List<WbsTreePrivate> wbsTreePrivatesNodeAndTabNow = jdbcTemplate.query(sqlNodeTreeAllNow, new BeanPropertyRowMapper<>(WbsTreePrivate.class));
+
+        //获取当前对应电签位置配置信息
+        List<WbsTreePrivate> collect1 = wbsTreePrivatesNodeAndTabNow.stream().filter(f -> f.getType().equals(10) || f.getType().equals(2)).collect(Collectors.toList());
+        List<Long> pKeyIds = collect1.stream().map(WbsTreePrivate::getPKeyId).collect(Collectors.toList());
+
+        //分组查询电签信息
+        List<TextdictInfo> textDictInfosAll = new ArrayList<>();
+        List<List<Long>> partition = Lists.partition(pKeyIds, 1000);
+        for (List<Long> ids : partition) {
+            String sql = "select id,tab_id,col_key,col_name,sig_role_id,sig_role_name from m_textdict_info where tab_id in(" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+            List<TextdictInfo> textDictInfos = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(TextdictInfo.class));
+            textDictInfosAll.addAll(textDictInfos);
+        }
+
+        //去重,解决之前由于删除接口重复保存,导致数据重复问题
+        List<TextdictInfo> list = textDictInfosAll.stream().collect(
+                Collectors.collectingAndThen(
+                        Collectors.toCollection(() -> new TreeSet<>(
+                                Comparator.comparing(o -> o.getTabId() + ";" + o.getSigRoleId() + ";" + o.getColKey() + ";" + o.getSigRoleName() + ";" + o.getColName()
+                                )
+                        )), ArrayList::new));
+
+        List<Long> idsAll = textDictInfosAll.stream().map(TextdictInfo::getId).collect(Collectors.toList());
+
+        List<Long> saveIds = list.stream().map(TextdictInfo::getId).collect(Collectors.toList());
+
+        List<Long> delIds = idsAll.stream().filter(f -> !saveIds.contains(f)).collect(Collectors.toList());
+
+        List<List<Long>> partition1 = Lists.partition(delIds, 1000);
+        for (List<Long> ids : partition1) {
+            String delSql = "delete from m_textdict_info where id in (" + org.apache.commons.lang.StringUtils.join(ids, ",") + ")";
+            jdbcTemplate.execute(delSql);
+        }
+
+    }
+
     @Transactional(rollbackFor = Exception.class)
     public boolean insertBatch(Collection<WbsTreePrivate> entityList, int batchSize) {
         try {

+ 46 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/AsyncConfigurer.java

@@ -0,0 +1,46 @@
+package org.springblade.manager.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.util.concurrent.*;
+
+@Slf4j
+@Configuration
+@EnableAsync
+public class AsyncConfigurer {
+
+    /**
+     * cpu 核心数量
+     */
+    public static final int cpuNum = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * 线程池配置
+     *
+     * @return
+     */
+    @Bean("taskExecutor1")
+    public ThreadPoolExecutor getAsyncExecutor() {
+        return new ThreadPoolMonitor(cpuNum
+                , cpuNum * 2
+                , 60
+                , TimeUnit.SECONDS
+                , new LinkedBlockingQueue<>(2000)
+                , new ThreadPoolExecutor.DiscardOldestPolicy(), "manager-thread-pool");
+    }
+
+    /**
+     * 线程池配置
+     *
+     * @return
+     */
+    @Bean("singleExecutor")
+    public ExecutorService getSingleExecutor() {
+        log.info("线程池初始化......");
+        return Executors.newSingleThreadExecutor();
+    }
+
+}

+ 191 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/utils/ThreadPoolMonitor.java

@@ -0,0 +1,191 @@
+package org.springblade.manager.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class ThreadPoolMonitor extends ThreadPoolExecutor {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    /**
+     * ActiveCount
+     */
+    int ac = 0;
+
+    /**
+     * 当前所有线程消耗的时间
+     */
+    private AtomicLong totalCostTime = new AtomicLong();
+
+    /**
+     * 当前执行的线程总数
+     */
+    private AtomicLong totalTasks = new AtomicLong();
+
+    /**
+     * 线程池名称
+     */
+    private String poolName;
+
+    /**
+     * 最短 执行时间
+     */
+    private long minCostTime;
+
+    /**
+     * 最长执行时间
+     */
+    private long maxCostTime;
+
+
+    /**
+     * 保存任务开始执行的时间
+     */
+    private ThreadLocal<Long> startTime = new ThreadLocal<>();
+
+    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+                             TimeUnit unit, BlockingQueue<Runnable> workQueue, String poolName) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+                Executors.defaultThreadFactory(), poolName);
+    }
+
+    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+                             TimeUnit unit, BlockingQueue<Runnable> workQueue,
+                             ThreadFactory threadFactory, String poolName) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+        this.poolName = poolName;
+    }
+
+    public ThreadPoolMonitor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler, String poolName) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
+        this.poolName = poolName;
+    }
+
+    /**
+     * 线程池延迟关闭时(等待线程池里的任务都执行完毕),统计线程池情况
+     */
+    @Override
+    public void shutdown() {
+        // 统计已执行任务、正在执行任务、未执行任务数量
+        logger.info("{} Going to shutdown. Executed tasks: {}, Running tasks: {}, Pending tasks: {}",
+                this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
+        super.shutdown();
+    }
+
+    @Override
+    public List<Runnable> shutdownNow() {
+        // 统计已执行任务、正在执行任务、未执行任务数量
+        logger.info("{} Going to immediately shutdown. Executed tasks: {}, Running tasks: {}, Pending tasks: {}",
+                this.poolName, this.getCompletedTaskCount(), this.getActiveCount(), this.getQueue().size());
+        return super.shutdownNow();
+    }
+
+    /**
+     * 任务执行之前,记录任务开始时间
+     */
+    @Override
+    protected void beforeExecute(Thread t, Runnable r) {
+        logger.info("{}-before: " +
+                        " PoolSize: {}, CorePoolSize: {}, ActiveCount: {}, " +
+                        "Completed: {}, Task: {}, Queue: {}, LargestPoolSize: {}, " +
+                        "MaximumPoolSize: {},  KeepAliveTime: {}, isShutdown: {}, isTerminated: {}",
+                this.poolName,
+                this.getPoolSize(), this.getCorePoolSize(), super.getActiveCount(),
+                this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(),
+                this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated());
+        startTime.set(System.currentTimeMillis());
+    }
+
+    /**
+     * 任务执行之后,计算任务结束时间
+     */
+    @Override
+    protected void afterExecute(Runnable r, Throwable t) {
+        long costTime = System.currentTimeMillis() - startTime.get();
+        startTime.remove();  //删除,避免占用太多内存
+        //设置最大最小执行时间
+        maxCostTime = maxCostTime > costTime ? maxCostTime : costTime;
+        if (totalTasks.get() == 0) {
+            minCostTime = costTime;
+        }
+        minCostTime = minCostTime < costTime ? minCostTime : costTime;
+        totalCostTime.addAndGet(costTime);
+        totalTasks.incrementAndGet();
+        ac = this.getActiveCount();  //获取ActiveCount的值
+
+        logger.info("{}-after: " +
+                        "Duration: {} ms, PoolSize: {}, CorePoolSize: {}, ActiveCount: {}, " +
+                        "Completed: {}, Task: {}, Queue: {}, LargestPoolSize: {}, " +
+                        "MaximumPoolSize: {},  KeepAliveTime: {}, isShutdown: {}, isTerminated: {}",
+                this.poolName,
+                costTime, this.getPoolSize(), this.getCorePoolSize(), super.getActiveCount(),
+                this.getCompletedTaskCount(), this.getTaskCount(), this.getQueue().size(), this.getLargestPoolSize(),
+                this.getMaximumPoolSize(), this.getKeepAliveTime(TimeUnit.MILLISECONDS), this.isShutdown(), this.isTerminated());
+    }
+
+    public int getAc() {
+        return ac;
+    }
+
+    /**
+     * 线程平均耗时
+     *
+     * @return
+     */
+    public float getAverageCostTime() {
+        return totalCostTime.get() / totalTasks.get();
+    }
+
+    /**
+     * 线程最大耗时
+     */
+    public long getMaxCostTime() {
+        return maxCostTime;
+    }
+
+    /**
+     * 线程最小耗时
+     */
+    public long getMinCostTime() {
+        return minCostTime;
+    }
+
+    /**
+     * 生成线程池所用的线程,改写了线程池默认的线程工厂
+     */
+    static class EventThreadFactory implements ThreadFactory {
+        private static final AtomicInteger poolNumber = new AtomicInteger(1);
+        private final ThreadGroup group;
+        private final AtomicInteger threadNumber = new AtomicInteger(1);
+        private final String namePrefix;
+
+        /**
+         * 初始化线程工厂
+         *
+         * @param poolName 线程池名称
+         */
+        EventThreadFactory(String poolName) {
+            SecurityManager s = System.getSecurityManager();
+            group = Objects.nonNull(s) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+            namePrefix = poolName + "-pool-" + poolNumber.getAndIncrement() + "-thread-";
+        }
+
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
+
+            if (t.isDaemon()) {
+                t.setDaemon(false);
+            }
+            if (t.getPriority() != Thread.NORM_PRIORITY) {
+                t.setPriority(Thread.NORM_PRIORITY);
+            }
+            return t;
+        }
+    }
+}