소스 검색

Merge branch 'master' of http://47.110.251.215:3000/java_org/bladex

huangtf 2 년 전
부모
커밋
0468c5283a
18개의 변경된 파일478개의 추가작업 그리고 98개의 파일을 삭제
  1. 3 0
      blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormulaBean.java
  2. 4 4
      blade-service/blade-business/src/main/java/org/springblade/business/controller/InformationWriteQueryController.java
  3. 2 1
      blade-service/blade-business/src/main/java/org/springblade/business/controller/TaskController.java
  4. 4 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.java
  5. 41 0
      blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml
  6. 1 1
      blade-service/blade-business/src/main/java/org/springblade/business/service/impl/InformationQueryServiceImpl.java
  7. 0 1
      blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocket.java
  8. 1 2
      blade-service/blade-business/src/main/java/org/springblade/business/socket/WebSocketManager.java
  9. 1 0
      blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java
  10. 39 30
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FormulaController.java
  11. 38 22
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/TextdictInfoController.java
  12. 13 2
      blade-service/blade-manager/src/main/java/org/springblade/manager/controller/WbsTreePrivateController.java
  13. 2 1
      blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java
  14. 2 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/IWbsTreePrivateService.java
  15. 3 3
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/FormulaServiceImpl.java
  16. 87 31
      blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsTreePrivateServiceImpl.java
  17. 46 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/AsyncConfigurer.java
  18. 191 0
      blade-service/blade-manager/src/main/java/org/springblade/manager/utils/ThreadPoolMonitor.java

+ 3 - 0
blade-service-api/blade-manager-api/src/main/java/org/springblade/manager/dto/FormulaBean.java

@@ -4,6 +4,8 @@ import lombok.Data;
 import org.springblade.manager.entity.Formula;
 import org.springframework.beans.BeanUtils;
 
