Quellcode durchsuchen

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

lvy vor 1 Woche
Ursprung
Commit
d0b5d5d991

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

@@ -5915,17 +5915,74 @@ public class FormulaServiceImpl extends BaseServiceImpl<FormulaMapper, Formula>
                         //判断 为
                         String falseStr = pa.get(2);;
                         if(pa.get(2).contains("(") && pa.get(2).contains(",") && pa.get(2).split(",").length == 3){
-                            pa.set(2,"-10086");
+                            pa.set(2,"(-10086)");
+                        }else{
+                            if(pa.get(2).isEmpty()){
+                                pa.set(2, "''");
+                            }else{
+                                if(!pa.get(2).contains("(")){
+                                    pa.set(2, "(" + pa.get(2) + ")");
+                                }
+                            }
                         }
-                        String string = pa.get(0) + "?" + pa.get(1) + ":(" + pa.get(2) + ")";
+                        String string = pa.get(0) + "?" + pa.get(1) + ":" + pa.get(2);
                         Expression parse = Expression.parse(string);
-                        Object data = parse.calculate(currentMap);
-                        //递归计算
-                        if(Objects.equals(String.valueOf(data),"-10086")){
-                            //进入递归算法
-                            data = multipleIfElse(falseStr,currentMap);
+
+                        // 针对一个元素多个单元格的数据单独处理
+                        Object o = currentMap.get("E");
+                        if(o != null){
+                            Map<String, List<String>> tableDataMap = (Map<String, List<String>>) o;
+
+                            Set<Integer> set = tableDataMap.values().stream().map(List::size).filter(size -> size != 1).collect(Collectors.toSet());
+                            List<Integer> collect = new ArrayList<>(set);
+                            if(collect.size() > 1){
+                                throw new com.alibaba.nacos.shaded.com.google.protobuf.ServiceException("计算单元格不一致 无法计算");
+                            }
+                            //一个元素存在多单元格
+                            if(collect.size() == 1){
+                                List<List<String>> collect1 = tableDataMap.values().stream().filter(x -> x.size() > 1).collect(Collectors.toList());
+                                //复制一份
+                                List<List<String>> lists = collect1.stream().map(ArrayList::new).collect(Collectors.toList());
+                                List<Object> dataAll = new ArrayList<>();
+                                //数据按 行单独计算
+                                for (int i = 0; i < collect.get(0); i++) {
+                                    for (int j = 0; j < lists.size(); j++) {
+                                        List<String> strings = collect1.get(j);
+                                        strings.clear();
+                                        strings.add(lists.get(j).get(i).toString());
+                                    }
+
+                                    Object data = parse.calculate(currentMap);
+                                    //递归计算
+                                    if(Objects.equals(String.valueOf(data),"-10086")){
+                                        //进入递归算法
+                                        data = multipleIfElse(falseStr,currentMap);
+                                    }
+                                    if("".equals(data)){
+                                        data = "/";
+                                    }
+                                    dataAll.add(data);
+                                }
+                                //赋值元素是否是多个单元格
+                                if(fd.getValues().size() > 1){
+                                    f = f.replace(f, putDataWithKey(dataAll, tec));
+                                } else {
+                                    //计算平均值
+                                    OptionalDouble op = dataAll.stream().filter(StringUtils::isNumber).map(StringUtils::handleNull).mapToDouble(Double::parseDouble).average();
+                                    if (op.isPresent()) {
+                                        f = f.replace(f, putDataWithKey(op.getAsDouble(), tec));
+                                    }
+                                }
+                            } else {
+                                Object data = parse.calculate(currentMap);
+                                //递归计算
+                                if(Objects.equals(String.valueOf(data),"-10086")){
+                                    //进入递归算法
+                                    data = multipleIfElse(falseStr,currentMap);
+                                }
+                                f = f.replace(f, putDataWithKey(data, tec));
+                            }
                         }
-                        f = f.replace(f, putDataWithKey(data, tec));
                     } else {
                         f = f.replace(f, "参数格式错误");
                     }

+ 18 - 0
blade-service/blade-meter/src/main/java/org/springblade/meter/config/RedissonConfig.java

@@ -0,0 +1,18 @@
+package org.springblade.meter.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+    @Bean
+    public RedissonClient redissonClient() {
+        Config config = new Config();
+        config.useSingleServer()
+                .setAddress("redis://127.0.0.1:6379");
+        return Redisson.create(config);
+    }
+}

+ 61 - 2
blade-service/blade-meter/src/main/java/org/springblade/meter/controller/MiddleMeterApplyController.java

@@ -16,19 +16,25 @@
  */
 package org.springblade.meter.controller;
 
+import com.alibaba.nacos.shaded.com.google.protobuf.ServiceException;
 import io.swagger.annotations.*;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import lombok.AllArgsConstructor;
 
 import javax.validation.Valid;
 
+import org.redisson.Redisson;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springblade.core.mp.support.Query;
+import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.api.R;
 import org.springblade.core.tool.utils.Func;
 import org.springblade.meter.dto.MiddleMeterApplyDTO;
 import org.springblade.meter.dto.WbsNodeDTO;
 import org.springblade.meter.entity.AttachmentForm;
 import org.springblade.meter.vo.*;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -39,6 +45,7 @@ import org.springblade.core.boot.ctrl.BladeController;
 
 import java.math.BigDecimal;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 中间计量申请表 控制器
