Эх сурвалжийг харах

Merge branch 'test-merge' of http://219.151.181.73:3000/zhuwei/bladex into test-merge

lvy 21 цаг өмнө
parent
commit
7ba1ade76f

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

@@ -3628,6 +3628,7 @@ public R<Boolean> updateContractNodeParameter(@RequestParam Long pKeyId, @Reques
             if (sourceType >= targetType) {
                 throw new ServiceException("当前节点类型不能大于或等于父级节点类型");
             }
+            node.setNodeType(nodeType);
         }
     }else {
         node.setNodeType(nodeType);

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

@@ -1743,7 +1743,7 @@ public class TaskController extends BladeController {
             if (dto.getSelectedType().equals(1)) {
                 // 待办页面逻辑
                 if (ObjectUtil.isNotEmpty(dto.getStatusValue()) && dto.getStatusValue().equals(1)) {
-                    sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND u_task_parallel.e_visa_status =0 AND u_task_parallel.e_visa_content !='当前等待电签的批次较多,请等待几分钟后刷新页面查看........')");
+                    sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND (u_task_parallel.e_visa_status IS NULL OR u_task_parallel.e_visa_status=0) AND (u_task_parallel.e_visa_content IS NULL OR u_task_parallel.e_visa_content != '当前等待电签的批次较多,请等待几分钟后刷新页面查看........'))");
                     params.add(1);
                     params.add(SecureUtil.getUserId());
                     // 关联电签状态字段
@@ -1757,7 +1757,7 @@ public class TaskController extends BladeController {
                     return R.data(emptyPage);
                 } else {
                     // 待办页未选状态:默认查待审批
-                    sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND u_task_parallel.e_visa_status =0 AND u_task_parallel.e_visa_content!='当前等待电签的批次较多,请等待几分钟后刷新页面查看........')");
+                    sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND (u_task_parallel.e_visa_status IS NULL OR u_task_parallel.e_visa_status=0) AND (u_task_parallel.e_visa_content IS NULL OR u_task_parallel.e_visa_content != '当前等待电签的批次较多,请等待几分钟后刷新页面查看........'))");
                     params.add(1);
                     params.add(SecureUtil.getUserId());
                     sqlString.append(" AND status = 1");
@@ -1773,7 +1773,7 @@ public class TaskController extends BladeController {
                 sqlString.append("report_user = ?");
                 params.add(SecureUtil.getUserId());
             } else if (dto.getSelectedType().equals(4)) {
-                sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND u_task_parallel.e_visa_status =0 AND u_task_parallel.e_visa_content='当前等待电签的批次较多,请等待几分钟后刷新页面查看........')");
+                sqlString.append("EXISTS (SELECT 1 FROM u_task_parallel WHERE u_task.process_instance_id = u_task_parallel.process_instance_id AND u_task_parallel.status = ? AND u_task_parallel.task_user = ? AND (u_task_parallel.e_visa_status IS NULL OR u_task_parallel.e_visa_status=0) AND u_task_parallel.e_visa_content='当前等待电签的批次较多,请等待几分钟后刷新页面查看........')");
                 params.add(1);
                 params.add(SecureUtil.getUserId());
                 sqlString.append(" AND status = 1");

+ 3 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/feign/WbsTreeContractClientImpl.java

@@ -177,6 +177,9 @@ public class WbsTreeContractClientImpl implements WbsTreeContractClient {
         if(StringUtils.isNotEmpty(node.getMajorDataType())){
             wrappers.set(WbsTreeContract::getMajorDataType,node.getMajorDataType());
         }
+        if(StringUtils.isNotEmpty(node.getNodeType())){
+            wrappers.set(WbsTreeContract::getNodeType,node.getNodeType());
+        }
         return this.wbsTreeContractService.update(wrappers.eq(WbsTreeContract::getPKeyId, node.getPKeyId()));
     }
 

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

@@ -1894,7 +1894,7 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                 List<NodeTable> subTabList = tec.getTableAll().stream().filter(e -> e.getNodeName().contains("附表") && (e.getTableType() == 1 || e.getTableType() == 5)).collect(Collectors.toList());
                 if(!subTabList.isEmpty()){
                     List<Long> removeIds=subTabList.stream().map(e->e.getPKeyId()).collect(Collectors.toList());
-                    this.wbsTreeContractMapper.deleteByIds(removeIds);
+                    this.wbsTreeContractMapper.deleteLogicByIds(removeIds);
                 }
             }
         } catch (Exception e) {

+ 238 - 36
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MiddleMeterApplyServiceImpl.java

@@ -28,6 +28,7 @@ import org.springblade.common.utils.SnowFlakeUtil;
 import org.springblade.core.log.exception.ServiceException;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.core.tool.utils.ObjectUtil;
 import org.springblade.manager.entity.ContractInfo;
@@ -83,6 +84,7 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
 
     private final IAttachmentFormServiceTask attachmentFormServiceTask;
 
+    private final BladeRedis bladeRedis;
 
 
     /**
@@ -694,58 +696,258 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
         return vo;
     }
 
-    /**
-     * 获取计量单编号
-     */
     @Override
     public String getMeterNumber(MiddleMeterApply apply) {
-        //如果计量期id为-1则代表不用查询
-        if (apply.getContractPeriodId() == -1){
+        if (apply.getContractPeriodId() == -1) {
+            return "";
+        }
+
+        String lockKey = "meter_number_lock:" + apply.getContractId() + ":" + apply.getContractPeriodId();
+        String requestId = UUID.randomUUID().toString();
+
+        try {
+            // 获取分布式锁
+            if (!tryLock(lockKey, requestId, 10L)) {
+                return "";
+            }
+
+            // 生成并检查编号
+            int maxRetries = 5;
+            for (int retryCount = 0; retryCount < maxRetries; retryCount++) {
+                String number = generateMeterNumber(apply);
+                if (StringUtils.isBlank(number)) {
+                    continue;
+                }
+
+                // 在Redis中预占编号
+                if (reserveNumber(number)) {
+                    return number;
+                }
+
+                try {
+                    Thread.sleep(100 * (retryCount + 1));
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    break;
+                }
+            }
             return "";
+
+        } finally {
+            releaseLock(lockKey, requestId);
+        }
+    }
+
+    /**
+     * 使用setEx实现分布式锁
+     */
+    private boolean tryLock(String lockKey, String requestId, long expireSeconds) {
+        int maxRetry = 3;
+        for (int i = 0; i < maxRetry; i++) {
+            // 先检查是否已存在锁
+            if (!bladeRedis.exists(lockKey)) {
+                // 不存在时尝试设置锁
+                bladeRedis.setEx(lockKey, requestId, expireSeconds);
+
+                // 再次检查确认自己是锁的持有者
+                String currentOwner = bladeRedis.get(lockKey);
+                if (requestId.equals(currentOwner)) {
+                    return true;
+                }
+            }
+
+            if (i < maxRetry - 1) {
+                try {
+                    Thread.sleep(100 * (i + 1));
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    break;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 安全释放锁
+     */
+    private void releaseLock(String lockKey, String requestId) {
+        try {
+            String currentValue = bladeRedis.get(lockKey);
+            if (requestId.equals(currentValue)) {
+                bladeRedis.del(lockKey);
+            }
+        } catch (Exception e) {
+            log.error("释放锁失败", e);
+        }
+    }
+
+    /**
+     * 预占编号 - 使用setEx + 检查机制
+     */
+    private boolean reserveNumber(String number) {
+        String numberKey = "meter_number_reserve:" + number;
+
+        // 先检查是否已存在
+        if (bladeRedis.exists(numberKey)) {
+            return false;
         }
+
+        // 尝试设置,如果在此期间有其他线程设置,可能会覆盖,但通过value来区分
+        String reserveValue = "reserved:" + System.currentTimeMillis() + ":" + Thread.currentThread().getId();
+        bladeRedis.setEx(numberKey, reserveValue, 300L); // 5分钟过期
+
+        // 再次检查确认我们是设置者
+        String currentValue = bladeRedis.get(numberKey);
+        return reserveValue.equals(currentValue);
+    }
+
+    private String generateMeterNumber(MiddleMeterApply apply) {
         StringBuilder str = new StringBuilder();
-        //获取合同信息
+
+        // 获取合同信息
         ContractInfo info = baseMapper.getContractInfo(apply.getContractId());
         String contractNumber = info.getContractNumber();
-        if (StringUtils.isBlank(contractNumber)){
-            throw new ServiceException("未获取到当前合同段编号信息");
+        if (StringUtils.isBlank(contractNumber)) {
+            return "";
         }
-        str.append(contractNumber+"-");
-        //获取计量期信息
+        str.append(contractNumber).append("-");
+
+        // 获取计量期信息
         ContractMeterPeriod contractMeterPeriod = contractMeterPeriodService.getById(apply.getContractPeriodId());
-        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())){
-            throw new ServiceException("未获取到计量期期号信息");
+        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())) {
+            return "";
         }
-        str.append(contractMeterPeriod.getPeriodNumber()+"-");
-        //获取流水号:当前合同段存在的当前计量期的申请单总数+1
-        List<MiddleMeterApply> allAPPly = baseMapper.getAllAPPly(apply.getContractId(), apply.getContractPeriodId());
-        if (allAPPly.size() == 0){
-            str.append(1);
-        }else {
-            List<Integer> list = allAPPly.stream().filter(l -> l.getApproveStatus() != null).map(l -> l.getApproveStatus()).sorted().collect(Collectors.toList());
-            if (list.size() == 0 || list.get(0) != 1){
-                str.append(1);
-            }else {
-                for (int i = 0; i < list.size() - 1; i++) {
-                    Integer num = list.get(i);
-                    if (num .equals(list.get(i+1)) ){
-                        throw new ServiceException("计量期期号出现相同,请联系管理员");
-                    }
-                    Integer j = ++num;
-                    String j2 = j.toString();
-                    String j3 = list.get(i + 1).toString();
-                    if (!j2.equals(j3)){
-                        str.append(num);
-                        return str.toString();
-                    }
+        str.append(contractMeterPeriod.getPeriodNumber()).append("-");
+
+        // 从Redis获取流水号
+        Integer nextSerial = getNextSerialNumber(apply);
+        if (nextSerial == null) {
+            log.error("获取流水号失败");
+            return "";
+        }
+        str.append(nextSerial);
+        return str.toString();
+    }
+
+    /**
+     * 使用Redis管理可用流水号
+     */
+    private Integer getNextSerialNumber(MiddleMeterApply apply) {
+        String serialKey = "meter_serial_available:" + apply.getContractId() + ":" + apply.getContractPeriodId();
+
+        try {
+            // 先尝试从Redis获取最小可用流水号
+            String minSerial = bladeRedis.lIndex(serialKey, 0);
+            if (minSerial != null) {
+                // 弹出最小的可用流水号
+                String popped = bladeRedis.lPop(serialKey);
+                if (popped != null) {
+                    return Integer.parseInt(popped);
                 }
-                str.append(list.size()+1);
             }
 
+            // Redis中没有可用流水号,从数据库初始化
+            return initAndGetSerialFromRedis(apply);
+
+        } catch (Exception e) {
+            log.error("Redis获取流水号异常", e);
+            return getNextSerialNumberFromDB(apply);
         }
-        return str.toString();
     }
 
+    /**
+     * 初始化Redis中的流水号池
+     */
+    private Integer initAndGetSerialFromRedis(MiddleMeterApply apply) {
+        String lockKey = "serial_init_lock:" + apply.getContractId() + ":" + apply.getContractPeriodId();
+        String requestId = UUID.randomUUID().toString();
+
+        try {
+            // 加锁防止重复初始化
+            if (tryLock(lockKey, requestId, 10L)) {
+                // 再次检查,防止其他线程已经初始化完成
+                String serialKey = "meter_serial_available:" + apply.getContractId() + ":" + apply.getContractPeriodId();
+                if (bladeRedis.lLen(serialKey) > 0) {
+                    String popped = bladeRedis.lPop(serialKey);
+                    return popped != null ? Integer.parseInt(popped) : null;
+                }
+
+                // 从数据库获取已使用的流水号
+                List<Integer> usedSerials = getUsedSerialsFromDB(apply);
+                int nextSerial = findNextAvailableSerial(usedSerials);
+
+                // 将后续的可用流水号预先放入Redis
+                for (int i = nextSerial + 1; i <= nextSerial + 10; i++) {
+                    bladeRedis.rPush(serialKey, String.valueOf(i));
+                }
+                bladeRedis.expire(serialKey, 86400L);
+
+                return nextSerial;
+            } else {
+                // 等待其他线程初始化完成
+                Thread.sleep(100);
+                return getNextSerialNumber(apply); // 重试
+            }
+        } catch (Exception e) {
+            log.error("初始化流水号池失败", e);
+            return getNextSerialNumberFromDB(apply);
+        } finally {
+            releaseLock(lockKey, requestId);
+        }
+    }
+
+    /**
+     * 从数据库获取已使用的流水号
+     */
+    private List<Integer> getUsedSerialsFromDB(MiddleMeterApply apply) {
+        try {
+            List<MiddleMeterApply> allApply = baseMapper.getAllAPPly(apply.getContractId(), apply.getContractPeriodId());
+            return allApply.stream()
+                    .filter(l -> l.getApproveStatus() != null)
+                    .map(MiddleMeterApply::getApproveStatus)
+                    .sorted()
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("从数据库获取已使用流水号失败", e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 查找下一个可用的流水号
+     */
+    private int findNextAvailableSerial(List<Integer> usedSerials) {
+        if (usedSerials.isEmpty()) {
+            return 1;
+        }
+
+        // 查找第一个可用的流水号
+        for (int i = 0; i < usedSerials.size(); i++) {
+            if (usedSerials.get(i) != i + 1) {
+                return i + 1;
+            }
+        }
+
+        // 如果所有序号都连续,返回下一个
+        return usedSerials.size() + 1;
+    }
+
+    /**
+     * 从数据库获取流水号(备用方案)
+     */
+    private Integer getNextSerialNumberFromDB(MiddleMeterApply apply) {
+        try {
+            List<Integer> usedSerials = getUsedSerialsFromDB(apply);
+            return findNextAvailableSerial(usedSerials);
+        } catch (Exception e) {
+            log.error("从数据库获取流水号失败", e);
+            return null;
+        }
+    }
+
+
+
     /**
      * 获取本期计量总金额
      */