+import java.util.Map;
+
 /**
  * @author yangyj
  * @Date 2022/6/14 16:27
@@ -37,6 +39,7 @@ public class FormulaBean {
     private Long projectId;
     private String dev;
     private Integer ver;
+    private Map<String,Object> dict;
     public Formula toFormula(){
         Formula f= new Formula();
         BeanUtils.copyProperties(this,f);

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

@@ -1310,7 +1310,7 @@ public class InformationWriteQueryController extends BladeController {
                     String sql = "select sort from m_wbs_tree_contract where contract_id = '" + node.getContractId() + "' and (id = '" + node.getId() + "' or old_id = '" + node.getId() + "')";
                     List<WbsTreeContract> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
                     List<Integer> collect = query.stream().filter(f -> ObjectUtils.isNotEmpty(f.getSort())).collect(Collectors.toList()).stream().map(WbsTreeContract::getSort).collect(Collectors.toList());
-                    Integer max;
+                    Integer max=1;
                     if (collect.size() > 0) {
                         max = collect.stream().reduce(collect.get(0), Integer::max);
                     } else {
@@ -1391,7 +1391,7 @@ public class InformationWriteQueryController extends BladeController {
                         String sql = "select sort from m_wbs_tree_contract where contract_id = '" + node.getContractId() + "' and (id = '" + node.getId() + "' or old_id = '" + node.getId() + "')";
                         List<WbsTreeContract> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
                         List<Integer> collect = query.stream().filter(f -> ObjectUtils.isNotEmpty(f.getSort())).collect(Collectors.toList()).stream().map(WbsTreeContract::getSort).collect(Collectors.toList());
-                        Integer max;
+                        Integer max=1;
                         if (collect.size() > 0) {
                             max = collect.stream().reduce(collect.get(0), Integer::max);
                         } else {
@@ -1833,7 +1833,7 @@ public class InformationWriteQueryController extends BladeController {
                 String sql = "select sort from m_wbs_tree_contract where contract_id = '" + treeContract.getContractId() + "' and (id = '" + half.getId() + "' or old_id = '" + half.getId() + "')";
                 List<WbsTreeContract> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(WbsTreeContract.class));
                 List<Integer> collect = query.stream().filter(f -> ObjectUtils.isNotEmpty(f.getSort())).collect(Collectors.toList()).stream().map(WbsTreeContract::getSort).collect(Collectors.toList());
-                Integer max;
+                Integer max =1 ;
                 if (collect.size() > 0) {
                     max = collect.stream().reduce(collect.get(0), Integer::max);
                 } else {
@@ -1912,7 +1912,7 @@ public class InformationWriteQueryController extends BladeController {
         if (saveList.size() > 0) {
             //保存施工日志
             if (saveLedger.size() > 0) {
-                this.constructionLedgerService.saveBatch(saveLedger, 1000);
+                this.constructionLedgerService.saveBatch(saveLedger,1000);
             }
 
             try {

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

@@ -427,7 +427,8 @@ public class TaskController extends BladeController {
 	 */
 	private void integrationMethod(TaskQueryVO queryVO, Map<String,Task> masterTaskMap, Map<String,TaskParallel> parallelMap, List<String> parallelProcessInstanceIds, String status){
 		//先查询符合条件的流程
-		LambdaQueryWrapper<Task> wrapper = Wrappers.<Task>lambdaQuery().eq(Task::getIsDeleted, 0).eq(Task::getProjectId, queryVO.getProjectId());
+		LambdaQueryWrapper<Task> wrapper = Wrappers.<Task>lambdaQuery().eq(Task::getIsDeleted, 0)
+				.eq(Task::getProjectId, queryVO.getProjectId()).eq(StringUtils.isNotBlank(queryVO.getBatch()),Task::getBatch,queryVO.getBatch());
 		this.integrationMethod(wrapper, queryVO);
 
 		//符合条件的集合

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

@@ -77,6 +77,10 @@ public interface InformationQueryMapper extends BaseMapper<InformationQuery> {
 	 * 统计
 	 */
 	Integer countInformationQuery(@Param("query") InformationQueryVO informationQuery);
+	/**
+	 * 统计
+	 */
+	Integer countInformationQueryTwo(@Param("query") InformationQueryVO informationQuery);
 
 	/**
 	 * 自定义分页

+ 41 - 0
blade-service/blade-business/src/main/java/org/springblade/business/mapper/InformationQueryMapper.xml

@@ -384,6 +384,47 @@
         ) AS query
     </select>
 
+    <select id="countInformationQueryTwo" resultType="java.lang.Integer">
+        select
+        count( distinct query.id)
+        from
+        (
+            select
+            query.id
+            from
+            (
+                select
+                iq.id,
+                (case iq.STATUS when 0 THEN null else t.batch end) as report_number,
+                date_format(iq.create_time,'%Y-%m-%d') as createTimes
+                from u_information_query iq left join (select  * from u_task k where k.status!=3 and k.contract_id = #{query.contractId}) t on iq.id = t.form_data_id  and t.is_deleted = 0
+                where
+                iq.is_deleted = 0
+                and iq.classify = #{query.classify}
+                and iq.contract_id = #{query.contractId}
+                <if test="query.taskStatus != null and query.taskStatus != ''"> and iq.status = #{query.taskStatus} </if>
+                <if test="query.sourceType != null and query.sourceType != ''"> and iq.source_type = #{query.sourceType} </if>
+                <if test="query.reportNumber != null and query.reportNumber != ''"> and t.batch = #{query.reportNumber} </if>
+                <if test="query.fileUserIdAndName != null and query.fileUserIdAndName != ''"> and iq.file_user_id_and_name like concat('%',#{query.fileUserIdAndName},'%') </if>
+                <if test="query.queryValue != null and query.queryValue != ''"> and (iq.name like concat('%',#{query.queryValue},'%') OR iq.number like concat('%',#{query.queryValue},'%')) </if>
+                <if test="query.firstTitle != null and query.firstTitle != ''"> and iq.type = 3 </if>
+                <if test="query.firstTitle == null or query.firstTitle == ''"> and iq.type != 3 </if>
+                <if test="query.wbsIds != null">
+                and iq.wbs_id in
+                <foreach collection="query.wbsIds" item="wbsIdc" open="(" separator="," close=")">
+                    #{wbsIdc}
+                </foreach>
+                </if>
+            ) AS query
+        where
+        1 = 1
+        <if test="query.reportNumber != null and query.reportNumber != ''"> and report_number = #{query.reportNumber} </if>
+        <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
+            and query.createTimes between #{query.startTime} and #{query.endTime}
+        </if>
+        ) AS query
+    </select>
+
     <select id="selectInformationQueryPage" resultMap="informationQueryResultMap">
         select
             query.wbs_id,

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

@@ -460,7 +460,7 @@ public class InformationQueryServiceImpl extends BaseServiceImpl<InformationQuer
         }
 
         //获取总量
-        Integer count = this.baseMapper.countInformationQuery(vo);
+        Integer count = this.baseMapper.countInformationQueryTwo(vo);
 
         //获取数据
         List<InformationQuery> result = this.baseMapper.selectInformationQueryPageTwo(current, page.getSize(), vo);

+ 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;
         }
 

+ 1 - 0
blade-service/blade-manager/src/main/java/com/mixsmart/utils/CustomFunction.java

@@ -7,6 +7,7 @@ import cn.hutool.core.util.HashUtil;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.RadixUtil;
 import cn.hutool.dfa.SensitiveUtil;
+import com.alibaba.fastjson.JSON;
 import com.jfireel.expression.Expression;
 import com.jfireel.expression.node.CalculateNode;
 import com.jfireel.expression.node.impl.CompileObjectMethodNode;

+ 39 - 30
blade-service/blade-manager/src/main/java/org/springblade/manager/controller/FormulaController.java

@@ -169,7 +169,19 @@ public class FormulaController {
             }
             List<Map<String,Object>> listMap = this.jdbcTemplate.queryForList(sb.toString());
             if(Func.isNotEmpty(listMap)){
-                return R.data(BeanUtil.toBean(listMap.get(0),FormulaBean.class));
+                Map<String,Object> map =listMap.get(0);
+                String rely = StringUtils.handleNull(map.get("rely"));
+                FormulaBean fb=BeanUtil.toBean(map,FormulaBean.class);
+                if(StringUtils.isNotEmpty(rely)){
+                    String[] relyArr = rely.split(StringPool.COMMA);
+                   List<Map<String,Object>> mapList =this.jdbcTemplate.queryForList("select CONCAT(a.tab_en_name,':',b.e_key) ekey,a.tab_ch_name tableName,b.e_name ename  ,b.e_length elength,c.dict_value type from m_table_info a JOIN m_wbs_form_element b on a.id=b.f_id  LEFT JOIN (select dict_key, dict_value from blade_dict where code ='data_type' and parent_id > 0 and is_sealed = 0 and is_deleted = 0 )c on b.e_type=c.dict_key" +
+                            " where  a.tab_en_name in( "+ Arrays.stream(relyArr).map(e->e.split(StringPool.COLON)[0]).distinct().collect(Collectors.joining(StringPool.COMMA,"'","'"))+")");
+                   if(ListUtils.isNotEmpty(mapList)){
+                       fb.setDict(mapList.stream().filter(e-> Arrays.stream(relyArr).anyMatch(c->StringUtils.isEquals(e.get("ekey"),c))).collect(Collectors.toMap(e->StringUtils.handleNull(e.get("ekey")), e->e)));
+                   }
+
+                }
+                return R.data(fb);
             }
 
         }
@@ -307,6 +319,24 @@ public class FormulaController {
         return R.fail("无数据");
     }
 
+
+    public static String TEMPLATE="{\n" +
+            "'type': 'radio',\n" +
+            "'info': {\n" +
+            "'label': '是否引用公式数据',\n" +
+            "'value': [\n" +
+            "{\n" +
+            "'label': '是',\n" +
+            "'value': 1\n" +
+            "},\n" +
+            "{\n" +
+            "'label': '否',\n" +
+            "'value': 0\n" +
+            "}\n" +
+            "]\n" +
+            "}\n" +
+            "}";
+
     @GetMapping("/panel")
     @ApiOperationSupport(order = 10)
     @ApiOperation(value = "公式交互面板", notes = "公式交互面板")
@@ -326,43 +356,22 @@ public class FormulaController {
                    Formula formula = this.service.getById(keyMapper.getFormulaId());
                    /*临时处理,等确定数据结构在优化*/
                    if(formula.getFormula().contains(".option")){
-                       result.put("type","radio");
-                       result.put("scope",0);
-                       Map<String,Object> info = new LinkedHashMap<>();
-                       result.put("info",info);
+                       JSONObject jo =JSON.parseObject(TEMPLATE);
+                       jo.put("scope",0);
+                       JSONObject info =jo.getJSONObject("info");
                        info.put("label","是否引用公式数据");
-                        List<Map<String,Object>> value = new ArrayList<>();
-                        info.put("value",value);
-                        Map<String,Object> y=new LinkedHashMap<>();
-                        Map<String,Object> n=new LinkedHashMap<>();
-                        value.add(y);
-                        value.add(n);
-                        y.put("label","是");
-                        y.put("value",1);
-                        n.put("label","否");
-                        n.put("value",0);
                        /*针对元素级别*/
                        List<Map<String,Object>> mapList=this.jdbcTemplate.queryForList("select id,parent_id parentId,table_id pKeyId,val value,e_key ekey,contract_id contractId,scope from m_formula_option where scope=0 and parent_id ="+fo.getParentId()+" and e_key='"+key+"' and contract_id="+fo.getContractId());
                        if(Func.isNotEmpty(mapList)){
-                           result.put("data",mapList.get(0));
+                           info.put("data",mapList.get(0));
                        }
+                     return    R.data(jo);
                    }else if (StringUtils.isEquals("MILE",formula.getNumber())){
                       if(StringUtils.isEquals(key,formula.getRelyList().get(0).split(StringPool.COLON)[1])){
-                          result.put("type","radio");
-                          result.put("scope",1);
-                          Map<String,Object> info = new LinkedHashMap<>();
-                          result.put("info",info);
+                          JSONObject jo =JSON.parseObject(TEMPLATE);
+                          jo.put("scope",1);
+                          JSONObject info =jo.getJSONObject("info");
                           info.put("label","竖直方向");
-                          List<Map<String,Object>> value = new ArrayList<>();
-                          info.put("value",value);
-                          Map<String,Object> y=new LinkedHashMap<>();
-                          Map<String,Object> n=new LinkedHashMap<>();
-                          value.add(y);
-                          value.add(n);
-                          y.put("label","是");
-                          y.put("value",1);
-                          n.put("label","否");
-                          n.put("value",0);
                           List<Map<String,Object>> mapList=this.jdbcTemplate.queryForList("select id,parent_id parentId,table_id pKeyId,val value,e_key ekey,contract_id contractId,scope from m_formula_option where scope=1 and table_id="+fo.getPKeyId()+" and parent_id ="+fo.getParentId()+" and e_key='"+key+"' and contract_id="+fo.getContractId());
                           if(Func.isNotEmpty(mapList)){
                               result.put("data",mapList.get(0));

+ 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 - 1
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java

@@ -99,7 +99,8 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
             //查询表格
             return this.wbsTreeContractService.list(wrapper);
         } else {
-            return this.wbsTreeContractService.list(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getParentId, treeNode.getId()).eq(WbsTreeContract::getContractId, treeNode.getContractId()).eq(WbsTreeContract::getType, "1"));
+            //.eq(WbsTreeContract::getType, "1")
+            return this.wbsTreeContractService.list(Wrappers.<WbsTreeContract>lambdaQuery().eq(WbsTreeContract::getParentId, treeNode.getId()).eq(WbsTreeContract::getContractId, treeNode.getContractId()));
         }
     }
 

+ 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);
+
 }

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

