|
@@ -2,7 +2,7 @@ package org.jeecg.modules.billet.billetOriginalProductRecord.controller;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.util.*;
|
|
|
-import java.util.concurrent.ThreadLocalRandom;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
import java.util.stream.Collectors;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
@@ -27,7 +27,6 @@ import org.jeecg.common.util.DateUtils;
|
|
|
import org.jeecg.common.util.oConvertUtils;
|
|
|
import org.jeecg.modules.actualControl.billetActual.billetActual.entity.BilletBasicInfo;
|
|
|
import org.jeecg.modules.actualControl.billetActual.billetActual.service.IBilletBasicInfoService;
|
|
|
-import org.jeecg.modules.actualControl.heatsActuals.service.IHeatsActualsService;
|
|
|
import org.jeecg.modules.billet.billetHotsend.entity.BilletHotsend;
|
|
|
import org.jeecg.modules.billet.billetHotsend.service.IBilletHotsendBaseService;
|
|
|
import org.jeecg.modules.billet.billetHotsendChangeShift.entity.BilletHotsendChangeShift;
|
|
@@ -37,6 +36,8 @@ import org.jeecg.modules.billet.billetOriginalProductRecord.entity.BilletOrigina
|
|
|
import org.jeecg.modules.billet.billetOriginalProductRecord.service.IBilletOriginalProductRecordService;
|
|
|
import org.jeecg.common.system.base.controller.JeecgController;
|
|
|
import org.jeecg.modules.billet.billetOriginalProductRecord.vo.*;
|
|
|
+import org.jeecg.modules.billet.stackingAndLoadingVehicles.entity.StackingAndLoadingVehicles;
|
|
|
+import org.jeecg.modules.billet.stackingAndLoadingVehicles.mapper.StackingAndLoadingVehiclesMapper;
|
|
|
import org.jeecg.modules.billet.storageBill.entity.HeatsActualsInfo;
|
|
|
import org.jeecg.modules.billet.storageBill.entity.StorageBillPrint;
|
|
|
import org.jeecg.modules.billet.storageBill.service.IStorageBillPrintService;
|
|
@@ -84,6 +85,8 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
|
|
|
@Autowired
|
|
|
private ISysDictService sysDictService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private StackingAndLoadingVehiclesMapper stackingAndLoadingVehiclesMapper;
|
|
|
/**
|
|
|
* 分页列表查询
|
|
|
*
|
|
@@ -180,13 +183,97 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
|
|
|
bopr.setIsEditCharge("2");
|
|
|
}
|
|
|
bopr.setUpdateTime(new Date());
|
|
|
+ // 判断remark字段是否为NULL,不为空代表需要起垛
|
|
|
+ if (oConvertUtils.isNotEmpty(bopr.getRemark())){
|
|
|
+ String str = bopr.getRemark();
|
|
|
+ String[] parts = str.split("-");
|
|
|
+ // 起垛的数量
|
|
|
+ int stackingSum = Integer.parseInt(parts[0]);
|
|
|
+ // 定尺
|
|
|
+ String size = parts[1];
|
|
|
+ String typeConfigId = parts[2];
|
|
|
+ handleAddStack(bopr.getCcmNo(), bopr.getHeatNo(), stackingSum, size, typeConfigId);
|
|
|
+ }
|
|
|
+ // 备注remark字段重置
|
|
|
+ bopr.setRemark("");
|
|
|
// 保存修改
|
|
|
billetOriginalProductRecordService.updateById(bopr);
|
|
|
}
|
|
|
return Result.OK("编辑成功!");
|
|
|
}
|
|
|
|
|
|
+ /***
|
|
|
+ * 处理起垛
|
|
|
+ * @param ccmNo
|
|
|
+ * @param heatNo
|
|
|
+ * @param stackingSum
|
|
|
+ * @param size
|
|
|
+ * @param typeConfigId
|
|
|
+ */
|
|
|
+ private void handleAddStack(String ccmNo, String heatNo, int stackingSum, String size, String typeConfigId) {
|
|
|
+ String classShiftGroup = String.format("class:shift:group:%s", ccmNo); // 班组
|
|
|
+ String classShift = String.format("class:shift:%s",ccmNo); // 班别
|
|
|
+ String shift = !oConvertUtils.getString(redisTemplate.opsForValue().get(classShift)).isEmpty() ? oConvertUtils.getString(redisTemplate.opsForValue().get(classShift)) : "";
|
|
|
+ String shiftGroup = !oConvertUtils.getString(redisTemplate.opsForValue().get(classShiftGroup)).isEmpty() ? oConvertUtils.getString(redisTemplate.opsForValue().get(classShiftGroup)) : "";
|
|
|
+ // 计算需要起垛的数量
|
|
|
+ int demandStackingSum = stackingSum / 4;
|
|
|
+ List<StackingAndLoadingVehicles> stackingAndLoadingVehiclesList = stackingAndLoadingVehiclesMapper.selectList(new QueryWrapper<StackingAndLoadingVehicles>()
|
|
|
+ .eq("ccm_no", ccmNo)
|
|
|
+ .eq("type_config_id", typeConfigId));
|
|
|
+ boolean allBilletNosNonNull = stackingAndLoadingVehiclesList != null &&
|
|
|
+ stackingAndLoadingVehiclesList.stream()
|
|
|
+ .allMatch(vehicle -> vehicle.getBilletNos() != null);
|
|
|
+ if (allBilletNosNonNull) {
|
|
|
+ log.info("{}{}", "没有可用的堆垛容器位置,起垛失败!", heatNo);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ StackingAndLoadingVehicles highAddressSALV = getHighestOccupiedLayer(stackingAndLoadingVehiclesList);
|
|
|
+ if (highAddressSALV == null) {
|
|
|
+ log.info("{}{}", "堆垛容器空位置获取为空,起垛失败!", heatNo);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (oConvertUtils.isEmpty(highAddressSALV.getBilletNos())){
|
|
|
+ // 根据铸机号、address、layer、typeConfigId查询堆垛容器位置
|
|
|
+ StackingAndLoadingVehicles nextPosition = stackingAndLoadingVehiclesMapper.selectOne(new QueryWrapper<StackingAndLoadingVehicles>()
|
|
|
+ .eq("ccm_no", ccmNo)
|
|
|
+ .eq("address", highAddressSALV.getAddress())
|
|
|
+ .eq("layer", highAddressSALV.getLayer())
|
|
|
+ .eq("type_config_id", typeConfigId));
|
|
|
+ nextPosition.setSize(size);
|
|
|
+ nextPosition.setShift(shift);
|
|
|
+ nextPosition.setShiftGroup(shiftGroup);
|
|
|
+ nextPosition.setHeatNo(heatNo);
|
|
|
+ nextPosition.setBilletNos(generateBilletNos(heatNo, ccmNo));
|
|
|
+ stackingAndLoadingVehiclesMapper.updateById(nextPosition);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 以demandStackingSum的值,确定需要计算出几个位置,根据highAddressSALV中address、layer,计算下个坐标位置
|
|
|
+ List<StackingAndLoadingVehicles> nextPositionsList = calculateNextPositions(highAddressSALV, demandStackingSum, ccmNo, heatNo);
|
|
|
|
|
|
+ // 检查是否成功计算出位置
|
|
|
+ if (nextPositionsList.isEmpty()) {
|
|
|
+ log.info("{}{}", "无法计算出可用位置,起垛失败!", heatNo);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ nextPositionsList.forEach(x -> {
|
|
|
+ // 根据铸机号、address、layer、typeConfigId查询堆垛容器位置
|
|
|
+ StackingAndLoadingVehicles nextPosition = stackingAndLoadingVehiclesMapper.selectOne(new QueryWrapper<StackingAndLoadingVehicles>()
|
|
|
+ .eq("ccm_no", x.getCcmNo())
|
|
|
+ .eq("address", x.getAddress())
|
|
|
+ .eq("layer", x.getLayer())
|
|
|
+ .eq("type_config_id", x.getTypeConfigId()));
|
|
|
+ x.setId(nextPosition.getId());
|
|
|
+ x.setSize(size);
|
|
|
+ x.setShift(shift);
|
|
|
+ x.setShiftGroup(shiftGroup);
|
|
|
+ x.setHeatNo(heatNo);
|
|
|
+ x.setCreateTime(nextPosition.getCreateTime());
|
|
|
+ x.setUpdateTime(new Date());
|
|
|
+ x.setSteel("");
|
|
|
+ x.setSpec("");
|
|
|
+ stackingAndLoadingVehiclesMapper.updateById(x);
|
|
|
+ });
|
|
|
+ }
|
|
|
/**
|
|
|
* 编辑
|
|
|
*
|
|
@@ -1660,4 +1747,103 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ private StackingAndLoadingVehicles getHighestOccupiedLayer(List<StackingAndLoadingVehicles> stackingAndLoadingVehiclesList) {
|
|
|
+ return Optional.ofNullable(stackingAndLoadingVehiclesList)
|
|
|
+ .filter(list -> !list.isEmpty())
|
|
|
+ .map(list -> list.stream()
|
|
|
+ .filter(item -> item.getBilletNos() != null && !item.getBilletNos().trim().isEmpty())
|
|
|
+ .max(Comparator.comparingInt((StackingAndLoadingVehicles item) -> Integer.parseInt(item.getLayer()))
|
|
|
+ .thenComparingInt(item -> Integer.parseInt(item.getAddress())))
|
|
|
+ .orElseGet(() -> {
|
|
|
+ // 如果没有找到已占用的位置,创建并返回第一层第一个位置的对象
|
|
|
+ StackingAndLoadingVehicles defaultPosition = new StackingAndLoadingVehicles();
|
|
|
+ defaultPosition.setLayer("1");
|
|
|
+ defaultPosition.setAddress("1");
|
|
|
+ // 设置其他必要的属性
|
|
|
+ if (!stackingAndLoadingVehiclesList.isEmpty()) {
|
|
|
+ StackingAndLoadingVehicles firstItem = stackingAndLoadingVehiclesList.get(0);
|
|
|
+ defaultPosition.setCcmNo(firstItem.getCcmNo());
|
|
|
+ defaultPosition.setTypeConfigId(firstItem.getTypeConfigId());
|
|
|
+ defaultPosition.setStackAddr(firstItem.getStackAddr());
|
|
|
+ }
|
|
|
+ return defaultPosition;
|
|
|
+ }))
|
|
|
+ .orElse(null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算下一组可用的堆垛位置
|
|
|
+ * @param highAddressSALV 当前最高占用位置的对象
|
|
|
+ * @param demandStackingSum 需要计算的位置数量
|
|
|
+ * @return 包含可用位置的对象列表
|
|
|
+ */
|
|
|
+ private List<StackingAndLoadingVehicles> calculateNextPositions(StackingAndLoadingVehicles highAddressSALV, int demandStackingSum, String ccmNo, String heatNo) {
|
|
|
+
|
|
|
+ List<StackingAndLoadingVehicles> resultPositions = new ArrayList<>();
|
|
|
+
|
|
|
+ // 获取当前最高占用位置的坐标
|
|
|
+ int currentLayer = Integer.parseInt(highAddressSALV.getLayer());
|
|
|
+ int currentAddress = Integer.parseInt(highAddressSALV.getAddress());
|
|
|
+
|
|
|
+ // 循环计算需要的位置数量
|
|
|
+ for (int i = 0; i < demandStackingSum; i++) {
|
|
|
+ // 计算下一个位置
|
|
|
+ currentAddress++;
|
|
|
+ // 如果当前位置超过每层的最大位置(9),则移动到下一层
|
|
|
+ if (currentAddress > 9) {
|
|
|
+ currentAddress = 1;
|
|
|
+ currentLayer ++;
|
|
|
+ // 检查是否超过最大层数限制
|
|
|
+ if (currentLayer > 20) {
|
|
|
+ log.warn("已达到最大层数限制(20层),无法继续分配位置");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新的位置对象
|
|
|
+ StackingAndLoadingVehicles newPosition = new StackingAndLoadingVehicles();
|
|
|
+ newPosition.setLayer(String.valueOf(currentLayer));
|
|
|
+ newPosition.setAddress(String.valueOf(currentAddress));
|
|
|
+ newPosition.setCcmNo(highAddressSALV.getCcmNo());
|
|
|
+ newPosition.setTypeConfigId(highAddressSALV.getTypeConfigId());
|
|
|
+ newPosition.setStackAddr(highAddressSALV.getStackAddr());
|
|
|
+ newPosition.setBilletNos(generateBilletNos(heatNo, ccmNo));
|
|
|
+ // 添加到结果列表
|
|
|
+ resultPositions.add(newPosition);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultPositions;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成短格式唯一坯号(炉号+铸机号+3位)
|
|
|
+ * @param heatNo 炉号
|
|
|
+ * @param ccmNo 连铸机号
|
|
|
+ * @return 逗号分隔的四个短格式坯号
|
|
|
+ */
|
|
|
+ private String generateBilletNos(String heatNo, String ccmNo) {
|
|
|
+ // 移除非数字字符并截取固定长度
|
|
|
+ String cleanHeatNo = heatNo.replaceAll("\\D", "").substring(0, Math.min(6, heatNo.length()));
|
|
|
+ String cleanCcmNo = ccmNo.replaceAll("\\D", "").substring(0, Math.min(2, ccmNo.length()));
|
|
|
+
|
|
|
+ // 补零处理:炉号固定6位,铸机号固定2位
|
|
|
+ cleanHeatNo = String.format("%6s", cleanHeatNo).replace(' ', '0').substring(0, 6);
|
|
|
+ cleanCcmNo = String.format("%2s", cleanCcmNo).replace(' ', '0').substring(0, 2);
|
|
|
+
|
|
|
+ // 生成全局唯一计数器(确保多线程安全)
|
|
|
+ long counter = System.nanoTime() % 1000; // 纳秒级时间戳,精度更高
|
|
|
+
|
|
|
+ // 生成四个不同的坯号
|
|
|
+ List<String> billetNosList = new ArrayList<>();
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ // 组合因子:炉号6位+铸机号2位+3位唯一码(000-999)
|
|
|
+ int uniqueCode = (int) ((counter + i) % 10000);
|
|
|
+ String billetNo = cleanHeatNo + cleanCcmNo + String.format("%04d", uniqueCode);
|
|
|
+ billetNosList.add(billetNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ return String.join(",", billetNosList);
|
|
|
+ }
|
|
|
+
|
|
|
}
|