@@ -53,6 +60,9 @@ import java.util.List;
 public class MiddleMeterApplyController extends BladeController {
 
     private final IMiddleMeterApplyService middleMeterApplyService;
+    private final BladeRedis bladeRedis;
+    @Autowired
+    private  RedissonClient redissonClient;
 
 
     /**
@@ -205,10 +215,59 @@ public class MiddleMeterApplyController extends BladeController {
             @ApiImplicitParam(name = "contractId", value = "合同id", required = true),
             @ApiImplicitParam(name = "contractPeriodId", value = "合同计量期id", required = true)
     })
-    public R<String> getMeterNumber(MiddleMeterApply middleMeterApply) {
-        return R.data(middleMeterApplyService.getMeterNumber(middleMeterApply));
+    public R<String> getMeterNumber(MiddleMeterApply middleMeterApply) throws ServiceException {
+        RLock lock = redissonClient.getLock("getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId());
+        // 不指定leaseTime,Redisson会自动续期(默认30秒,可通过Config配置)
+        lock.lock();
+        try {
+            String meterNumber = middleMeterApplyService.getMeterNumber(middleMeterApply);
+            String redisKey = "getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId() + ":" + meterNumber;
+
+            if (bladeRedis.exists(redisKey)) {
+                // 初始编号已存在,生成新编号
+                String meterNumber1 = getMeterNumber1(meterNumber, middleMeterApply.getContractId(), middleMeterApply.getContractPeriodId());
+                String newRedisKey = "getMeterNumber:" + middleMeterApply.getContractId() + ":" + middleMeterApply.getContractPeriodId() + ":" + meterNumber1;
+                bladeRedis.setEx(newRedisKey, meterNumber1, 300L);
+                return R.data(meterNumber1); // 返回新编号
+            } else {
+                bladeRedis.setEx(redisKey, meterNumber, 300L);
+                return R.data(meterNumber);
+            }
+        } finally {
+            // 确保锁释放(判断是否持有锁,避免异常场景下误释放)
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+
+    public String getMeterNumber1(String meterNumber, Long contractId, Long contractPeriodId) throws ServiceException {
+        // 校验编号格式,避免substring异常
+        int lastDashIndex = meterNumber.lastIndexOf("-");
+        if (lastDashIndex == -1) {
+            throw new ServiceException("编号格式错误,缺少分隔符 '-'");
+        }
+        String prefix = meterNumber.substring(0, lastDashIndex + 1);
+        int lastNumber = Integer.parseInt(meterNumber.substring(lastDashIndex + 1));
+
+        // 循环生成新编号,直到不存在于Redis中
+        while (true) {
+            lastNumber++;
+            String newMeterNumber = prefix + lastNumber;
+            String redisKey = "getMeterNumber:" + contractId + ":" + contractPeriodId + ":" + newMeterNumber;
+            // 如果新编号不存在,则返回
+            if (!bladeRedis.exists(redisKey)) {
+                return newMeterNumber;
+            }
+            // 防止无限循环(极端情况:连续N个编号都被占用,可加最大次数限制)
+            if (lastNumber > 1000) { // 例如最多尝试1000次
+                throw new ServiceException("生成编号失败,尝试次数过多");
+            }
+        }
     }
 
+
+
     /**
      * 获取本期计量总金额
      */

+ 33 - 237
blade-service/blade-meter/src/main/java/org/springblade/meter/service/impl/MiddleMeterApplyServiceImpl.java

@@ -698,256 +698,52 @@ public class MiddleMeterApplyServiceImpl extends BaseServiceImpl<MiddleMeterAppl
 
     @Override
     public String getMeterNumber(MiddleMeterApply apply) {
-        if (apply.getContractPeriodId() == -1) {
+        //如果计量期id为-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)) {
-            return "";
+        if (StringUtils.isBlank(contractNumber)){
+            throw new ServiceException("未获取到当前合同段编号信息");
         }
-        str.append(contractNumber).append("-");
-
-        // 获取计量期信息
+        str.append(contractNumber+"-");
+        //获取计量期信息
         ContractMeterPeriod contractMeterPeriod = contractMeterPeriodService.getById(apply.getContractPeriodId());
-        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())) {
-            return "";
-        }
-        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);
-                }
-            }
-
-            // Redis中没有可用流水号,从数据库初始化
-            return initAndGetSerialFromRedis(apply);
-
-        } catch (Exception e) {
-            log.error("Redis获取流水号异常", e);
-            return getNextSerialNumberFromDB(apply);
+        if (contractMeterPeriod == null || StringUtils.isBlank(contractMeterPeriod.getPeriodNumber())){
+            throw new ServiceException("未获取到计量期期号信息");
         }
-    }
-
-    /**
-     * 初始化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));
+        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();
+                    }
                 }
-                bladeRedis.expire(serialKey, 86400L);
-
-                return nextSerial;
-            } else {
-                // 等待其他线程初始化完成
-                Thread.sleep(100);
-                return getNextSerialNumber(apply); // 重试
+                str.append(list.size()+1);
             }
-        } 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;
         }
+        return str.toString();
     }
-
-
-
     /**
      * 获取本期计量总金额
      */