@@ -738,7 +738,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                  Formula formula=fd.getFormula();
                  String f=formula.getFormula();
                  if (f.contains("converge")){
-                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(\\w+)\\(([^]]+)\\)",f);
+                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(converge)\\(([^)]+)\\)",f);
                      while (m.find()){
                          List<FormData> target = getFormDataByCode(m.group(2));
                          Object data =target.stream().flatMap(e->e.getValues().stream()).map(ElementData::getValue).collect(Collectors.toList());
@@ -746,7 +746,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                      }
                  }
                  if(f.contains("compound")){
-                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(compound)\\(([^]]+)\\)",f);
+                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(compound)\\(([^)]+)\\)",f);
                      while (m.find()){
                          List<FormData> target = getFormDataByCode(m.group(2));
                          List<List<Object>> values=target.stream().map(e->e.getValues().stream().map(ElementData::getValue).collect(Collectors.toList())).collect(Collectors.toList());
@@ -762,7 +762,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                      }
                  }
                  if(f.contains(".option")){
-                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(optionC?)\\(([^]]+)\\)",f);
+                     Matcher m = RegexUtils.matcher("T\\(com.mixsmart.utils.CustomFunction\\)\\.(optionC?)\\(([^)]+)\\)",f);
                      while (m.find()){
                        String[] args= m.group(2).split(",");
                        String flag=args[0];

+ 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;
+        }
+    }
+}