lingpeng.li hai 2 semanas
pai
achega
8896e60c40

+ 2182 - 2181
zgztBus/jeecg-module-sbm/src/main/java/org/jeecg/modules/billet/billetOriginalProductRecord/controller/BilletOriginalProductRecordController.java

@@ -11,7 +11,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -37,7 +37,6 @@ import org.jeecg.modules.billet.billetHotsend.entity.BilletHotsend;
 import org.jeecg.modules.billet.billetHotsend.service.IBilletHotsendBaseService;
 import org.jeecg.modules.billet.billetHotsendChangeShift.entity.BilletHotsendChangeShift;
 import org.jeecg.modules.billet.billetHotsendChangeShift.service.IBilletHotsendChangeShiftService;
-import org.jeecg.modules.billet.billetOriginalProductRecord.dto.BilletOriginalProductRecordEditDTO;
 import org.jeecg.modules.billet.billetOriginalProductRecord.dto.LengthCountQueryDTO;
 import org.jeecg.modules.billet.billetOriginalProductRecord.dto.QualityInspectionQueryDTO;
 import org.jeecg.modules.billet.billetOriginalProductRecord.entity.BilletOriginalProductRecord;
@@ -58,7 +57,7 @@ import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.ModelAndView;
 
- /**
+/**
  * @Description: 钢坯生成原始记录
  * @Author: jeecg-boot
  * @Date:   2025-06-23
@@ -79,28 +78,28 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 	@Autowired
 	private IBilletHotsendChangeShiftService billetHotsendChangeShiftService;
 
-	 @Autowired
-	 private IBilletHotsendBaseService billetHotsendBaseService;
+	@Autowired
+	private IBilletHotsendBaseService billetHotsendBaseService;
 
-	 @Autowired
-	 private IBilletBasicInfoService billetBasicInfoService;
+	@Autowired
+	private IBilletBasicInfoService billetBasicInfoService;
 
-	 @Autowired
-	 private IStorageBillPrintService storageBillPrintService;
+	@Autowired
+	private IStorageBillPrintService storageBillPrintService;
 
-	 @Autowired
-	 private ISysDictService sysDictService;
+	@Autowired
+	private ISysDictService sysDictService;
 
-	 @Autowired
-	 private StackingAndLoadingVehiclesMapper stackingAndLoadingVehiclesMapper;
+	@Autowired
+	private StackingAndLoadingVehiclesMapper stackingAndLoadingVehiclesMapper;
 
-	 @Autowired
-	 private IStorageBillService storageBillService;
+	@Autowired
+	private IStorageBillService storageBillService;
 
-	 @Autowired
-	 private IShiftConfigurationService shiftConfigurationService;
-	 
-	 /**
+	@Autowired
+	private IShiftConfigurationService shiftConfigurationService;
+
+	/**
 	 * 分页列表查询
 	 *
 	 * @param billetOriginalProductRecord
@@ -113,15 +112,15 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 	@ApiOperation(value="钢坯生成原始记录-分页列表查询", notes="钢坯生成原始记录-分页列表查询")
 	@GetMapping(value = "/list")
 	public Result<IPage<BilletOriginalProductRecord>> queryPageList(BilletOriginalProductRecord billetOriginalProductRecord,
-								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
-								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
-								   HttpServletRequest req) {
+																	@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+																	@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+																	HttpServletRequest req) {
 		QueryWrapper<BilletOriginalProductRecord> queryWrapper = QueryGenerator.initQueryWrapper(billetOriginalProductRecord, req.getParameterMap());
 		Page<BilletOriginalProductRecord> page = new Page<BilletOriginalProductRecord>(pageNo, pageSize);
 		IPage<BilletOriginalProductRecord> pageList = billetOriginalProductRecordService.page(page, queryWrapper);
 		return Result.OK(pageList);
 	}
-	
+
 	/**
 	 *   添加
 	 *
@@ -189,7 +188,7 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 		billetOriginalProductRecordService.save(billetOriginalProductRecord);
 		return Result.OK("添加成功!");
 	}
-	
+
 	/**
 	 *  编辑
 	 *
@@ -239,277 +238,319 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 		return Result.OK("编辑成功!");
 	}
 
-	 /**
-	  * 处理编辑操作中的公共逻辑
-	  */
-	 private void processCommonEditLogic(BilletOriginalProductRecord bopr, BilletOriginalProductRecord newRecord, boolean hotChargeLengthUpdated) {
-		 // 复制所有非空字段(忽略ID和流支数字段)
-		 String[] ignoreProperties = {"id", "oneStrandSum", "twoStrandSum", "threeStrandSum",
-				 "fourStrandSum", "fiveStrandSum", "sixStrandSum",
-				 "sevenStrandSum", "eightStrandSum", "amount"};
-		 BeanUtils.copyProperties(newRecord, bopr, ignoreProperties);
-
-		 // 如果更新了hotChargeLength,设置is_edit_charge为2
-		 if (hotChargeLengthUpdated) {
-			 bopr.setIsEditCharge("2");
-		 }
-
-		 // 判断stackInfo字段是否为非空,不为空代表需要起垛
-		 if (oConvertUtils.isNotEmpty(bopr.getStackInfo())) {
-			 String str = bopr.getStackInfo();
-			 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);
-			 // 备注stackInfo字段重置
-			 bopr.setStackInfo("");
-		 }
-		 // 保存修改
-		 billetOriginalProductRecordService.updateById(bopr);
-	 }
-
-	 /***
-	  * 处理起垛
-	  * @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;
-		 if (demandStackingSum <= 0) {
-			 log.info("起垛数量计算结果为非正数,起垛失败!heatNo={}, stackingSum={}", heatNo, stackingSum);
-			 return;
-		 }
-
-		 // 查询所有可能的位置,并按layer和address排序(低layer优先,address从1到9)
-		 List<StackingAndLoadingVehicles> allPositions = stackingAndLoadingVehiclesMapper.selectList(
-				 new QueryWrapper<StackingAndLoadingVehicles>()
-						 .eq("ccm_no", ccmNo)
-						 .eq("type_config_id", typeConfigId));
-
-		 if (allPositions != null) {
-			 allPositions.sort(Comparator.comparing(StackingAndLoadingVehicles::getLayer,
-							 Comparator.comparingInt(Integer::parseInt))
-					 .thenComparing(StackingAndLoadingVehicles::getAddress,
-							 Comparator.comparingInt(Integer::parseInt)));
-		 }
-
-		 // 获取所有可用的空位置(按排序后的顺序)
-		 List<StackingAndLoadingVehicles> availablePositions = allPositions.stream()
-				 .filter(v -> oConvertUtils.isEmpty(v.getBilletNos()))
-				 .collect(Collectors.toList());
-
-		 // 如果没有可用的空位置,则尝试计算新位置
-		 if (availablePositions.isEmpty()) {
-			 // 获取最高占用层
-			 StackingAndLoadingVehicles highAddressSALV = getHighestOccupiedLayer(allPositions);
-
-			 // 如果没有任何占用层,从1.1开始
-			 if (highAddressSALV == null) {
-				 highAddressSALV = new StackingAndLoadingVehicles();
-				 highAddressSALV.setAddress("1");
-				 highAddressSALV.setLayer("1");
-				 highAddressSALV.setCcmNo(ccmNo);
-				 highAddressSALV.setTypeConfigId(typeConfigId);
-			 } else {
-				 log.info("最高占用层位置:{}.{}", highAddressSALV.getLayer(), highAddressSALV.getAddress());
-			 }
-
-			 // 计算新的位置(按address优先、layer其次的顺序)
-			 availablePositions = calculateNextPositions(highAddressSALV, demandStackingSum, ccmNo, typeConfigId);
-
-			 // 验证生成的位置顺序
-			 if (!availablePositions.isEmpty()) {
-				 StringBuilder positionLog = new StringBuilder("生成的新位置顺序:");
-				 availablePositions.forEach(p ->
-						 positionLog.append(p.getLayer()).append(".").append(p.getAddress()).append(" → "));
-				 log.info(positionLog.substring(0, positionLog.length() - 4)); // 移除最后的" → "
-			 }
-			 if (availablePositions.isEmpty()) {
-				 log.info("无法计算出可用位置,起垛失败!heatNo={}", heatNo);
-				 return;
-			 }
-		 }
-
-		 // 处理每个位置
-		 int positionsToProcess = Math.min(demandStackingSum, availablePositions.size());
-		 log.info("需要处理{}个位置,实际可用{}个位置", demandStackingSum, positionsToProcess);
-
-		 for (int i = 0; i < positionsToProcess; i++) {
-			 StackingAndLoadingVehicles position = availablePositions.get(i);
-
-			 // 如果是计算出来的新位置,需要查询数据库获取完整信息
-			 if (position.getId() == null) {
-				 StackingAndLoadingVehicles dbPosition = stackingAndLoadingVehiclesMapper.selectOne(
-						 new QueryWrapper<StackingAndLoadingVehicles>()
-								 .eq("ccm_no", position.getCcmNo())
-								 .eq("address", position.getAddress())
-								 .eq("layer", position.getLayer())
-								 .eq("type_config_id", position.getTypeConfigId()));
-
-				 if (dbPosition == null) {
-					 // 如果数据库中不存在该位置,可能需要创建新记录
-					 log.info("创建新的堆垛容器位置:layer={}, address={}", position.getLayer(), position.getAddress());
-					 position.setCreateTime(new Date());
-					 position.setUpdateTime(new Date());
-					 stackingAndLoadingVehiclesMapper.insert(position);
-				 } else {
-					 position.setId(dbPosition.getId());
-					 position.setCreateTime(dbPosition.getCreateTime());
-				 }
-			 }
-
-			 // 设置位置属性
-			 position.setSize(size);
-			 position.setShift(shift);
-			 position.setShiftGroup(shiftGroup);
-			 position.setHeatNo(heatNo);
-			 position.setUpdateTime(new Date());
-			 position.setSteel("");
-			 position.setSpec("");
-			 position.setBilletNos(generateBilletNos(heatNo, ccmNo)); // 生成带序号的钢坯编号
-
-			 try {
-				 // 更新位置信息
-				 stackingAndLoadingVehiclesMapper.updateById(position);
-				 log.info("成功更新堆垛容器位置:layer={}, address={}, id={}",
-						 position.getLayer(), position.getAddress(), position.getId());
-			 } catch (Exception e) {
-				 log.error("更新堆垛容器位置失败:layer={}, address={}",
-						 position.getLayer(), position.getAddress(), e);
-			 }
-		 }
-	 }
-	 /**
-	  *  编辑
-	  *
-	  * @param billetOriginalProductRecord
-	  * @return
-	  */
-	 @AutoLog(value = "确认钢坯生成原始记录")
-	 @ApiOperation(value="确认钢坯生成原始记录", notes="确认钢坯生成原始记录")
-	 @RequestMapping(value = "/confirmRecord", method = {RequestMethod.PUT})
-	 public Result<String> confirmRecord(@RequestBody BilletOriginalProductRecord billetOriginalProductRecord) {
-		 BilletOriginalProductRecord bopr = billetOriginalProductRecordService.getById(billetOriginalProductRecord.getId());
-		 if(bopr == null) {
-			 return Result.error("未找到对应数据,编辑失败!");
-		 }
-		 LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-		 applyConfirmInfo(billetOriginalProductRecord, sysUser);
-		 billetOriginalProductRecordService.updateById(billetOriginalProductRecord);
-
-		 return Result.OK("确认成功!");
-	 }
-
-	 /**
-	  *  推钢室快速创建装运单
-	  *
-	  * @param
-	  * @return
-	  */
-	 @AutoLog(value = "推钢室快速创建装运单")
-	 @ApiOperation(value="推钢室快速创建装运单", notes="推钢室快速创建装运单")
-	 @RequestMapping(value = "/addStorageBill", method = {RequestMethod.PUT})
-	 public Result<String> addStorageBillHandle(@RequestParam(name="ccmNo",required = false) String ccmNo,
-												@RequestParam(name="positionNum",required = true) Integer positionNum,
-												@RequestParam(name="licensePlate",required = true) String licensePlate) {
-		 // 参数验证
-		 if (positionNum == 2 && StringUtils.isEmpty(ccmNo)) {
-			 return Result.error("车位2铸机号不能为空!");
-		 }
-
-		 StorageBill storageBill = new StorageBill();
-		 storageBill.setId(String.valueOf(IdWorker.getId()));
-		 // 确定最终的ccmNo
-		 String finalCcmNo;
-		 if (positionNum == 1) {
-			 finalCcmNo = "5";
-		 } else if (positionNum == 2) {
-			 finalCcmNo = ccmNo;
-		 } else if (positionNum == 3 || positionNum == 4) {
-			 finalCcmNo = "6";
-		 } else {
-			 return Result.error("无效的车位号!");
-		 }
-		 storageBill.setCcmNo(finalCcmNo);
-		 // 从 Redis 获取班次信息
-		 String shiftGroup = getShiftInfo(storageBill.getCcmNo(), "class:shift:group:%s");
-		 String shift = getShiftInfo(storageBill.getCcmNo(), "class:shift:%s");
-		 // 空值检查
-		 if (shiftGroup == null || shift == null) {
-			 return Result.error("班组、班别不存在,创建失败!");
-		 }
-		 // 判断车牌号是否存在未发车的装运单信息
-		 LambdaQueryWrapper<StorageBill> queryWrapper = new LambdaQueryWrapper<>();
-		 queryWrapper.eq(StorageBill::getLicensePlate, licensePlate)
-				 .eq(StorageBill::getShiftGroup, shiftGroup)
-				 .eq(StorageBill::getShift, shift)
-				 .isNull(StorageBill::getOutTime);
-		 StorageBill isStorageBill = storageBillService.getOne(queryWrapper);
-		 if (oConvertUtils.isNotEmpty(isStorageBill)) {
-			 log.info("推钢室查询到存在未发车车辆,车牌号为:{},新增钢坯装运单失败!", storageBill.getLicensePlate());
-			 return Result.error("该车存在未发车信息,创建失败!");
-		 }
-		 // 判断车位是否存在未发车车辆(2025/3.3,半自动化逻辑,等自动化发车车位发车完善后,在添加此段逻辑)
-		 List<StorageBill> storageBillList = storageBillService.list(new LambdaQueryWrapper<StorageBill>()
-				 .eq(StorageBill::getPositionNum, positionNum)
-				 .isNull(StorageBill::getOutTime));
-		 if (oConvertUtils.listIsNotEmpty(storageBillList)){
-			 log.info("{}{}", "推钢室该车位存在未发车信息,新增钢坯装运单失败!", JSON.toJSON(storageBillList));
-			 return Result.error("该车位存在未发车信息,创建失败!");
-		 }
-
-		 // 根据铸机号、班组、班别,创建时间倒序 只返回一条,查询储运配置信息
-		 LambdaQueryWrapper<ShiftConfiguration> queryWrapper1 = new LambdaQueryWrapper<>();
-		 queryWrapper1.eq(ShiftConfiguration::getCcmNo, storageBill.getCcmNo())
-				 .eq(ShiftConfiguration::getShiftGroup, shiftGroup)
-				 .eq(ShiftConfiguration::getShift, shift)
-				 .orderByDesc(ShiftConfiguration::getCreateTime)
-				 .last("limit 1");
-		 ShiftConfiguration shiftConfiguration = shiftConfigurationService.getOne(queryWrapper1);
-		 if (shiftConfiguration != null && oConvertUtils.isNotEmpty(shiftConfiguration.getDestination())){
-			 storageBill.setBrandNum(shiftConfiguration.getSteelGrade());//牌号
-			 storageBill.setNewOldPlatform(shiftConfiguration.getNewOldPlatform());
-			 storageBill.setTypeConfigId("1024");
-		 }else {
-			 // C端自动化创建装运单时,默认未知目的地
-			 storageBill.setTypeConfigId("1024");
-		 }
-
-		 storageBill.setArrivalTime(new Date());// 到达时间
-		 // 更新交班记录 通过铸机号、班组、班别去查询交班记录并初始化 出车号
-		 updateBilletHotsendChangeShift(storageBill.getCcmNo(), shiftGroup, shift);
-		 storageBill.setPositionNum(positionNum);
-		 storageBill.setLicensePlate(licensePlate);
-		 storageBill.setAmountTotal(0);
-		 storageBill.setPanelAmountTotal(0);
-		 storageBill.setShiftGroup(shiftGroup);
-		 storageBill.setShift(shift);
-		 String uniqueCode = generateUniqueCode(new Date(), storageBill.getCcmNo(), shift, shiftGroup);
-		 storageBill.setUniqueCode(uniqueCode);
-		 storageBill.setLicensePlateStatus(0);
-		 storageBill.setCarNum(0); // 本车车次
-		 storageBill.setCarAllNum(0); // 总车车次
-		 storageBill.setBtype("0");
-		 storageBillService.save(storageBill);
-
-		 return Result.OK("创建成功!");
-	 }
-	
+	/**
+	 * 处理编辑操作中的公共逻辑
+	 */
+	private void processCommonEditLogic(BilletOriginalProductRecord bopr, BilletOriginalProductRecord newRecord, boolean hotChargeLengthUpdated) {
+		// 复制所有非空字段(忽略ID和流支数字段)
+		String[] ignoreProperties = {"id", "oneStrandSum", "twoStrandSum", "threeStrandSum",
+				"fourStrandSum", "fiveStrandSum", "sixStrandSum",
+				"sevenStrandSum", "eightStrandSum", "amount"};
+		BeanUtils.copyProperties(newRecord, bopr, ignoreProperties);
+
+		// 如果更新了hotChargeLength,设置is_edit_charge为2
+		if (hotChargeLengthUpdated) {
+			bopr.setIsEditCharge("2");
+		}
+
+		// 判断stackInfo字段是否为非空,不为空代表需要起垛
+		if (oConvertUtils.isNotEmpty(bopr.getStackInfo())) {
+			String str = bopr.getStackInfo();
+			String[] parts = str.split("-");
+			// 起垛的数量
+			int stackingSum = Integer.parseInt(parts[0]);
+			// 定尺
+			String size = parts[1];
+			String typeConfigId = parts[2];
+			// 根据炉号清空已起垛数据
+			clearStackByHeatNo(bopr.getCcmNo(), bopr.getHeatNo(), size, typeConfigId);
+			// 根据炉号、数量进行起垛
+			handleAddStack(bopr.getCcmNo(), bopr.getHeatNo(), stackingSum, size, typeConfigId);
+			// 备注stackInfo字段重置
+			bopr.setStackInfo("");
+		}
+		// 保存修改
+		billetOriginalProductRecordService.updateById(bopr);
+	}
+
+	/**
+	 * 清空指定炉已经起垛的 数据
+	 * @param ccmNo
+	 * @param heatNo
+	 * @param typeConfigId
+	 */
+	private void clearStackByHeatNo(String ccmNo, String heatNo, String size, String typeConfigId) {
+		if (oConvertUtils.isEmpty(ccmNo) || oConvertUtils.isEmpty(heatNo) || oConvertUtils.isEmpty(typeConfigId) || oConvertUtils.isEmpty(size)){
+			log.info("{}{}", "清空指定炉已经起垛的数据时参数为空:", ccmNo + ">|<" + heatNo + ">|<" + size + ">|<" + typeConfigId);
+			return;
+		}
+		// 根据ccmNo、heatNo、typeConfigId查询出已经起垛的记录
+		LambdaQueryWrapper<StackingAndLoadingVehicles> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(StackingAndLoadingVehicles::getCcmNo, ccmNo)
+				.eq(StackingAndLoadingVehicles::getHeatNo, heatNo)
+				.eq(StackingAndLoadingVehicles::getSize, size)
+				.eq(StackingAndLoadingVehicles::getTypeConfigId, typeConfigId);
+		List<StackingAndLoadingVehicles> stackingAndLoadingVehiclesList = stackingAndLoadingVehiclesMapper.selectList(queryWrapper);
+		if (oConvertUtils.listIsEmpty(stackingAndLoadingVehiclesList)){
+			log.info("{}{}", "该炉没有需要清空的堆垛信息:", heatNo);
+			return;
+		}
+		List<String> ids = stackingAndLoadingVehiclesList.stream().map(StackingAndLoadingVehicles::getId).collect(Collectors.toList());
+		// 创建更新包装器
+		LambdaUpdateWrapper<StackingAndLoadingVehicles> updateWrapper = new LambdaUpdateWrapper<>();
+		updateWrapper.in(StackingAndLoadingVehicles::getId, ids)
+				.set(StackingAndLoadingVehicles::getBilletNos, null)
+				.set(StackingAndLoadingVehicles::getSpec, null)
+				.set(StackingAndLoadingVehicles::getSteel, null)
+				.set(StackingAndLoadingVehicles::getSize, null)
+				.set(StackingAndLoadingVehicles::getShift, null)
+				.set(StackingAndLoadingVehicles::getHeatNo, null)
+				.set(StackingAndLoadingVehicles::getCreateDate, null)
+				.set(StackingAndLoadingVehicles::getShiftGroup, null)
+				.set(StackingAndLoadingVehicles::getUpdateTime, new Date());
+		// 执行批量更新
+		stackingAndLoadingVehiclesMapper.update(null, updateWrapper);
+	}
+
+	/***
+	 * 处理起垛
+	 * @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;
+		if (demandStackingSum <= 0) {
+			log.info("起垛数量计算结果为非正数,起垛失败!heatNo={}, stackingSum={}", heatNo, stackingSum);
+			return;
+		}
+
+		// 查询所有可能的位置,并按layer和address排序(低layer优先,address从1到9)
+		List<StackingAndLoadingVehicles> allPositions = stackingAndLoadingVehiclesMapper.selectList(
+				new QueryWrapper<StackingAndLoadingVehicles>()
+						.eq("ccm_no", ccmNo)
+						.eq("type_config_id", typeConfigId));
+
+		if (allPositions != null) {
+			allPositions.sort(Comparator.comparing(StackingAndLoadingVehicles::getLayer,
+							Comparator.comparingInt(Integer::parseInt))
+					.thenComparing(StackingAndLoadingVehicles::getAddress,
+							Comparator.comparingInt(Integer::parseInt)));
+		}
+
+		// 获取所有可用的空位置(按排序后的顺序)
+		List<StackingAndLoadingVehicles> availablePositions = allPositions.stream()
+				.filter(v -> oConvertUtils.isEmpty(v.getBilletNos()))
+				.collect(Collectors.toList());
+
+		// 如果没有可用的空位置,则尝试计算新位置
+		if (availablePositions.isEmpty()) {
+			// 获取最高占用层
+			StackingAndLoadingVehicles highAddressSALV = getHighestOccupiedLayer(allPositions);
+
+			// 如果没有任何占用层,从1.1开始
+			if (highAddressSALV == null) {
+				highAddressSALV = new StackingAndLoadingVehicles();
+				highAddressSALV.setAddress("1");
+				highAddressSALV.setLayer("1");
+				highAddressSALV.setCcmNo(ccmNo);
+				highAddressSALV.setTypeConfigId(typeConfigId);
+			} else {
+				log.info("最高占用层位置:{}.{}", highAddressSALV.getLayer(), highAddressSALV.getAddress());
+			}
+
+			// 计算新的位置(按address优先、layer其次的顺序)
+			availablePositions = calculateNextPositions(highAddressSALV, demandStackingSum, ccmNo, typeConfigId);
+
+			// 验证生成的位置顺序
+			if (!availablePositions.isEmpty()) {
+				StringBuilder positionLog = new StringBuilder("生成的新位置顺序:");
+				availablePositions.forEach(p ->
+						positionLog.append(p.getLayer()).append(".").append(p.getAddress()).append(" → "));
+				log.info(positionLog.substring(0, positionLog.length() - 4)); // 移除最后的" → "
+			}
+			if (availablePositions.isEmpty()) {
+				log.info("无法计算出可用位置,起垛失败!heatNo={}", heatNo);
+				return;
+			}
+		}
+
+		// 处理每个位置
+		int positionsToProcess = Math.min(demandStackingSum, availablePositions.size());
+		log.info("需要处理{}个位置,实际可用{}个位置", demandStackingSum, positionsToProcess);
+
+		for (int i = 0; i < positionsToProcess; i++) {
+			StackingAndLoadingVehicles position = availablePositions.get(i);
+
+			// 如果是计算出来的新位置,需要查询数据库获取完整信息
+			if (position.getId() == null) {
+				StackingAndLoadingVehicles dbPosition = stackingAndLoadingVehiclesMapper.selectOne(
+						new QueryWrapper<StackingAndLoadingVehicles>()
+								.eq("ccm_no", position.getCcmNo())
+								.eq("address", position.getAddress())
+								.eq("layer", position.getLayer())
+								.eq("type_config_id", position.getTypeConfigId()));
+
+				if (dbPosition == null) {
+					// 如果数据库中不存在该位置,可能需要创建新记录
+					log.info("创建新的堆垛容器位置:layer={}, address={}", position.getLayer(), position.getAddress());
+					position.setCreateTime(new Date());
+					position.setUpdateTime(new Date());
+					stackingAndLoadingVehiclesMapper.insert(position);
+				} else {
+					position.setId(dbPosition.getId());
+					position.setCreateTime(dbPosition.getCreateTime());
+				}
+			}
+
+			// 设置位置属性
+			position.setSize(size);
+			position.setShift(shift);
+			position.setShiftGroup(shiftGroup);
+			position.setHeatNo(heatNo);
+			position.setUpdateTime(new Date());
+			position.setSteel("");
+			position.setSpec("");
+			position.setBilletNos(generateBilletNos(heatNo, ccmNo)); // 生成带序号的钢坯编号
+
+			try {
+				// 更新位置信息
+				stackingAndLoadingVehiclesMapper.updateById(position);
+				log.info("成功更新堆垛容器位置:layer={}, address={}, id={}",
+						position.getLayer(), position.getAddress(), position.getId());
+			} catch (Exception e) {
+				log.error("更新堆垛容器位置失败:layer={}, address={}",
+						position.getLayer(), position.getAddress(), e);
+			}
+		}
+	}
+	/**
+	 *  编辑
+	 *
+	 * @param billetOriginalProductRecord
+	 * @return
+	 */
+	@AutoLog(value = "确认钢坯生成原始记录")
+	@ApiOperation(value="确认钢坯生成原始记录", notes="确认钢坯生成原始记录")
+	@RequestMapping(value = "/confirmRecord", method = {RequestMethod.PUT})
+	public Result<String> confirmRecord(@RequestBody BilletOriginalProductRecord billetOriginalProductRecord) {
+		BilletOriginalProductRecord bopr = billetOriginalProductRecordService.getById(billetOriginalProductRecord.getId());
+		if(bopr == null) {
+			return Result.error("未找到对应数据,编辑失败!");
+		}
+		LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		applyConfirmInfo(billetOriginalProductRecord, sysUser);
+		billetOriginalProductRecordService.updateById(billetOriginalProductRecord);
+
+		return Result.OK("确认成功!");
+	}
+
+	/**
+	 *  推钢室快速创建装运单
+	 *
+	 * @param
+	 * @return
+	 */
+	@AutoLog(value = "推钢室快速创建装运单")
+	@ApiOperation(value="推钢室快速创建装运单", notes="推钢室快速创建装运单")
+	@RequestMapping(value = "/addStorageBill", method = {RequestMethod.PUT})
+	public Result<String> addStorageBillHandle(@RequestParam(name="ccmNo",required = false) String ccmNo,
+											   @RequestParam(name="positionNum",required = true) Integer positionNum,
+											   @RequestParam(name="licensePlate",required = true) String licensePlate) {
+		// 参数验证
+		if (positionNum == 2 && StringUtils.isEmpty(ccmNo)) {
+			return Result.error("车位2铸机号不能为空!");
+		}
+
+		StorageBill storageBill = new StorageBill();
+		storageBill.setId(String.valueOf(IdWorker.getId()));
+		// 确定最终的ccmNo
+		String finalCcmNo;
+		if (positionNum == 1) {
+			finalCcmNo = "5";
+		} else if (positionNum == 2) {
+			finalCcmNo = ccmNo;
+		} else if (positionNum == 3 || positionNum == 4) {
+			finalCcmNo = "6";
+		} else {
+			return Result.error("无效的车位号!");
+		}
+		storageBill.setCcmNo(finalCcmNo);
+		// 从 Redis 获取班次信息
+		String shiftGroup = getShiftInfo(storageBill.getCcmNo(), "class:shift:group:%s");
+		String shift = getShiftInfo(storageBill.getCcmNo(), "class:shift:%s");
+		// 空值检查
+		if (shiftGroup == null || shift == null) {
+			return Result.error("班组、班别不存在,创建失败!");
+		}
+		// 判断车牌号是否存在未发车的装运单信息
+		LambdaQueryWrapper<StorageBill> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(StorageBill::getLicensePlate, licensePlate)
+				.eq(StorageBill::getShiftGroup, shiftGroup)
+				.eq(StorageBill::getShift, shift)
+				.isNull(StorageBill::getOutTime);
+		StorageBill isStorageBill = storageBillService.getOne(queryWrapper);
+		if (oConvertUtils.isNotEmpty(isStorageBill)) {
+			log.info("推钢室查询到存在未发车车辆,车牌号为:{},新增钢坯装运单失败!", storageBill.getLicensePlate());
+			return Result.error("该车存在未发车信息,创建失败!");
+		}
+		// 判断车位是否存在未发车车辆(2025/3.3,半自动化逻辑,等自动化发车车位发车完善后,在添加此段逻辑)
+		List<StorageBill> storageBillList = storageBillService.list(new LambdaQueryWrapper<StorageBill>()
+				.eq(StorageBill::getPositionNum, positionNum)
+				.isNull(StorageBill::getOutTime));
+		if (oConvertUtils.listIsNotEmpty(storageBillList)){
+			log.info("{}{}", "推钢室该车位存在未发车信息,新增钢坯装运单失败!", JSON.toJSON(storageBillList));
+			return Result.error("该车位存在未发车信息,创建失败!");
+		}
+
+		// 根据铸机号、班组、班别,创建时间倒序 只返回一条,查询储运配置信息
+		LambdaQueryWrapper<ShiftConfiguration> queryWrapper1 = new LambdaQueryWrapper<>();
+		queryWrapper1.eq(ShiftConfiguration::getCcmNo, storageBill.getCcmNo())
+				.eq(ShiftConfiguration::getShiftGroup, shiftGroup)
+				.eq(ShiftConfiguration::getShift, shift)
+				.orderByDesc(ShiftConfiguration::getCreateTime)
+				.last("limit 1");
+		ShiftConfiguration shiftConfiguration = shiftConfigurationService.getOne(queryWrapper1);
+		if (shiftConfiguration != null && oConvertUtils.isNotEmpty(shiftConfiguration.getDestination())){
+			storageBill.setBrandNum(shiftConfiguration.getSteelGrade());//牌号
+			storageBill.setNewOldPlatform(shiftConfiguration.getNewOldPlatform());
+			storageBill.setTypeConfigId("1024");
+		}else {
+			// C端自动化创建装运单时,默认未知目的地
+			storageBill.setTypeConfigId("1024");
+		}
+
+		storageBill.setArrivalTime(new Date());// 到达时间
+		// 更新交班记录 通过铸机号、班组、班别去查询交班记录并初始化 出车号
+		updateBilletHotsendChangeShift(storageBill.getCcmNo(), shiftGroup, shift);
+		storageBill.setPositionNum(positionNum);
+		storageBill.setLicensePlate(licensePlate);
+		storageBill.setAmountTotal(0);
+		storageBill.setPanelAmountTotal(0);
+		storageBill.setShiftGroup(shiftGroup);
+		storageBill.setShift(shift);
+		String uniqueCode = generateUniqueCode(new Date(), storageBill.getCcmNo(), shift, shiftGroup);
+		storageBill.setUniqueCode(uniqueCode);
+		storageBill.setLicensePlateStatus(0);
+		storageBill.setCarNum(0); // 本车车次
+		storageBill.setCarAllNum(0); // 总车车次
+		storageBill.setBtype("0");
+		storageBillService.save(storageBill);
+
+		return Result.OK("创建成功!");
+	}
+
 	/**
 	 *   通过id删除
 	 *
@@ -524,7 +565,7 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 		billetOriginalProductRecordService.removeById(id);
 		return Result.OK("删除成功!");
 	}
-	
+
 	/**
 	 *  批量删除
 	 *
@@ -539,7 +580,7 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 		this.billetOriginalProductRecordService.removeByIds(Arrays.asList(ids.split(",")));
 		return Result.OK("批量删除成功!");
 	}
-	
+
 	/**
 	 * 通过id查询
 	 *
@@ -557,1889 +598,1849 @@ public class BilletOriginalProductRecordController extends JeecgController<Bille
 		return Result.OK(billetOriginalProductRecord);
 	}
 
-    /**
-    * 导出excel
-    *
-    * @param request
-    * @param billetOriginalProductRecord
-    */
-    @RequiresPermissions("billetOriginalProductRecord:billet_original_product_record:exportXls")
-    @RequestMapping(value = "/exportXls")
-    public ModelAndView exportXls(HttpServletRequest request, BilletOriginalProductRecord billetOriginalProductRecord) {
-        return super.exportXls(request, billetOriginalProductRecord, BilletOriginalProductRecord.class, "钢坯生成原始记录");
-    }
-
-    /**
-      * 通过excel导入数据
-    *
-    * @param request
-    * @param response
-    * @return
-    */
-    @RequiresPermissions("billetOriginalProductRecord:billet_original_product_record:importExcel")
-    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
-    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
-        return super.importExcel(request, response, BilletOriginalProductRecord.class);
-    }
-
-
-	 @ApiOperation(value="钢坯原始生产记录查询", notes="钢坯原始生产记录查询")
-	 @GetMapping(value = "/queryBilletRecordByCcmNo")
-	 public Result<BilletOriginalProductRecordDetail> queryHeatsActualsByCcmNo(@RequestParam(name="ccmNo", required = false) String ccmNo,
-																			   @RequestParam(name="changeShiftId", required = false) String changeShiftId,
-																			   @RequestParam(name="queryType") String queryType) {
-		 List<BilletOriginalProductRecord> billetOriginalProductRecords = new ArrayList<>();
-		 BilletHotsendChangeShift billetHotsendChangeShift;
-		 if ("1".equals(queryType)){
-			 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)) : "";
-
-			 if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
-				 return Result.error("班组班别获取为空,钢坯原始生产记录查询失败!");
-			 }
-			 // 根据ccmNo、shift、shiftGroup查询最新的交班记录
-			 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-			 queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
-					 .eq(BilletHotsendChangeShift::getShift, shift)
-					 .eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
-					 .isNull(BilletHotsendChangeShift::getChangeShiftTime)
-					 .orderByDesc(BilletHotsendChangeShift::getCreateTime)
-					 .last("limit 1");
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-			 if (billetHotsendChangeShift == null){
-				 log.info("{}{}", "钢坯原始生产记录,交班记录为空!", ccmNo + "失败时间:" + new Date());
-				 return Result.error("交班信息为空,钢坯原始生产记录查询失败!");
-			 }
-		 }else {
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getById(changeShiftId);
-		 }
-		 if (billetHotsendChangeShift == null) {
-			 log.error("未查询到有效的交班记录,无法继续处理");
-			 return Result.error("未找到对应的交班信息,原始生产记录获取失败!");
-		 }
-		 //1、 获取当班浇筑炉次详细信息
-		 List<HeatsActualsInfo> heatsActualsInfoList = queryCurrentHeatsActualsInfo(ccmNo, billetHotsendChangeShift.getShift(), billetHotsendChangeShift.getShiftGroup(), billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime(), queryType);
-		 if (oConvertUtils.listIsNotEmpty(heatsActualsInfoList)){
-			 log.info("原始生产记录,当班浇筑炉次数据信息: " + JSON.toJSON(heatsActualsInfoList));
-			 //2、把获取到的当班浇筑炉次信息heatsActualsInfoList保存到原始生产记录表
-			 heatsActualsInfoList.forEach(x -> {
-				 BilletOriginalProductRecord billetOriginalProductRecord = new BilletOriginalProductRecord();
-				 billetOriginalProductRecord.setId(String.valueOf(IdWorker.getId()));
-				 billetOriginalProductRecord.setCcmNo(ccmNo);
-				 billetOriginalProductRecord.setHeatNo(x.getHeatNo());
-				 billetOriginalProductRecord.setShift(x.getShift());
-				 billetOriginalProductRecord.setShiftGroup(x.getShiftGroup());
-				 billetOriginalProductRecord.setGrade(x.getBrandNum());
-				 billetOriginalProductRecord.setOneStrandSum(x.getOneSum());
-				 billetOriginalProductRecord.setTwoStrandSum(x.getTwoSum());
-				 billetOriginalProductRecord.setThreeStrandSum(x.getThreeSum());
-				 billetOriginalProductRecord.setFourStrandSum(x.getFourSum());
-				 billetOriginalProductRecord.setFiveStrandSum(x.getFiveSum());
-				 billetOriginalProductRecord.setSixStrandSum(x.getSixSum());
-				 billetOriginalProductRecord.setSevenStrandSum(x.getSevenSum());
-				 billetOriginalProductRecord.setEightStrandSum(x.getEightSum());
-				 billetOriginalProductRecord.setBrandNum(x.getBrandNum());
-				 String totalInfoJson = x.getTotalInfo();
-				 if (oConvertUtils.isEmpty(totalInfoJson)){
-					 billetOriginalProductRecord.setAmount(0);// 合计
-				 }else {
-					 JSONObject json = JSON.parseObject(totalInfoJson);
-					 Integer totalCount = json.getInteger("totalCount");
-					 billetOriginalProductRecord.setAmount(totalCount);// 合计
-				 }
-				 billetOriginalProductRecord.setRollClubOneDetails(x.getDirectRolling());// 直轧热送棒一
-				 billetOriginalProductRecord.setHotChargeLength(x.getHotCharge());
-				 billetOriginalProductRecord.setStackLength(x.getStacking());
-				 billetOriginalProductRecord.setLengthDetails(x.getLength());
-				 billetOriginalProductRecord.setCreateTime(DateUtils.str2Date(x.getCreateTime(), DateUtils.datetimeFormat.get()));
-				 billetOriginalProductRecord.setDeliveryTime(DateUtils.str2Date(x.getCreateTime(), DateUtils.datetimeFormat.get()));
-				 billetOriginalProductRecord.setIsEditCharge("1");
-				 billetOriginalProductRecords.add(billetOriginalProductRecord);
-			 });
-			 log.info("钢坯原始生产记录信息: " + JSON.toJSON(billetOriginalProductRecords));
-
-			 // 在批量保存前,过滤掉已存在的炉号记录
-			 List<BilletOriginalProductRecord> finalRecords = billetOriginalProductRecords.stream()
-					 .filter(record -> {
-						 // 使用 getOne 方法检查是否存在相同记录(铸机号、炉号、班次、班组均相同)
-						 LambdaQueryWrapper<BilletOriginalProductRecord> checkWrapper = new LambdaQueryWrapper<>();
-						 checkWrapper.eq(BilletOriginalProductRecord::getCcmNo, record.getCcmNo())
-								 .eq(BilletOriginalProductRecord::getHeatNo, record.getHeatNo())
-								 .eq(BilletOriginalProductRecord::getShift, record.getShift())
-								 .eq(BilletOriginalProductRecord::getShiftGroup, record.getShiftGroup())
-								 .last("LIMIT 1"); // 只查询一条记录,提高性能
-						 // 如果 getOne 结果为 null,表示记录不存在,保留该记录
-						 return billetOriginalProductRecordService.getOne(checkWrapper, false) == null;
-					 }).collect(Collectors.toList());
-			 if(oConvertUtils.listIsNotEmpty(finalRecords)){
-				 try {
-					 // 批量保存
-					 billetOriginalProductRecordService.saveBatch(finalRecords);
-				 } catch (DuplicateKeyException e) {
-					 log.error("炉号重复插入:{}", JSON.toJSONString(billetOriginalProductRecords), e);
-				 }
-			 }
-		 }
-		 QueryWrapper<BilletOriginalProductRecord> queryWrapper3 = new QueryWrapper<>();
-		 queryWrapper3.eq("ccm_no", ccmNo)
-				 .eq("shift", billetHotsendChangeShift.getShift())
-				 .eq("shift_group", billetHotsendChangeShift.getShiftGroup());
-		 if ("1".equals(queryType)){
-			 queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), new Date());
-		 }else {
-			 queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime());
-		 }
-		 // 通过铸机号、班组、班别、交班开始时间 查询钢坯生产原始记录
-		 List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper3);
-		 BilletOriginalProductRecordDetail billetOriginalProductRecordDetails = new BilletOriginalProductRecordDetail();
-		 billetOriginalProductRecordDetails.setBilletOriginalProductRecordList(billetOriginalProductRecordList);
-		 billetOriginalProductRecordDetails.setSizeInfo(billetHotsendChangeShift.getSizeInfo());
-		 billetOriginalProductRecordDetails.setContent(billetHotsendChangeShift.getContent());
-		 billetOriginalProductRecordDetails.setConfirmStatus(billetHotsendChangeShift.getConfirmStatus());
-		 return Result.OK(billetOriginalProductRecordDetails);
-	 }
-
-
-	 @ApiOperation("送样卡获取定尺支数明细表")
-	 @GetMapping("/lengthDetailsTable")
-	 public Result<List<LengthCountVO>> getLengthDetailsTable(LengthCountQueryDTO queryDTO) {
-		 if (queryDTO == null || StringUtils.isBlank(queryDTO.getCcmNo())) {
-			 return Result.error("参数不能为空");
-		 }
-
-		 String shift = "";
-		 String shiftGroup = "";
-		 BilletHotsendChangeShift billetHotsendChangeShift;
-
-		 if (oConvertUtils.isEmpty(queryDTO.getChangeShiftId())) {
-			 String classShiftGroup = String.format("class:shift:group:%s", queryDTO.getCcmNo());
-			 String classShift = String.format("class:shift:%s", queryDTO.getCcmNo());
-			 shift = oConvertUtils.getString(redisTemplate.opsForValue().get(classShift), "");
-			 shiftGroup = oConvertUtils.getString(redisTemplate.opsForValue().get(classShiftGroup), "");
-
-			 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-			 queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, queryDTO.getCcmNo())
-					 .eq(BilletHotsendChangeShift::getShift, shift)
-					 .eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
-					 .orderByDesc(BilletHotsendChangeShift::getCreateTime)
-					 .last("limit 1");
-
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-			 if (billetHotsendChangeShift == null) {
-				 log.info("查询班次信息失败,交班记录为空!失败时间:{}", new Date());
-				 return Result.OK(Collections.emptyList());
-			 }
-		 } else {
-			 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-			 queryWrapper.eq(BilletHotsendChangeShift::getId, queryDTO.getChangeShiftId())
-					 .eq(BilletHotsendChangeShift::getCcmNo, queryDTO.getCcmNo());
-
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-			 if (billetHotsendChangeShift == null) {
-				 log.info("查询班次信息失败,交班记录为空!失败时间:{}", new Date());
-				 return Result.OK(Collections.emptyList());
-			 }
-		 }
-
-		 Date startTime = billetHotsendChangeShift.getCreateTime();
-		 Date endTime = billetHotsendChangeShift.getChangeShiftTime() != null
-				 ? billetHotsendChangeShift.getChangeShiftTime()
-				 : new Date();
-
-		 QueryWrapper<BilletOriginalProductRecord> queryWrapperB = new QueryWrapper<>();
-		 queryWrapperB.eq("ccm_no", queryDTO.getCcmNo())
-				 .eq("shift", billetHotsendChangeShift.getShift())
-				 .eq("shift_group", billetHotsendChangeShift.getShiftGroup())
-				 .ge("create_time", startTime)
-				 .le("create_time", endTime)
-				 .orderByAsc("create_time");
-
-		 List<BilletOriginalProductRecord> records = billetOriginalProductRecordService.list(queryWrapperB);
-
-		 List<LengthCountVO> resultList = new ArrayList<>();
-		 Set<String> allLengths = new TreeSet<>();
-		 ObjectMapper objectMapper = new ObjectMapper();
-
-		 for (BilletOriginalProductRecord record : records) {
-			 LengthCountVO vo = new LengthCountVO();
-			 vo.setHeatNo(record.getHeatNo());
-
-			 String brandNum = Optional.ofNullable(record.getGrade())
-					 .map(bn -> sysDictService.queryDictTextByKey("billet_spec", bn))
-					 .orElseGet(() -> sysDictService.queryDictTextByKey("billet_spec", "5"));
-			 vo.setBrandNum(brandNum);
-
-			 Map<String, Integer> mergedLengthCount = new HashMap<>();
-
-			 // 解析 rollClubOneDetails 的 lengthGroupCount
-			 String rollClubOneDetailsJson = record.getRollClubOneDetails();
-			 if (StringUtils.isNotBlank(rollClubOneDetailsJson)) {
-				 try {
-					 JsonNode rollDetails = objectMapper.readTree(rollClubOneDetailsJson);
-					 JsonNode lengthGroupCount = rollDetails.path("lengthGroupCount");
-					 if (lengthGroupCount.isObject()) {
-						 for (Iterator<Map.Entry<String, JsonNode>> it = lengthGroupCount.fields(); it.hasNext(); ) {
-							 Map.Entry<String, JsonNode> entry = it.next();
-							 String mm = entry.getKey();
-							 int count = entry.getValue().asInt(0);
-							 mergedLengthCount.merge(mm, count, Integer::sum);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.warn("解析 rollClubOneDetails 失败: {}, 内容: {}", record.getHeatNo(), rollClubOneDetailsJson, e);
-				 }
-			 }
-
-			 // 解析 hotChargeLength 数组
-			 String hotChargeLengthJson = record.getHotChargeLength();
-			 if (StringUtils.isNotBlank(hotChargeLengthJson)) {
-				 try {
-					 JsonNode hotArray = objectMapper.readTree(hotChargeLengthJson);
-					 if (hotArray.isArray()) {
-						 for (JsonNode node : hotArray) {
-							 String mm = node.path("hotChargeLength").asText();
-							 int count = node.path("totalCount").asInt(0);
-							 mergedLengthCount.merge(mm, count, Integer::sum);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.warn("解析 hotChargeLength 失败: {}, 内容: {}", record.getHeatNo(), hotChargeLengthJson, e);
-				 }
-			 }
-
-			 //  解析 stackLength 数组
-			 String stackLengthJson = record.getStackLength();
-			 if (StringUtils.isNotBlank(stackLengthJson)) {
-				 try {
-					 JsonNode stackArray = objectMapper.readTree(stackLengthJson);
-					 if (stackArray.isArray()) {
-						 for (JsonNode node : stackArray) {
-							 String mm = node.path("stackingLength").asText();
-							 int count = node.path("stackingCount").asInt(0);
-							 mergedLengthCount.merge(mm, count, Integer::sum);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.warn("解析 stackLength 失败: {}, 内容: {}", record.getHeatNo(), stackLengthJson, e);
-				 }
-			 }
-
-			 // 转换 mm 为 m(两位小数),组装 vo
-			 for (Map.Entry<String, Integer> entry : mergedLengthCount.entrySet()) {
-				 String mmStr = entry.getKey();
-				 int count = entry.getValue();
-				 String mStr;
-				 try {
-					 BigDecimal mm = new BigDecimal(mmStr);
-					 mStr = mm.divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP).toString();
-				 } catch (Exception e) {
-					 mStr = mmStr;
-				 }
-				 vo.getLengthCountMap().put(mStr, count);
-				 allLengths.add(mStr);
-			 }
-
-			 resultList.add(vo);
-		 }
-
-		 // 补齐所有定尺列(不存在的补0)
-		 for (LengthCountVO vo : resultList) {
-			 for (String length : allLengths) {
-				 vo.getLengthCountMap().putIfAbsent(length, 0);
-			 }
-		 }
-
-		 return Result.OK(resultList);
-	 }
-
-
-	 @ApiOperation("质检记录定尺明细(用于菜单)")
-	 @GetMapping("/qualityInspectionMenu")
-	 public Result<Map<String, Object>> getQualityInspectionMenu(QualityInspectionQueryDTO queryDTO) {
-
-		 Map<String, Object> result = billetOriginalProductRecordService.getQualityInspectionMenu(queryDTO);
-		 return Result.OK(result);
-	 }
-
-	 /**
-	  *  修改部分质检信息
-	  *
-	  * @param
-	  * @return
-	  */
-	 @AutoLog(value = "修改部分质检信息")
-	 @ApiOperation(value="修改部分质检信息", notes="修改部分质检信息")
-	 @PutMapping(value = "/updateInfo")
-	 public Result<String> updateInfo(@RequestBody BilletOriginalProductRecordEditDTO editDTO) {
-		 BilletOriginalProductRecord byId = billetOriginalProductRecordService.getById(editDTO.getOriginalProductRecordId());
-		 if (byId == null) {
-			 return Result.error("未找到对应数据,编辑失败!");
-		 }
-
-		 if (oConvertUtils.isEmpty(editDTO.getOriginalProductRecordId())) {
-			 return Result.error("原始记录id不能为空!");
-		 }
-
-		 // 使用 UpdateWrapper 只更新指定字段
-		 UpdateWrapper<BilletOriginalProductRecord> updateWrapper = new UpdateWrapper<>();
-		 updateWrapper.eq("id", editDTO.getOriginalProductRecordId());
-
-		 if (StringUtils.isNotBlank(editDTO.getBrandNum())) {
-			 updateWrapper.set("brand_num", editDTO.getBrandNum());
-		 }
-		 if (editDTO.getDeliveryTime() != null) {
-			 updateWrapper.set("delivery_time", editDTO.getDeliveryTime());
-		 }
-		 if (StringUtils.isNotBlank(editDTO.getNotes())) {
-			 updateWrapper.set("notes", editDTO.getNotes());
-		 }
-
-		 billetOriginalProductRecordService.update(updateWrapper);
-
-		 return Result.OK("编辑成功!");
-	 }
-
-
-	 /**
-	  * 获取当前班次下所有炉次浇筑数据
-	  * @param ccmNo
-	  * @param shift
-	  * @param shiftGroup
-	  * @return
-	  */
-	 private List<HeatsActualsInfo> queryCurrentHeatsActualsInfo(String ccmNo, String shift, String shiftGroup, Date shiftStartTime, Date shiftEndTime, String queryType) {
-		 List<HeatsActualsInfo> heatsActualsInfoList = new ArrayList<>();
-		 //根据ccmNo、shift、shiftGroup、大于billetHotsendChangeShift的创建时间 查询所有炉次传递单BilletHotsend
-		 LambdaQueryWrapper<BilletHotsend> queryWrapper1 = new LambdaQueryWrapper<>();
-		 queryWrapper1.eq(BilletHotsend::getCcmNo, ccmNo)
-				 .eq(BilletHotsend::getShift, shift)
-				 .eq(BilletHotsend::getShiftGroup, shiftGroup);
-		 if ("1".equals(queryType)){
-			 queryWrapper1.between(BilletHotsend::getCreateTime, shiftStartTime, new Date());
-		 }else {
-			 queryWrapper1.between(BilletHotsend::getCreateTime, shiftStartTime, shiftEndTime);
-		 }
-		 queryWrapper1.orderByDesc(BilletHotsend::getCreateTime);
-		 List<BilletHotsend> billetHotsendList = billetHotsendBaseService.list(queryWrapper1);
-		 if (oConvertUtils.listIsEmpty(billetHotsendList)){
-			 log.info("{}{}", "钢坯原始生产记录查询失败,炉次传递单为空!", ccmNo + "失败时间:" + new Date());
-			 return heatsActualsInfoList;
-		 }
-		 List<String> distinctHeatNoList = billetHotsendList.stream()
-				 .map(BilletHotsend::getHeatNo)      // 提取炉号
-				 .filter(Objects::nonNull)           // 过滤可能的 null 值
-				 .distinct()                         // 去重
-				 .collect(Collectors.toList());      // 转为列表
-		 List<BilletHotsend> filteredBilletHotsendList = new ArrayList<>();
-		 // 根据铸机号、班别、班别、炉号查询钢坯原始生产记录
-		 QueryWrapper<BilletOriginalProductRecord> queryWrapper8 = new QueryWrapper<>();
-		 queryWrapper8.eq("ccm_no", ccmNo)
-				      .eq("shift", shift)
-		 			  .eq("shift_group", shiftGroup)
-		 			  .in("heat_no", distinctHeatNoList)
-				      .orderByDesc("create_time");
-		 List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper8);
-		 if (oConvertUtils.listIsNotEmpty(billetOriginalProductRecordList)){
-			 List<String> distinctOriginalProductRecordHeatNoList = billetOriginalProductRecordList.stream()
-					 .map(BilletOriginalProductRecord::getHeatNo)      // 提取炉号
-					 .filter(Objects::nonNull)           // 过滤可能的 null 值
-					 .distinct()                         // 去重
-					 .collect(Collectors.toList());      // 转为列表
-			 // 2. 将炉号列表转换为 Set 以提高查询效率
-			 Set<String> excludeHeatNos = new HashSet<>(distinctOriginalProductRecordHeatNoList);
-			 // 3. 过滤 billetHotsendList,保留炉号不在 excludeHeatNos 中的记录
-			 filteredBilletHotsendList = billetHotsendList.stream()
-					 .filter(item -> {
-						 String heatNo = item.getHeatNo();
-						 // 保留 heatNo 为空或不在 excludeHeatNos 中的记录
-						 return heatNo == null || !excludeHeatNos.contains(heatNo);
-					 }).collect(Collectors.toList());
-			 // 4. 同步原始钢坯生产记录表中存在的炉号信息(热装hotChargeLength字段)
-			 billetOriginalProductRecordList.forEach(x -> {
-				 // 查询装运单打印表最新的数据,获取热装定尺
-				 String shiftAndShiftGroup = x.getShift() + "/" + x.getShiftGroup();
-				 String heatNo = x.getHeatNo();
-				 // 构建安全的 JSON 路径表达式
-				 String jsonPath = "$.\"" + heatNo + "\"";
-				 List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(
-						 new QueryWrapper<StorageBillPrint>()
-								 .lambda()
-								 .eq(StorageBillPrint::getCcmNo, x.getCcmNo())
-								 .eq(StorageBillPrint::getClasses, shiftAndShiftGroup) // 新增的条件
-								 .apply("JSON_EXTRACT(heat_no, '" + jsonPath + "') IS NOT NULL")
-				 );
-				 // 如果装运单打印表数据不为空,并且热装字段已经被编辑过,就不在实时读取装运打印表的实时热装数据
-				 if (oConvertUtils.listIsNotEmpty(storageBillPrintList) && "1".equals(x.getIsEditCharge())){
-					 List<Map<String, Object>> finalResult = handleStorageBillPrintHotCharge(storageBillPrintList, heatNo);
-					 x.setHotChargeLength(JSON.toJSONString(finalResult));
-					 billetOriginalProductRecordService.updateById(x);
-				 }
-			 });
-		 }else {
-			 filteredBilletHotsendList = billetHotsendList;
-		 }
-		 // 查询当班炉次浇筑时,增量查询
-		 filteredBilletHotsendList.forEach(x -> {
-			 HeatsActualsInfo heatsActualsInfo = new HeatsActualsInfo();
-			 heatsActualsInfo.setCreateTime(DateUtils.date2Str(x.getCreateTime(), DateUtils.datetimeFormat.get()));
-			 heatsActualsInfo.setShiftGroup(x.getShiftGroup());
-			 heatsActualsInfo.setShift(x.getShift());
-			 heatsActualsInfo.setHeatNo(x.getHeatNo());
-			 heatsActualsInfo.setBrandNum(x.getBrandNum());// 牌号 钢种
-			 // 根据铸机号、炉号查询钢坯实绩信息BilletBasicInfo
-			 LambdaQueryWrapper<BilletBasicInfo> queryWrapper2 = new LambdaQueryWrapper<>();
-			 queryWrapper2.eq(BilletBasicInfo::getCcmNo, x.getCcmNo())
-					 .eq(BilletBasicInfo::getHeatNo, x.getHeatNo())
-					 .eq(BilletBasicInfo::getShift, x.getShift())
-					 .eq(BilletBasicInfo::getShiftGroup, x.getShiftGroup());
-			 List<BilletBasicInfo> billetBasicInfoList = billetBasicInfoService.list(queryWrapper2);
-			 if (oConvertUtils.listIsEmpty(billetBasicInfoList)){
-				 log.info("{}{}", "钢坯原始生产记录,该炉对应的钢坯实绩不存在:", x.getHeatNo());
-				 return;
-			 }
-			 // 统计各流号的数量
-			 Map<Integer, Long> strandCountMap = billetBasicInfoList.stream()
-					 .filter(info -> info.getStrandNo() != null && info.getStrandNo() >= 1 && info.getStrandNo() <= 8)
-					 .collect(Collectors.groupingBy(BilletBasicInfo::getStrandNo, Collectors.counting()));
-
-			 // 获取StrandNo等于1的所有定尺length,并去重后用逗号连接
-			 heatsActualsInfo.setOneStrandNo(Math.toIntExact(strandCountMap.getOrDefault(1, 0L)));
-			 List<BilletBasicInfo> strandOneData = filterByStrandNo(billetBasicInfoList,1);
-			 heatsActualsInfo.setOneLength(JSON.toJSONString(groupByLength(strandOneData)));
-			 heatsActualsInfo.setOneSum(strandOneData.size());
-
-			 heatsActualsInfo.setTwoStrandNo(Math.toIntExact(strandCountMap.getOrDefault(2, 0L)));
-			 List<BilletBasicInfo> strandTwoData = filterByStrandNo(billetBasicInfoList,2);
-			 heatsActualsInfo.setTwoLength(JSON.toJSONString(groupByLength(strandTwoData)));
-			 heatsActualsInfo.setTwoSum(strandTwoData.size());
-
-			 heatsActualsInfo.setThreeStrandNo(Math.toIntExact(strandCountMap.getOrDefault(3, 0L)));
-			 List<BilletBasicInfo> strandThreeData = filterByStrandNo(billetBasicInfoList,3);
-			 heatsActualsInfo.setThreeLength(JSON.toJSONString(groupByLength(strandThreeData)));
-			 heatsActualsInfo.setThreeSum(strandThreeData.size());
-
-			 heatsActualsInfo.setFourStrandNo(Math.toIntExact(strandCountMap.getOrDefault(4, 0L)));
-			 List<BilletBasicInfo> strandFourData = filterByStrandNo(billetBasicInfoList,4);
-			 heatsActualsInfo.setFourLength(JSON.toJSONString(groupByLength(strandFourData)));
-			 heatsActualsInfo.setFourSum(strandFourData.size());
-
-			 heatsActualsInfo.setFiveStrandNo(Math.toIntExact(strandCountMap.getOrDefault(5, 0L)));
-			 List<BilletBasicInfo> strandFiveData = filterByStrandNo(billetBasicInfoList,5);
-			 heatsActualsInfo.setFiveLength(JSON.toJSONString(groupByLength(strandFiveData)));
-			 heatsActualsInfo.setFiveSum(strandFiveData.size());
-
-			 heatsActualsInfo.setSixStrandNo(Math.toIntExact(strandCountMap.getOrDefault(6, 0L)));
-			 List<BilletBasicInfo> strandSixData = filterByStrandNo(billetBasicInfoList,6);
-			 heatsActualsInfo.setSixLength(JSON.toJSONString(groupByLength(strandSixData)));
-			 heatsActualsInfo.setSixSum(strandSixData.size());
-
-			 heatsActualsInfo.setSevenStrandNo(Math.toIntExact(strandCountMap.getOrDefault(7, 0L)));
-			 List<BilletBasicInfo> strandSevenData = filterByStrandNo(billetBasicInfoList,7);
-			 heatsActualsInfo.setSevenLength(JSON.toJSONString(groupByLength(strandSevenData)));
-			 heatsActualsInfo.setSevenSum(strandSevenData.size());
-
-			 heatsActualsInfo.setEightStrandNo(Math.toIntExact(strandCountMap.getOrDefault(8, 0L)));
-			 List<BilletBasicInfo> strandEightData = filterByStrandNo(billetBasicInfoList,8);
-			 heatsActualsInfo.setEightLength(JSON.toJSONString(groupByLength(strandEightData)));
-			 heatsActualsInfo.setEightSum(strandEightData.size());
-
-			 // 5#直轧棒一、6#热送高线 过滤并计算
-			 List<BilletBasicInfo> filterDirectRollingList = billetBasicInfoList.stream()
-					 .filter(info -> "roll_club_one".equals(info.getBelongTable()) || "roll_height".equals(info.getBelongTable()))
-					 .collect(Collectors.toList());
-			 if (oConvertUtils.listIsNotEmpty(filterDirectRollingList)){
-				 // 计算总重(保留4位小数)
-				 double totalWeight = filterDirectRollingList.stream()
-						 .mapToDouble(BilletBasicInfo::getBilletWeight)
-						 .sum();
-				 totalWeight = Math.round(totalWeight * 10000) / 10000.0;
-
-				 // 统计总数
-				 int totalCount = filterDirectRollingList.size();
-
-				 // 按定尺 length 分组统计每组数量(Long 类型)
-				 Map<Integer, Long> lengthCountMapRaw = filterDirectRollingList.stream()
-						 .filter(info -> info.getLength() != null)
-						 .collect(Collectors.groupingBy(BilletBasicInfo::getLength, Collectors.counting()));
-
-				 // 转换为 Map<String, Long>,确保 JSON key 是字符串
-				 Map<String, Long> lengthCountMap = lengthCountMapRaw.entrySet().stream()
-						 .collect(Collectors.toMap(
-								 e -> String.valueOf(e.getKey()), // key 转字符串
-								 Map.Entry::getValue
-						 ));
-
-				 // 转为JSON字符串
-				 Map<String, Object> directRollingMap = new HashMap<>();
-				 directRollingMap.put("directRollingTotalWeight", totalWeight);
-				 directRollingMap.put("directRollingTotalCount", totalCount);
-				 directRollingMap.put("lengthGroupCount", lengthCountMap); // 定尺统计结果
-				 String jsonResult = JSON.toJSONString(directRollingMap); // 使用FastJSON转换.
-				 heatsActualsInfo.setDirectRolling(jsonResult);
-			 }
-
-			 // 堆垛过滤并计算
-			 List<BilletBasicInfo> filterStackList = billetBasicInfoList.stream()
-					 .filter(info -> "stacking_and_loading_vehicles".equals(info.getBelongTable()))
-					 .collect(Collectors.toList());
-			 if (oConvertUtils.listIsNotEmpty(filterStackList)){
-				 // 按定尺长度分组
-				 Map<Integer, List<BilletBasicInfo>> lengthGroupMap = filterStackList.stream()
-						 .filter(info -> info.getLength() != null)
-						 .collect(Collectors.groupingBy(BilletBasicInfo::getLength));
-
-				 // 构建分组统计结果列表
-				 List<Map<String, Object>> lengthGroupList = new ArrayList<>();
-
-				 for (Map.Entry<Integer, List<BilletBasicInfo>> entry : lengthGroupMap.entrySet()) {
-					 Integer length = entry.getKey();
-					 List<BilletBasicInfo> billets = entry.getValue();
-
-					 // 计算该定尺长度的总重(保留4位小数)
-					 double lengthWeight = billets.stream()
-							 .mapToDouble(BilletBasicInfo::getBilletWeight)
-							 .sum();
-					 lengthWeight = Math.round(lengthWeight * 10000) / 10000.0;
-
-					 // 统计该定尺长度的数量
-					 int lengthCount = billets.size();
-
-					 // 构建该定尺长度的统计结果
-					 Map<String, Object> lengthStat = new HashMap<>();
-					 lengthStat.put("stackingWeight", lengthWeight);
-					 lengthStat.put("stackingCount", lengthCount);
-					 lengthStat.put("stackingLength", length);
-					 // 添加到结果列表
-					 lengthGroupList.add(lengthStat);
-				 }
-				 // 直接将列表转换为JSON
-				 String jsonResult = JSON.toJSONString(lengthGroupList);
-				 heatsActualsInfo.setStacking(jsonResult);
-			 }
-
-			 // 根据铸机号、炉号、班组、班别查询装运单打印表
-			 String shiftAndShiftGroup = x.getShift() + "/" + x.getShiftGroup();
-			 String heatNo = x.getHeatNo();
-			 // 构建安全的 JSON 路径表达式
-			 String jsonPath = "$.\"" + heatNo + "\"";
-			 List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(
-					 new QueryWrapper<StorageBillPrint>()
-							 .lambda()
-							 .eq(StorageBillPrint::getCcmNo, x.getCcmNo())
-							 .eq(StorageBillPrint::getClasses, shiftAndShiftGroup) // 新增的条件
-							 .apply("JSON_EXTRACT(heat_no, '" + jsonPath + "') IS NOT NULL")
-			 );
-			 if (oConvertUtils.listIsNotEmpty(storageBillPrintList)){
-				 List<Map<String, Object>> finalResult = handleStorageBillPrintHotCharge(storageBillPrintList, heatNo);
-				 // 使用结果...
-				 log.info("钢坯原始记录,热装打印表分组统计结果: {}", JSON.toJSONString(finalResult));
-				 heatsActualsInfo.setHotCharge(JSON.toJSONString(finalResult));
-			 }
-
-			 // 按length字段分组,并统计每组的总数和总重
-			 Map<Integer, Map<String, Object>> lengthResultMap = billetBasicInfoList.stream()
-					 .filter(info -> info.getLength() != null) // 过滤掉length为null的记录
-					 .collect(Collectors.groupingBy(
-							 BilletBasicInfo::getLength, // 按length分组
-							 Collectors.collectingAndThen(
-									 Collectors.toList(),
-									 list -> {
-										 // 计算每组的总重(保留4位小数)
-										 double totalWeight = list.stream()
-												 .mapToDouble(BilletBasicInfo::getBilletWeight)
-												 .sum();
-										 totalWeight = Math.round(totalWeight * 10000) / 10000.0;
-										 // 统计每组的总数
-										 int totalCount = list.size();
-										 // 创建每组的结果Map
-										 Map<String, Object> groupResult = new HashMap<>();
-										 groupResult.put("lengthTotalWeight", totalWeight);
-										 groupResult.put("lengthTotalCount", totalCount);
-										 //棒一统计
-										 long rollClubOneCount = list.stream()
-												 .filter(billet -> "roll_club_one".equals(billet.getBelongTable()))
-												 .count();
-										 groupResult.put("rollClubOneCount", (int) rollClubOneCount);
-										 // 棒二统计
-										 long rollClubTwoCount = list.stream()
-												 .filter(billet -> "roll_club_two".equals(billet.getBelongTable()))
-												 .count();
-										 groupResult.put("rollClubTwoCount", (int) rollClubTwoCount);
-										 // 棒三统计
-										 long rollClubThreeCount = list.stream()
-												 .filter(billet -> "roll_club_three".equals(billet.getBelongTable()))
-												 .count();
-										 groupResult.put("rollClubThreeCount", (int) rollClubThreeCount);
-										 // 高线统计
-										 long rollHeightCount = list.stream()
-												 .filter(billet -> "roll_height".equals(billet.getBelongTable()))
-												 .count();
-										 groupResult.put("rollHeightCount", (int) rollHeightCount);
-										 // 堆垛统计
-										 long stackingAndLoadingVehiclesCount = list.stream()
-												 .filter(billet -> "stacking_and_loading_vehicles".equals(billet.getBelongTable()))
-												 .count();
-										 groupResult.put("stackingAndLoadingVehiclesCount", (int) stackingAndLoadingVehiclesCount);
-										 return groupResult;
-									 }
-							 )
-					 ));
-			 // 将Integer键转换为String键
-			 Map<String, Map<String, Object>> stringKeyMap = lengthResultMap.entrySet().stream()
-					 .collect(Collectors.toMap(
-							 e -> String.valueOf(e.getKey()),
-							 Map.Entry::getValue
-					 ));
-
-			 // 转换为JSON字符串
-			 String jsonResult = JSON.toJSONString(stringKeyMap);
-			 heatsActualsInfo.setLength(jsonResult);
-
-			 // 统计总数
-			 long totalCount = billetBasicInfoList.size();
-
-			 // 计算总重(保留4位小数)
-			 double totalWeight = billetBasicInfoList.stream()
-					 .mapToDouble(BilletBasicInfo::getBilletWeight)
-					 .sum();
-			 totalWeight = Math.round(totalWeight * 10000) / 10000.0;
-
-			 // 转为JSON字符串
-			 Map<String, Object> resultMap = new HashMap<>();
-			 resultMap.put("totalCount", totalCount);
-			 resultMap.put("totalWeight", totalWeight);
-			 String sumJsonResult = JSON.toJSONString(resultMap); // 使用FastJSON转换
-			 heatsActualsInfo.setTotalInfo(sumJsonResult);
-
-			 heatsActualsInfoList.add(heatsActualsInfo);
-		 });
-		 return heatsActualsInfoList;
-	 }
-
-	 @ApiOperation(value="钢坯堆垛原始生产记录查询", notes="钢坯原始堆垛生产记录查询")
-	 @GetMapping(value = "/queryBilletStackRecordByCcmNo")
-	 public Result<List<BilletOriginalHeatNoDetail>> queryBilletStackRecordByCcmNo(@RequestParam(name="ccmNo", required = false) String ccmNo,
-																			   @RequestParam(name="changeShiftId", required = false) String changeShiftId,
-																			   @RequestParam(name="queryType") String queryType) {
-		 List<BilletOriginalHeatNoDetail> billetOriginalHeatNoDetailList = new ArrayList<>();
-		 BilletHotsendChangeShift billetHotsendChangeShift;
-		 if ("1".equals(queryType)){
-			 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)) : "";
-
-			 if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
-				 return Result.error("班组班别获取为空,钢坯堆垛原始生产记录查询失败!");
-			 }
-			 // 根据ccmNo、shift、shiftGroup查询最新的交班记录
-			 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-			 queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
-					 .eq(BilletHotsendChangeShift::getShift, shift)
-					 .eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
-					 .isNull(BilletHotsendChangeShift::getChangeShiftTime)
-					 .orderByDesc(BilletHotsendChangeShift::getCreateTime)
-					 .last("limit 1");
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-			 if (billetHotsendChangeShift == null){
-				 log.info("{}{}", "钢坯堆垛原始生产记录,交班记录为空!", ccmNo + "失败时间:" + new Date());
-				 return Result.error("交班信息为空,钢坯堆垛原始生产记录查询失败!");
-			 }
-		 }else {
-			 billetHotsendChangeShift = billetHotsendChangeShiftService.getById(changeShiftId);
-		 }
-
-		 QueryWrapper<BilletOriginalProductRecord> queryWrapper3 = new QueryWrapper<>();
-		 queryWrapper3.eq("ccm_no", ccmNo)
-				 .eq("shift", billetHotsendChangeShift.getShift())
-				 .eq("shift_group", billetHotsendChangeShift.getShiftGroup());
-		 if ("1".equals(queryType)){
-			 queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), new Date());
-		 }else {
-			 queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime());
-		 }
-		 // 通过铸机号、班组、班别、交班开始时间 查询钢坯堆垛生产原始记录
-		 List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper3);
-		 if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
-			 return Result.OK(billetOriginalHeatNoDetailList);
-		 }
-		 billetOriginalProductRecordList.forEach(x -> {
-			 BilletOriginalHeatNoDetail billetOriginalHeatNoDetail = new BilletOriginalHeatNoDetail();
-			 billetOriginalHeatNoDetail.setCcmNo(x.getCcmNo());
-			 billetOriginalHeatNoDetail.setHeatNo(x.getHeatNo());
-			 billetOriginalHeatNoDetail.setBrandNum(x.getGrade());
-			 billetOriginalHeatNoDetail.setShiftGroup(x.getShiftGroup());
-			 billetOriginalHeatNoDetail.setShift(x.getShift());
-			 if (oConvertUtils.isNotEmpty(x.getStackLength())){
-				 billetOriginalHeatNoDetail.setStackLength(x.getStackLength());
-				 String stackLengthJson = x.getStackLength();
-				 JSONArray jsonArray = JSON.parseArray(stackLengthJson);
-				 // 初始化总数和总重
-				 int totalCount = 0;
-				 double totalWeight = 0.0d;
-				 // 遍历 JSON 数组计算总数和总重
-				 for (int i = 0; i < jsonArray.size(); i++) {
-					 JSONObject item = jsonArray.getJSONObject(i);
-					 // 获取 stackingCount 字段并累加到总数
-					 int count = item.getIntValue("stackingCount");
-					 // 如果 stackingCount 为 0,跳过该项
-					 if (count == 0) {
-						 continue;
-					 }
-					 totalCount += count;
-					 // 获取 stackingWeight 字段并累加到总重
-					 double weight = item.getDoubleValue("stackingWeight");
-					 totalWeight += weight;
-				 }
-				 // 使用 DecimalFormat   四舍五入 保留四位小数
-				 DecimalFormat df = new DecimalFormat("#.####");
-				 String formattedWeight = df.format(totalWeight);
-				 double roundedWeight = Double.parseDouble(formattedWeight);
-				 billetOriginalHeatNoDetail.setAmountTotal(totalCount);
-				 billetOriginalHeatNoDetail.setBlankOutput(roundedWeight);
-			 }
-			 billetOriginalHeatNoDetailList.add(billetOriginalHeatNoDetail);
-		 });
-
-		 return Result.OK(billetOriginalHeatNoDetailList);
-	 }
-
-
-	 @ApiOperation(value="所有钢坯堆垛信息查询", notes="所有钢坯堆垛信息查询")
-	 @GetMapping(value = "/queryBilletStackInfoByCcmNo")
-	 public Result<List<Map<String, Object>>> queryBilletStackInfoByCcmNo(@RequestParam(name="ccmNo", required = true) String ccmNo,
+	/**
+	 * 导出excel
+	 *
+	 * @param request
+	 * @param billetOriginalProductRecord
+	 */
+	@RequiresPermissions("billetOriginalProductRecord:billet_original_product_record:exportXls")
+	@RequestMapping(value = "/exportXls")
+	public ModelAndView exportXls(HttpServletRequest request, BilletOriginalProductRecord billetOriginalProductRecord) {
+		return super.exportXls(request, billetOriginalProductRecord, BilletOriginalProductRecord.class, "钢坯生成原始记录");
+	}
+
+	/**
+	 * 通过excel导入数据
+	 *
+	 * @param request
+	 * @param response
+	 * @return
+	 */
+	@RequiresPermissions("billetOriginalProductRecord:billet_original_product_record:importExcel")
+	@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+	public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+		return super.importExcel(request, response, BilletOriginalProductRecord.class);
+	}
+
+
+	@ApiOperation(value="钢坯原始生产记录查询", notes="钢坯原始生产记录查询")
+	@GetMapping(value = "/queryBilletRecordByCcmNo")
+	public Result<BilletOriginalProductRecordDetail> queryHeatsActualsByCcmNo(@RequestParam(name="ccmNo", required = false) String ccmNo,
+																			  @RequestParam(name="changeShiftId", required = false) String changeShiftId,
+																			  @RequestParam(name="queryType") String queryType) {
+		List<BilletOriginalProductRecord> billetOriginalProductRecords = new ArrayList<>();
+		BilletHotsendChangeShift billetHotsendChangeShift;
+		if ("1".equals(queryType)){
+			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)) : "";
+
+			if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
+				return Result.error("班组班别获取为空,钢坯原始生产记录查询失败!");
+			}
+			// 根据ccmNo、shift、shiftGroup查询最新的交班记录
+			LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+			queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
+					.eq(BilletHotsendChangeShift::getShift, shift)
+					.eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
+					.isNull(BilletHotsendChangeShift::getChangeShiftTime)
+					.orderByDesc(BilletHotsendChangeShift::getCreateTime)
+					.last("limit 1");
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+			if (billetHotsendChangeShift == null){
+				log.info("{}{}", "钢坯原始生产记录,交班记录为空!", ccmNo + "失败时间:" + new Date());
+				return Result.error("交班信息为空,钢坯原始生产记录查询失败!");
+			}
+		}else {
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getById(changeShiftId);
+		}
+		if (billetHotsendChangeShift == null) {
+			log.error("未查询到有效的交班记录,无法继续处理");
+			return Result.error("未找到对应的交班信息,原始生产记录获取失败!");
+		}
+		//1、 获取当班浇筑炉次详细信息
+		List<HeatsActualsInfo> heatsActualsInfoList = queryCurrentHeatsActualsInfo(ccmNo, billetHotsendChangeShift.getShift(), billetHotsendChangeShift.getShiftGroup(), billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime(), queryType);
+		if (oConvertUtils.listIsNotEmpty(heatsActualsInfoList)){
+			log.info("原始生产记录,当班浇筑炉次数据信息: " + JSON.toJSON(heatsActualsInfoList));
+			//2、把获取到的当班浇筑炉次信息heatsActualsInfoList保存到原始生产记录表
+			heatsActualsInfoList.forEach(x -> {
+				BilletOriginalProductRecord billetOriginalProductRecord = new BilletOriginalProductRecord();
+				billetOriginalProductRecord.setId(String.valueOf(IdWorker.getId()));
+				billetOriginalProductRecord.setCcmNo(ccmNo);
+				billetOriginalProductRecord.setHeatNo(x.getHeatNo());
+				billetOriginalProductRecord.setShift(x.getShift());
+				billetOriginalProductRecord.setShiftGroup(x.getShiftGroup());
+				billetOriginalProductRecord.setGrade(x.getBrandNum());
+				billetOriginalProductRecord.setOneStrandSum(x.getOneSum());
+				billetOriginalProductRecord.setTwoStrandSum(x.getTwoSum());
+				billetOriginalProductRecord.setThreeStrandSum(x.getThreeSum());
+				billetOriginalProductRecord.setFourStrandSum(x.getFourSum());
+				billetOriginalProductRecord.setFiveStrandSum(x.getFiveSum());
+				billetOriginalProductRecord.setSixStrandSum(x.getSixSum());
+				billetOriginalProductRecord.setSevenStrandSum(x.getSevenSum());
+				billetOriginalProductRecord.setEightStrandSum(x.getEightSum());
+				String totalInfoJson = x.getTotalInfo();
+				if (oConvertUtils.isEmpty(totalInfoJson)){
+					billetOriginalProductRecord.setAmount(0);// 合计
+				}else {
+					JSONObject json = JSON.parseObject(totalInfoJson);
+					Integer totalCount = json.getInteger("totalCount");
+					billetOriginalProductRecord.setAmount(totalCount);// 合计
+				}
+				billetOriginalProductRecord.setRollClubOneDetails(x.getDirectRolling());// 直轧热送棒一
+				billetOriginalProductRecord.setHotChargeLength(x.getHotCharge());
+				billetOriginalProductRecord.setStackLength(x.getStacking());
+				billetOriginalProductRecord.setLengthDetails(x.getLength());
+				billetOriginalProductRecord.setCreateTime(DateUtils.str2Date(x.getCreateTime(), DateUtils.datetimeFormat.get()));
+				billetOriginalProductRecord.setIsEditCharge("1");
+				billetOriginalProductRecords.add(billetOriginalProductRecord);
+			});
+			log.info("钢坯原始生产记录信息: " + JSON.toJSON(billetOriginalProductRecords));
+
+			// 在批量保存前,过滤掉已存在的炉号记录
+			List<BilletOriginalProductRecord> finalRecords = billetOriginalProductRecords.stream()
+					.filter(record -> {
+						// 使用 getOne 方法检查是否存在相同记录(铸机号、炉号、班次、班组均相同)
+						LambdaQueryWrapper<BilletOriginalProductRecord> checkWrapper = new LambdaQueryWrapper<>();
+						checkWrapper.eq(BilletOriginalProductRecord::getCcmNo, record.getCcmNo())
+								.eq(BilletOriginalProductRecord::getHeatNo, record.getHeatNo())
+								.eq(BilletOriginalProductRecord::getShift, record.getShift())
+								.eq(BilletOriginalProductRecord::getShiftGroup, record.getShiftGroup())
+								.last("LIMIT 1"); // 只查询一条记录,提高性能
+						// 如果 getOne 结果为 null,表示记录不存在,保留该记录
+						return billetOriginalProductRecordService.getOne(checkWrapper, false) == null;
+					}).collect(Collectors.toList());
+			if(oConvertUtils.listIsNotEmpty(finalRecords)){
+				try {
+					// 批量保存
+					billetOriginalProductRecordService.saveBatch(finalRecords);
+				} catch (DuplicateKeyException e) {
+					log.error("炉号重复插入:{}", JSON.toJSONString(billetOriginalProductRecords), e);
+				}
+			}
+		}
+		QueryWrapper<BilletOriginalProductRecord> queryWrapper3 = new QueryWrapper<>();
+		queryWrapper3.eq("ccm_no", ccmNo)
+				.eq("shift", billetHotsendChangeShift.getShift())
+				.eq("shift_group", billetHotsendChangeShift.getShiftGroup());
+		if ("1".equals(queryType)){
+			queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), new Date());
+		}else {
+			queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime());
+		}
+		// 通过铸机号、班组、班别、交班开始时间 查询钢坯生产原始记录
+		List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper3);
+		BilletOriginalProductRecordDetail billetOriginalProductRecordDetails = new BilletOriginalProductRecordDetail();
+		billetOriginalProductRecordDetails.setBilletOriginalProductRecordList(billetOriginalProductRecordList);
+		billetOriginalProductRecordDetails.setSizeInfo(billetHotsendChangeShift.getSizeInfo());
+		billetOriginalProductRecordDetails.setContent(billetHotsendChangeShift.getContent());
+		billetOriginalProductRecordDetails.setConfirmStatus(billetHotsendChangeShift.getConfirmStatus());
+		return Result.OK(billetOriginalProductRecordDetails);
+	}
+
+
+	@ApiOperation("送样卡获取定尺支数明细表")
+	@GetMapping("/lengthDetailsTable")
+	public Result<List<LengthCountVO>> getLengthDetailsTable(LengthCountQueryDTO queryDTO) {
+		if (queryDTO == null || StringUtils.isBlank(queryDTO.getCcmNo())) {
+			return Result.error("参数不能为空");
+		}
+
+		String shift = "";
+		String shiftGroup = "";
+		BilletHotsendChangeShift billetHotsendChangeShift;
+
+		if (oConvertUtils.isEmpty(queryDTO.getChangeShiftId())) {
+			String classShiftGroup = String.format("class:shift:group:%s", queryDTO.getCcmNo());
+			String classShift = String.format("class:shift:%s", queryDTO.getCcmNo());
+			shift = oConvertUtils.getString(redisTemplate.opsForValue().get(classShift), "");
+			shiftGroup = oConvertUtils.getString(redisTemplate.opsForValue().get(classShiftGroup), "");
+
+			LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+			queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, queryDTO.getCcmNo())
+					.eq(BilletHotsendChangeShift::getShift, shift)
+					.eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
+					.orderByDesc(BilletHotsendChangeShift::getCreateTime)
+					.last("limit 1");
+
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+			if (billetHotsendChangeShift == null) {
+				log.info("查询班次信息失败,交班记录为空!失败时间:{}", new Date());
+				return Result.OK(Collections.emptyList());
+			}
+		} else {
+			LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+			queryWrapper.eq(BilletHotsendChangeShift::getId, queryDTO.getChangeShiftId())
+					.eq(BilletHotsendChangeShift::getCcmNo, queryDTO.getCcmNo());
+
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+			if (billetHotsendChangeShift == null) {
+				log.info("查询班次信息失败,交班记录为空!失败时间:{}", new Date());
+				return Result.OK(Collections.emptyList());
+			}
+		}
+
+		Date startTime = billetHotsendChangeShift.getCreateTime();
+		Date endTime = billetHotsendChangeShift.getChangeShiftTime() != null
+				? billetHotsendChangeShift.getChangeShiftTime()
+				: new Date();
+
+		QueryWrapper<BilletOriginalProductRecord> queryWrapperB = new QueryWrapper<>();
+		queryWrapperB.eq("ccm_no", queryDTO.getCcmNo())
+				.eq("shift", billetHotsendChangeShift.getShift())
+				.eq("shift_group", billetHotsendChangeShift.getShiftGroup())
+				.ge("create_time", startTime)
+				.le("create_time", endTime)
+				.orderByAsc("create_time");
+
+		List<BilletOriginalProductRecord> records = billetOriginalProductRecordService.list(queryWrapperB);
+
+		List<LengthCountVO> resultList = new ArrayList<>();
+		Set<String> allLengths = new TreeSet<>();
+		ObjectMapper objectMapper = new ObjectMapper();
+
+		for (BilletOriginalProductRecord record : records) {
+			LengthCountVO vo = new LengthCountVO();
+			vo.setHeatNo(record.getHeatNo());
+
+			String brandNum = Optional.ofNullable(record.getGrade())
+					.map(bn -> sysDictService.queryDictTextByKey("billet_spec", bn))
+					.orElseGet(() -> sysDictService.queryDictTextByKey("billet_spec", "5"));
+			vo.setBrandNum(brandNum);
+
+			Map<String, Integer> mergedLengthCount = new HashMap<>();
+
+			// 解析 rollClubOneDetails 的 lengthGroupCount
+			String rollClubOneDetailsJson = record.getRollClubOneDetails();
+			if (StringUtils.isNotBlank(rollClubOneDetailsJson)) {
+				try {
+					JsonNode rollDetails = objectMapper.readTree(rollClubOneDetailsJson);
+					JsonNode lengthGroupCount = rollDetails.path("lengthGroupCount");
+					if (lengthGroupCount.isObject()) {
+						for (Iterator<Map.Entry<String, JsonNode>> it = lengthGroupCount.fields(); it.hasNext(); ) {
+							Map.Entry<String, JsonNode> entry = it.next();
+							String mm = entry.getKey();
+							int count = entry.getValue().asInt(0);
+							mergedLengthCount.merge(mm, count, Integer::sum);
+						}
+					}
+				} catch (Exception e) {
+					log.warn("解析 rollClubOneDetails 失败: {}, 内容: {}", record.getHeatNo(), rollClubOneDetailsJson, e);
+				}
+			}
+
+			// 解析 hotChargeLength 数组
+			String hotChargeLengthJson = record.getHotChargeLength();
+			if (StringUtils.isNotBlank(hotChargeLengthJson)) {
+				try {
+					JsonNode hotArray = objectMapper.readTree(hotChargeLengthJson);
+					if (hotArray.isArray()) {
+						for (JsonNode node : hotArray) {
+							String mm = node.path("hotChargeLength").asText();
+							int count = node.path("totalCount").asInt(0);
+							mergedLengthCount.merge(mm, count, Integer::sum);
+						}
+					}
+				} catch (Exception e) {
+					log.warn("解析 hotChargeLength 失败: {}, 内容: {}", record.getHeatNo(), hotChargeLengthJson, e);
+				}
+			}
+
+			//  解析 stackLength 数组
+			String stackLengthJson = record.getStackLength();
+			if (StringUtils.isNotBlank(stackLengthJson)) {
+				try {
+					JsonNode stackArray = objectMapper.readTree(stackLengthJson);
+					if (stackArray.isArray()) {
+						for (JsonNode node : stackArray) {
+							String mm = node.path("stackingLength").asText();
+							int count = node.path("stackingCount").asInt(0);
+							mergedLengthCount.merge(mm, count, Integer::sum);
+						}
+					}
+				} catch (Exception e) {
+					log.warn("解析 stackLength 失败: {}, 内容: {}", record.getHeatNo(), stackLengthJson, e);
+				}
+			}
+
+			// 转换 mm 为 m(两位小数),组装 vo
+			for (Map.Entry<String, Integer> entry : mergedLengthCount.entrySet()) {
+				String mmStr = entry.getKey();
+				int count = entry.getValue();
+				String mStr;
+				try {
+					BigDecimal mm = new BigDecimal(mmStr);
+					mStr = mm.divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP).toString();
+				} catch (Exception e) {
+					mStr = mmStr;
+				}
+				vo.getLengthCountMap().put(mStr, count);
+				allLengths.add(mStr);
+			}
+
+			resultList.add(vo);
+		}
+
+		// 补齐所有定尺列(不存在的补0)
+		for (LengthCountVO vo : resultList) {
+			for (String length : allLengths) {
+				vo.getLengthCountMap().putIfAbsent(length, 0);
+			}
+		}
+
+		return Result.OK(resultList);
+	}
+
+
+	@ApiOperation("质检记录定尺明细(用于菜单)")
+	@GetMapping("/qualityInspectionMenu")
+	public Result<Map<String, Object>> getQualityInspectionMenu(QualityInspectionQueryDTO queryDTO) {
+
+		Map<String, Object> result = billetOriginalProductRecordService.getQualityInspectionMenu(queryDTO);
+		return Result.OK(result);
+	}
+
+
+	/**
+	 * 获取当前班次下所有炉次浇筑数据
+	 * @param ccmNo
+	 * @param shift
+	 * @param shiftGroup
+	 * @return
+	 */
+	private List<HeatsActualsInfo> queryCurrentHeatsActualsInfo(String ccmNo, String shift, String shiftGroup, Date shiftStartTime, Date shiftEndTime, String queryType) {
+		List<HeatsActualsInfo> heatsActualsInfoList = new ArrayList<>();
+		//根据ccmNo、shift、shiftGroup、大于billetHotsendChangeShift的创建时间 查询所有炉次传递单BilletHotsend
+		LambdaQueryWrapper<BilletHotsend> queryWrapper1 = new LambdaQueryWrapper<>();
+		queryWrapper1.eq(BilletHotsend::getCcmNo, ccmNo)
+				.eq(BilletHotsend::getShift, shift)
+				.eq(BilletHotsend::getShiftGroup, shiftGroup);
+		if ("1".equals(queryType)){
+			queryWrapper1.between(BilletHotsend::getCreateTime, shiftStartTime, new Date());
+		}else {
+			queryWrapper1.between(BilletHotsend::getCreateTime, shiftStartTime, shiftEndTime);
+		}
+		queryWrapper1.orderByDesc(BilletHotsend::getCreateTime);
+		List<BilletHotsend> billetHotsendList = billetHotsendBaseService.list(queryWrapper1);
+		if (oConvertUtils.listIsEmpty(billetHotsendList)){
+			log.info("{}{}", "钢坯原始生产记录查询失败,炉次传递单为空!", ccmNo + "失败时间:" + new Date());
+			return heatsActualsInfoList;
+		}
+		List<String> distinctHeatNoList = billetHotsendList.stream()
+				.map(BilletHotsend::getHeatNo)      // 提取炉号
+				.filter(Objects::nonNull)           // 过滤可能的 null 值
+				.distinct()                         // 去重
+				.collect(Collectors.toList());      // 转为列表
+		List<BilletHotsend> filteredBilletHotsendList = new ArrayList<>();
+		// 根据铸机号、班别、班别、炉号查询钢坯原始生产记录
+		QueryWrapper<BilletOriginalProductRecord> queryWrapper8 = new QueryWrapper<>();
+		queryWrapper8.eq("ccm_no", ccmNo)
+				.eq("shift", shift)
+				.eq("shift_group", shiftGroup)
+				.in("heat_no", distinctHeatNoList)
+				.orderByDesc("create_time");
+		List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper8);
+		if (oConvertUtils.listIsNotEmpty(billetOriginalProductRecordList)){
+			List<String> distinctOriginalProductRecordHeatNoList = billetOriginalProductRecordList.stream()
+					.map(BilletOriginalProductRecord::getHeatNo)      // 提取炉号
+					.filter(Objects::nonNull)           // 过滤可能的 null 值
+					.distinct()                         // 去重
+					.collect(Collectors.toList());      // 转为列表
+			// 2. 将炉号列表转换为 Set 以提高查询效率
+			Set<String> excludeHeatNos = new HashSet<>(distinctOriginalProductRecordHeatNoList);
+			// 3. 过滤 billetHotsendList,保留炉号不在 excludeHeatNos 中的记录
+			filteredBilletHotsendList = billetHotsendList.stream()
+					.filter(item -> {
+						String heatNo = item.getHeatNo();
+						// 保留 heatNo 为空或不在 excludeHeatNos 中的记录
+						return heatNo == null || !excludeHeatNos.contains(heatNo);
+					}).collect(Collectors.toList());
+			// 4. 同步原始钢坯生产记录表中存在的炉号信息(热装hotChargeLength字段)
+			billetOriginalProductRecordList.forEach(x -> {
+				// 查询装运单打印表最新的数据,获取热装定尺
+				String shiftAndShiftGroup = x.getShift() + "/" + x.getShiftGroup();
+				String heatNo = x.getHeatNo();
+				// 构建安全的 JSON 路径表达式
+				String jsonPath = "$.\"" + heatNo + "\"";
+				List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(
+						new QueryWrapper<StorageBillPrint>()
+								.lambda()
+								.eq(StorageBillPrint::getCcmNo, x.getCcmNo())
+								.eq(StorageBillPrint::getClasses, shiftAndShiftGroup) // 新增的条件
+								.apply("JSON_EXTRACT(heat_no, '" + jsonPath + "') IS NOT NULL")
+				);
+				// 如果装运单打印表数据不为空,并且热装字段已经被编辑过,就不在实时读取装运打印表的实时热装数据
+				if (oConvertUtils.listIsNotEmpty(storageBillPrintList) && "1".equals(x.getIsEditCharge())){
+					List<Map<String, Object>> finalResult = handleStorageBillPrintHotCharge(storageBillPrintList, heatNo);
+					x.setHotChargeLength(JSON.toJSONString(finalResult));
+					billetOriginalProductRecordService.updateById(x);
+				}
+			});
+		}else {
+			filteredBilletHotsendList = billetHotsendList;
+		}
+		// 查询当班炉次浇筑时,增量查询
+		filteredBilletHotsendList.forEach(x -> {
+			HeatsActualsInfo heatsActualsInfo = new HeatsActualsInfo();
+			heatsActualsInfo.setCreateTime(DateUtils.date2Str(x.getCreateTime(), DateUtils.datetimeFormat.get()));
+			heatsActualsInfo.setShiftGroup(x.getShiftGroup());
+			heatsActualsInfo.setShift(x.getShift());
+			heatsActualsInfo.setHeatNo(x.getHeatNo());
+			heatsActualsInfo.setBrandNum(x.getBrandNum());// 牌号 钢种
+			// 根据铸机号、炉号查询钢坯实绩信息BilletBasicInfo
+			LambdaQueryWrapper<BilletBasicInfo> queryWrapper2 = new LambdaQueryWrapper<>();
+			queryWrapper2.eq(BilletBasicInfo::getCcmNo, x.getCcmNo())
+					.eq(BilletBasicInfo::getHeatNo, x.getHeatNo())
+					.eq(BilletBasicInfo::getShift, x.getShift())
+					.eq(BilletBasicInfo::getShiftGroup, x.getShiftGroup());
+			List<BilletBasicInfo> billetBasicInfoList = billetBasicInfoService.list(queryWrapper2);
+			if (oConvertUtils.listIsEmpty(billetBasicInfoList)){
+				log.info("{}{}", "钢坯原始生产记录,该炉对应的钢坯实绩不存在:", x.getHeatNo());
+				return;
+			}
+			// 统计各流号的数量
+			Map<Integer, Long> strandCountMap = billetBasicInfoList.stream()
+					.filter(info -> info.getStrandNo() != null && info.getStrandNo() >= 1 && info.getStrandNo() <= 8)
+					.collect(Collectors.groupingBy(BilletBasicInfo::getStrandNo, Collectors.counting()));
+
+			// 获取StrandNo等于1的所有定尺length,并去重后用逗号连接
+			heatsActualsInfo.setOneStrandNo(Math.toIntExact(strandCountMap.getOrDefault(1, 0L)));
+			List<BilletBasicInfo> strandOneData = filterByStrandNo(billetBasicInfoList,1);
+			heatsActualsInfo.setOneLength(JSON.toJSONString(groupByLength(strandOneData)));
+			heatsActualsInfo.setOneSum(strandOneData.size());
+
+			heatsActualsInfo.setTwoStrandNo(Math.toIntExact(strandCountMap.getOrDefault(2, 0L)));
+			List<BilletBasicInfo> strandTwoData = filterByStrandNo(billetBasicInfoList,2);
+			heatsActualsInfo.setTwoLength(JSON.toJSONString(groupByLength(strandTwoData)));
+			heatsActualsInfo.setTwoSum(strandTwoData.size());
+
+			heatsActualsInfo.setThreeStrandNo(Math.toIntExact(strandCountMap.getOrDefault(3, 0L)));
+			List<BilletBasicInfo> strandThreeData = filterByStrandNo(billetBasicInfoList,3);
+			heatsActualsInfo.setThreeLength(JSON.toJSONString(groupByLength(strandThreeData)));
+			heatsActualsInfo.setThreeSum(strandThreeData.size());
+
+			heatsActualsInfo.setFourStrandNo(Math.toIntExact(strandCountMap.getOrDefault(4, 0L)));
+			List<BilletBasicInfo> strandFourData = filterByStrandNo(billetBasicInfoList,4);
+			heatsActualsInfo.setFourLength(JSON.toJSONString(groupByLength(strandFourData)));
+			heatsActualsInfo.setFourSum(strandFourData.size());
+
+			heatsActualsInfo.setFiveStrandNo(Math.toIntExact(strandCountMap.getOrDefault(5, 0L)));
+			List<BilletBasicInfo> strandFiveData = filterByStrandNo(billetBasicInfoList,5);
+			heatsActualsInfo.setFiveLength(JSON.toJSONString(groupByLength(strandFiveData)));
+			heatsActualsInfo.setFiveSum(strandFiveData.size());
+
+			heatsActualsInfo.setSixStrandNo(Math.toIntExact(strandCountMap.getOrDefault(6, 0L)));
+			List<BilletBasicInfo> strandSixData = filterByStrandNo(billetBasicInfoList,6);
+			heatsActualsInfo.setSixLength(JSON.toJSONString(groupByLength(strandSixData)));
+			heatsActualsInfo.setSixSum(strandSixData.size());
+
+			heatsActualsInfo.setSevenStrandNo(Math.toIntExact(strandCountMap.getOrDefault(7, 0L)));
+			List<BilletBasicInfo> strandSevenData = filterByStrandNo(billetBasicInfoList,7);
+			heatsActualsInfo.setSevenLength(JSON.toJSONString(groupByLength(strandSevenData)));
+			heatsActualsInfo.setSevenSum(strandSevenData.size());
+
+			heatsActualsInfo.setEightStrandNo(Math.toIntExact(strandCountMap.getOrDefault(8, 0L)));
+			List<BilletBasicInfo> strandEightData = filterByStrandNo(billetBasicInfoList,8);
+			heatsActualsInfo.setEightLength(JSON.toJSONString(groupByLength(strandEightData)));
+			heatsActualsInfo.setEightSum(strandEightData.size());
+
+			// 5#直轧棒一、6#热送高线 过滤并计算
+			List<BilletBasicInfo> filterDirectRollingList = billetBasicInfoList.stream()
+					.filter(info -> "roll_club_one".equals(info.getBelongTable()) || "roll_height".equals(info.getBelongTable()))
+					.collect(Collectors.toList());
+			if (oConvertUtils.listIsNotEmpty(filterDirectRollingList)){
+				// 计算总重(保留4位小数)
+				double totalWeight = filterDirectRollingList.stream()
+						.mapToDouble(BilletBasicInfo::getBilletWeight)
+						.sum();
+				totalWeight = Math.round(totalWeight * 10000) / 10000.0;
+
+				// 统计总数
+				int totalCount = filterDirectRollingList.size();
+
+				// 按定尺 length 分组统计每组数量(Long 类型)
+				Map<Integer, Long> lengthCountMapRaw = filterDirectRollingList.stream()
+						.filter(info -> info.getLength() != null)
+						.collect(Collectors.groupingBy(BilletBasicInfo::getLength, Collectors.counting()));
+
+				// 转换为 Map<String, Long>,确保 JSON key 是字符串
+				Map<String, Long> lengthCountMap = lengthCountMapRaw.entrySet().stream()
+						.collect(Collectors.toMap(
+								e -> String.valueOf(e.getKey()), // key 转字符串
+								Map.Entry::getValue
+						));
+
+				// 转为JSON字符串
+				Map<String, Object> directRollingMap = new HashMap<>();
+				directRollingMap.put("directRollingTotalWeight", totalWeight);
+				directRollingMap.put("directRollingTotalCount", totalCount);
+				directRollingMap.put("lengthGroupCount", lengthCountMap); // 定尺统计结果
+				String jsonResult = JSON.toJSONString(directRollingMap); // 使用FastJSON转换.
+				heatsActualsInfo.setDirectRolling(jsonResult);
+			}
+
+			// 堆垛过滤并计算
+			List<BilletBasicInfo> filterStackList = billetBasicInfoList.stream()
+					.filter(info -> "stacking_and_loading_vehicles".equals(info.getBelongTable()))
+					.collect(Collectors.toList());
+			if (oConvertUtils.listIsNotEmpty(filterStackList)){
+				// 按定尺长度分组
+				Map<Integer, List<BilletBasicInfo>> lengthGroupMap = filterStackList.stream()
+						.filter(info -> info.getLength() != null)
+						.collect(Collectors.groupingBy(BilletBasicInfo::getLength));
+
+				// 构建分组统计结果列表
+				List<Map<String, Object>> lengthGroupList = new ArrayList<>();
+
+				for (Map.Entry<Integer, List<BilletBasicInfo>> entry : lengthGroupMap.entrySet()) {
+					Integer length = entry.getKey();
+					List<BilletBasicInfo> billets = entry.getValue();
+
+					// 计算该定尺长度的总重(保留4位小数)
+					double lengthWeight = billets.stream()
+							.mapToDouble(BilletBasicInfo::getBilletWeight)
+							.sum();
+					lengthWeight = Math.round(lengthWeight * 10000) / 10000.0;
+
+					// 统计该定尺长度的数量
+					int lengthCount = billets.size();
+
+					// 构建该定尺长度的统计结果
+					Map<String, Object> lengthStat = new HashMap<>();
+					lengthStat.put("stackingWeight", lengthWeight);
+					lengthStat.put("stackingCount", lengthCount);
+					lengthStat.put("stackingLength", length);
+					// 添加到结果列表
+					lengthGroupList.add(lengthStat);
+				}
+				// 直接将列表转换为JSON
+				String jsonResult = JSON.toJSONString(lengthGroupList);
+				heatsActualsInfo.setStacking(jsonResult);
+			}
+
+			// 根据铸机号、炉号、班组、班别查询装运单打印表
+			String shiftAndShiftGroup = x.getShift() + "/" + x.getShiftGroup();
+			String heatNo = x.getHeatNo();
+			// 构建安全的 JSON 路径表达式
+			String jsonPath = "$.\"" + heatNo + "\"";
+			List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(
+					new QueryWrapper<StorageBillPrint>()
+							.lambda()
+							.eq(StorageBillPrint::getCcmNo, x.getCcmNo())
+							.eq(StorageBillPrint::getClasses, shiftAndShiftGroup) // 新增的条件
+							.apply("JSON_EXTRACT(heat_no, '" + jsonPath + "') IS NOT NULL")
+			);
+			if (oConvertUtils.listIsNotEmpty(storageBillPrintList)){
+				List<Map<String, Object>> finalResult = handleStorageBillPrintHotCharge(storageBillPrintList, heatNo);
+				// 使用结果...
+				log.info("钢坯原始记录,热装打印表分组统计结果: {}", JSON.toJSONString(finalResult));
+				heatsActualsInfo.setHotCharge(JSON.toJSONString(finalResult));
+			}
+
+			// 按length字段分组,并统计每组的总数和总重
+			Map<Integer, Map<String, Object>> lengthResultMap = billetBasicInfoList.stream()
+					.filter(info -> info.getLength() != null) // 过滤掉length为null的记录
+					.collect(Collectors.groupingBy(
+							BilletBasicInfo::getLength, // 按length分组
+							Collectors.collectingAndThen(
+									Collectors.toList(),
+									list -> {
+										// 计算每组的总重(保留4位小数)
+										double totalWeight = list.stream()
+												.mapToDouble(BilletBasicInfo::getBilletWeight)
+												.sum();
+										totalWeight = Math.round(totalWeight * 10000) / 10000.0;
+										// 统计每组的总数
+										int totalCount = list.size();
+										// 创建每组的结果Map
+										Map<String, Object> groupResult = new HashMap<>();
+										groupResult.put("lengthTotalWeight", totalWeight);
+										groupResult.put("lengthTotalCount", totalCount);
+										//棒一统计
+										long rollClubOneCount = list.stream()
+												.filter(billet -> "roll_club_one".equals(billet.getBelongTable()))
+												.count();
+										groupResult.put("rollClubOneCount", (int) rollClubOneCount);
+										// 棒二统计
+										long rollClubTwoCount = list.stream()
+												.filter(billet -> "roll_club_two".equals(billet.getBelongTable()))
+												.count();
+										groupResult.put("rollClubTwoCount", (int) rollClubTwoCount);
+										// 棒三统计
+										long rollClubThreeCount = list.stream()
+												.filter(billet -> "roll_club_three".equals(billet.getBelongTable()))
+												.count();
+										groupResult.put("rollClubThreeCount", (int) rollClubThreeCount);
+										// 高线统计
+										long rollHeightCount = list.stream()
+												.filter(billet -> "roll_height".equals(billet.getBelongTable()))
+												.count();
+										groupResult.put("rollHeightCount", (int) rollHeightCount);
+										// 堆垛统计
+										long stackingAndLoadingVehiclesCount = list.stream()
+												.filter(billet -> "stacking_and_loading_vehicles".equals(billet.getBelongTable()))
+												.count();
+										groupResult.put("stackingAndLoadingVehiclesCount", (int) stackingAndLoadingVehiclesCount);
+										return groupResult;
+									}
+							)
+					));
+			// 将Integer键转换为String键
+			Map<String, Map<String, Object>> stringKeyMap = lengthResultMap.entrySet().stream()
+					.collect(Collectors.toMap(
+							e -> String.valueOf(e.getKey()),
+							Map.Entry::getValue
+					));
+
+			// 转换为JSON字符串
+			String jsonResult = JSON.toJSONString(stringKeyMap);
+			heatsActualsInfo.setLength(jsonResult);
+
+			// 统计总数
+			long totalCount = billetBasicInfoList.size();
+
+			// 计算总重(保留4位小数)
+			double totalWeight = billetBasicInfoList.stream()
+					.mapToDouble(BilletBasicInfo::getBilletWeight)
+					.sum();
+			totalWeight = Math.round(totalWeight * 10000) / 10000.0;
+
+			// 转为JSON字符串
+			Map<String, Object> resultMap = new HashMap<>();
+			resultMap.put("totalCount", totalCount);
+			resultMap.put("totalWeight", totalWeight);
+			String sumJsonResult = JSON.toJSONString(resultMap); // 使用FastJSON转换
+			heatsActualsInfo.setTotalInfo(sumJsonResult);
+
+			heatsActualsInfoList.add(heatsActualsInfo);
+		});
+		return heatsActualsInfoList;
+	}
+
+	@ApiOperation(value="钢坯堆垛原始生产记录查询", notes="钢坯原始堆垛生产记录查询")
+	@GetMapping(value = "/queryBilletStackRecordByCcmNo")
+	public Result<List<BilletOriginalHeatNoDetail>> queryBilletStackRecordByCcmNo(@RequestParam(name="ccmNo", required = false) String ccmNo,
+																				  @RequestParam(name="changeShiftId", required = false) String changeShiftId,
+																				  @RequestParam(name="queryType") String queryType) {
+		List<BilletOriginalHeatNoDetail> billetOriginalHeatNoDetailList = new ArrayList<>();
+		BilletHotsendChangeShift billetHotsendChangeShift;
+		if ("1".equals(queryType)){
+			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)) : "";
+
+			if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
+				return Result.error("班组班别获取为空,钢坯堆垛原始生产记录查询失败!");
+			}
+			// 根据ccmNo、shift、shiftGroup查询最新的交班记录
+			LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+			queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
+					.eq(BilletHotsendChangeShift::getShift, shift)
+					.eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
+					.isNull(BilletHotsendChangeShift::getChangeShiftTime)
+					.orderByDesc(BilletHotsendChangeShift::getCreateTime)
+					.last("limit 1");
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+			if (billetHotsendChangeShift == null){
+				log.info("{}{}", "钢坯堆垛原始生产记录,交班记录为空!", ccmNo + "失败时间:" + new Date());
+				return Result.error("交班信息为空,钢坯堆垛原始生产记录查询失败!");
+			}
+		}else {
+			billetHotsendChangeShift = billetHotsendChangeShiftService.getById(changeShiftId);
+		}
+
+		QueryWrapper<BilletOriginalProductRecord> queryWrapper3 = new QueryWrapper<>();
+		queryWrapper3.eq("ccm_no", ccmNo)
+				.eq("shift", billetHotsendChangeShift.getShift())
+				.eq("shift_group", billetHotsendChangeShift.getShiftGroup());
+		if ("1".equals(queryType)){
+			queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), new Date());
+		}else {
+			queryWrapper3.between("create_time", billetHotsendChangeShift.getCreateTime(), billetHotsendChangeShift.getChangeShiftTime());
+		}
+		// 通过铸机号、班组、班别、交班开始时间 查询钢坯堆垛生产原始记录
+		List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper3);
+		if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
+			return Result.OK(billetOriginalHeatNoDetailList);
+		}
+		billetOriginalProductRecordList.forEach(x -> {
+			BilletOriginalHeatNoDetail billetOriginalHeatNoDetail = new BilletOriginalHeatNoDetail();
+			billetOriginalHeatNoDetail.setCcmNo(x.getCcmNo());
+			billetOriginalHeatNoDetail.setHeatNo(x.getHeatNo());
+			billetOriginalHeatNoDetail.setBrandNum(x.getGrade());
+			billetOriginalHeatNoDetail.setShiftGroup(x.getShiftGroup());
+			billetOriginalHeatNoDetail.setShift(x.getShift());
+			if (oConvertUtils.isNotEmpty(x.getStackLength())){
+				billetOriginalHeatNoDetail.setStackLength(x.getStackLength());
+				String stackLengthJson = x.getStackLength();
+				JSONArray jsonArray = JSON.parseArray(stackLengthJson);
+				// 初始化总数和总重
+				int totalCount = 0;
+				double totalWeight = 0.0d;
+				// 遍历 JSON 数组计算总数和总重
+				for (int i = 0; i < jsonArray.size(); i++) {
+					JSONObject item = jsonArray.getJSONObject(i);
+					// 获取 stackingCount 字段并累加到总数
+					int count = item.getIntValue("stackingCount");
+					// 如果 stackingCount 为 0,跳过该项
+					if (count == 0) {
+						continue;
+					}
+					totalCount += count;
+					// 获取 stackingWeight 字段并累加到总重
+					double weight = item.getDoubleValue("stackingWeight");
+					totalWeight += weight;
+				}
+				// 使用 DecimalFormat   四舍五入 保留四位小数
+				DecimalFormat df = new DecimalFormat("#.####");
+				String formattedWeight = df.format(totalWeight);
+				double roundedWeight = Double.parseDouble(formattedWeight);
+				billetOriginalHeatNoDetail.setAmountTotal(totalCount);
+				billetOriginalHeatNoDetail.setBlankOutput(roundedWeight);
+			}
+			billetOriginalHeatNoDetailList.add(billetOriginalHeatNoDetail);
+		});
+
+		return Result.OK(billetOriginalHeatNoDetailList);
+	}
+
+
+	@ApiOperation(value="所有钢坯堆垛信息查询", notes="所有钢坯堆垛信息查询")
+	@GetMapping(value = "/queryBilletStackInfoByCcmNo")
+	public Result<List<Map<String, Object>>> queryBilletStackInfoByCcmNo(@RequestParam(name="ccmNo", required = true) String ccmNo,
 																		 @RequestParam(name="typeConfigId", required = true) String typeConfigId) {
-		 List<Map<String, Object>> resultList = new ArrayList<>();
-
-		 // 查询所有可能的位置,并按layer和address排序(低layer优先,address从1到9)
-		 List<StackingAndLoadingVehicles> stackingAndLoadingVehiclesList = stackingAndLoadingVehiclesMapper.selectList(
-				 new QueryWrapper<StackingAndLoadingVehicles>()
-						 .eq("ccm_no", ccmNo)
-						 .eq("type_config_id", typeConfigId)
-						 .isNotNull("heat_no")      // 添加 heatNo 不为 null 的条件
-						 .isNotNull("size")         // 添加 size 不为 null 的条件
-						 .isNotNull("billet_nos")); // 添加 billetNos 不为 null 的条件
-		 if (oConvertUtils.listIsEmpty(stackingAndLoadingVehiclesList)){
-			 return Result.OK(resultList);
-		 }
-		 // 根据 heatNo 分组
-		 Map<String, List<StackingAndLoadingVehicles>> heatNoGroupMap = stackingAndLoadingVehiclesList.stream()
-				 .collect(Collectors.groupingBy(StackingAndLoadingVehicles::getHeatNo));
-
-		 // 处理每个炉号分组
-		 for (Map.Entry<String, List<StackingAndLoadingVehicles>> heatNoEntry : heatNoGroupMap.entrySet()) {
-			 String heatNo = heatNoEntry.getKey();
-			 List<StackingAndLoadingVehicles> heatNoItems = heatNoEntry.getValue();
-
-			 // 根据 size 进一步分组
-			 Map<String, List<StackingAndLoadingVehicles>> sizeGroupMap = heatNoItems.stream()
-					 .collect(Collectors.groupingBy(StackingAndLoadingVehicles::getSize));
-
-			 // 初始化炉号总数量和总重量
-			 int totalCount = 0;
-			 BigDecimal totalWeight = BigDecimal.ZERO;
-
-			 // 构建明细列表
-			 JSONArray detailsArray = new JSONArray();
-
-			 // 处理每个 size 分组
-			 for (Map.Entry<String, List<StackingAndLoadingVehicles>> sizeEntry : sizeGroupMap.entrySet()) {
-				 String size = sizeEntry.getKey();
-				 List<StackingAndLoadingVehicles> sizeItems = sizeEntry.getValue();
-
-				 // 计算该 size 的数量(记录数)
-				 int sizeCount = sizeItems.size();
-
-				 // 计算单根重量:size/1000 * 4 * 0.2265
-				 BigDecimal sizeValue = new BigDecimal(size);
-				 BigDecimal singleWeight = sizeValue.divide(BigDecimal.valueOf(1000), 10, RoundingMode.HALF_UP)
-						 .multiply(BigDecimal.valueOf(4))
-						 .multiply(BigDecimal.valueOf(0.2265));
-
-				 // 计算该 size 的总重量
-				 BigDecimal sizeTotalWeight = singleWeight.multiply(BigDecimal.valueOf(sizeCount))
-						 .setScale(4, RoundingMode.HALF_UP);
-
-				 // 更新炉号总数量和总重量
-				 totalCount += sizeCount;
-				 totalWeight = totalWeight.add(sizeTotalWeight);
-
-				 // 添加明细项
-				 JSONObject detail = new JSONObject();
-				 detail.put("stackingCount", sizeCount * 4);
-				 detail.put("stackingLength", size);
-				 detail.put("stackingWeight", sizeTotalWeight.toString());
-				 detailsArray.add(detail);
-			 }
-
-			 // 构建结果项
-			 Map<String, Object> resultItem = new LinkedHashMap<>();
-			 resultItem.put("heatNo", heatNo);
-			 resultItem.put("totalCount", totalCount * 4);
-			 resultItem.put("totalWeight", totalWeight.setScale(4, RoundingMode.HALF_UP).toString());
-			 resultItem.put("details", detailsArray);
-
-			 resultList.add(resultItem);
-		 }
-		 return Result.OK(resultList);
-	 }
-
-
-	 private List<Map<String, Object>> handleStorageBillPrintHotCharge(List<StorageBillPrint> storageBillPrintList, String heatNo) {
-		 List<Map<String, Object>> hotChargeList = new ArrayList<>();
-		 List<Map<String, Object>> finalResult = new ArrayList<>();
-		 // 遍历列表,解析每个 heatNo JSON 并累加数量
-		 for (StorageBillPrint print : storageBillPrintList) {
-			 Map<String, Object> hotChargeMap = new HashMap<>();
-			 String jsonHeatNo = print.getHeatNo();
-
-			 // 初始化当前记录的数量和重量
-			 Integer currentCount = 0;
-			 BigDecimal currentWeight = BigDecimal.ZERO;
-			 // 处理可能包含逗号的定尺值
-			 String sizeValue = print.getSize();
-			 String lengthValue = "0"; // 默认值
-
-			 if (oConvertUtils.isNotEmpty(sizeValue)) {
-				 lengthValue = sizeValue.contains(",")
-						 ? sizeValue.split(",")[0]  // 提取第一个值
-						 : sizeValue;              // 否则使用原值
-			 }
-
-			 if (oConvertUtils.isNotEmpty(jsonHeatNo)) {
-				 try {
-					 // 解析 JSON 对象
-					 JSONObject heatNoJson = JSON.parseObject(jsonHeatNo);
-
-					 // 获取指定炉号对应的数量(如果存在)
-					 if (heatNoJson.containsKey(heatNo)) {
-						 Integer count = heatNoJson.getInteger(heatNo);
-						 if (count != null) {
-							 currentCount = count;
-							 // 使用 BigDecimal 计算重量,避免精度丢失
-							 BigDecimal size = new BigDecimal(lengthValue);
-							 BigDecimal factor = new BigDecimal("0.2265");
-							 currentWeight = size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
-									 .multiply(factor)
-									 .multiply(new BigDecimal(count))
-									 .setScale(4, RoundingMode.HALF_UP);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.error("解析 heatNo JSON 失败: {}", jsonHeatNo, e);
-					 continue; // 跳过当前记录
-				 }
-			 }
-			 String btype = print.getBtype();
-			 // 设置热装信息
-			 hotChargeMap.put("hotChargeBtype", btype);
-			 hotChargeMap.put("hotChargeLength", lengthValue);
-			 hotChargeMap.put("hotChargeTotalCount", currentCount);
-			 hotChargeMap.put("hotChargeTotalWeight", currentWeight.toPlainString());
-
-			 // 设置目的地简称(添加默认值)
-			 String destination = "未知";
-			 if ("棒二".equals(print.getDestination())) {
-				 destination = "roll_club_two";
-			 } else if ("棒三".equals(print.getDestination())) {
-				 destination = "roll_club_three";
-			 } else if ("上若".equals(print.getDestination())) {
-				 destination = "roll_out_shipp";
-			 }
-			 hotChargeMap.put("hotChargeDestination", destination);
-			 // 将当前记录的热装信息添加到列表
-			 hotChargeList.add(hotChargeMap);
-		 }
-		 // 按 hotChargeLength 和 hotChargeDestination 分组统计
-		 Map<String, Map<String, Object>> groupedResult = new HashMap<>();
-
-		 if (oConvertUtils.listIsNotEmpty(hotChargeList)) {
-			 for (Map<String, Object> item : hotChargeList) {
-				 // 使用 getOrDefault 避免空指针
-				 String length = (String) item.getOrDefault("hotChargeLength", "未知");
-				 String destination = (String) item.getOrDefault("hotChargeDestination", "未知");
-				 String btype = (String) item.getOrDefault("hotChargeBtype", "未知");
-				 Integer count = (Integer) item.getOrDefault("hotChargeTotalCount", 0);
-				 BigDecimal weight = new BigDecimal(item.getOrDefault("hotChargeTotalWeight", "0").toString());
-
-				 // **修改分组键:添加 btype**
-				 String groupKey = length + "_" + destination + "_" + btype;
-
-				 // 初始化或获取分组统计结果
-				 groupedResult.computeIfAbsent(groupKey, k -> {
-					 Map<String, Object> groupData = new HashMap<>();
-					 groupData.put("hotChargeLength", length);
-					 groupData.put("hotChargeDestination", destination);
-					 groupData.put("hotChargeBtype", btype); // **添加 btype 到分组数据**
-					 groupData.put("totalCount", 0);
-					 groupData.put("totalWeight", BigDecimal.ZERO);
-					 return groupData;
-				 });
-
-				 // 累加数量和重量
-				 Map<String, Object> groupData = groupedResult.get(groupKey);
-				 Integer totalCount = (Integer) groupData.get("totalCount") + count;
-				 BigDecimal totalWeight = ((BigDecimal) groupData.get("totalWeight")).add(weight);
-
-				 groupData.put("totalCount", totalCount);
-				 groupData.put("totalWeight", totalWeight);
-
-			 }
-			 // 转换为列表并格式化重量
-			 finalResult = groupedResult.values().stream()
-					 .peek(data -> {
-						 // 格式化重量为字符串,保留4位小数
-						 data.put("totalWeight", ((BigDecimal) data.get("totalWeight")).toPlainString());
-					 }).collect(Collectors.toList());
-		 }
-		 return finalResult;
-	 }
-
-	 @ApiOperation(value="钢坯棒一棒二棒三上若高线统计明细查询", notes="钢坯棒一棒二棒三上若统计明细查询")
-	 @GetMapping(value = "/queryBilletStatisticsDetailByCcmNo")
-	 public Result<List<BilletDetailsInfo>> queryBilletStatisticsDetailByCcmNo(@RequestParam(name="ccmNo") String ccmNo,
-																	 		   @RequestParam(name="changeShiftId", required = false, defaultValue = "") String changeShiftId,
-																			   @RequestParam(name="queryDate", required = false, defaultValue = "") String queryDate,
-																			   @RequestParam(name="startTime", required = false, defaultValue = "") String startTime,
-																			   @RequestParam(name="endTime", required = false, defaultValue = "") String endTime,
-																	           @RequestParam(name="queryType") String queryType,
-																			   @RequestParam(name="heatNo", required = false, defaultValue = "") String heatNo,
-																			   @RequestParam(name = "size", required = false, defaultValue = "") String size,
-																			   @RequestParam(name = "btype", required = false, defaultValue = "") String btype,
-																			   @RequestParam(name = "brandNum", required = false, defaultValue = "") String brandNum,
-																			   @RequestParam(name="licensePlate", required = false, defaultValue = "") String licensePlate) {
-		 List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
-		 if (queryType.equals("1") || queryType.equals("5")){
-			 // 查询5号机棒一、6号机高线,指定日期的统计明细
-			 billetDetailsInfoList = queryRollClubOneStatistics(ccmNo,  changeShiftId, queryDate, heatNo, startTime, endTime);
-		 }else if(queryType.equals("2")){ // 查询棒二,指定班次的统计明细
-			 billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "棒二", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
-		 }else if(queryType.equals("3")){  // 查询棒三,指定班次的统计明细
-			 billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "棒三", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
-		 }else if(queryType.equals("4")){ // 查询上若,指定班次的统计明细
-			 billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "上若", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
-		 }
-		 return Result.OK(billetDetailsInfoList);
-	 }
-
-	 @ApiOperation(value="推钢室当班炉次浇筑信息查询", notes="推钢室当班炉次浇筑信息查询")
-	 @GetMapping(value = "/queryOriginalHeatInfoByCcmNo")
-	 public Result<BilletOriginalInfo> queryHeatsActualsByCcmNo(@RequestParam(name="ccmNo", required = true) String ccmNo) {
-		 BilletOriginalInfo billetOriginalInfo = new BilletOriginalInfo();
-		 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)) : "";
-
-		 if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
-			 return Result.error("班组班别获取为空,查询失败!");
-		 }
+		List<Map<String, Object>> resultList = new ArrayList<>();
+
+		// 查询所有可能的位置,并按layer和address排序(低layer优先,address从1到9)
+		List<StackingAndLoadingVehicles> stackingAndLoadingVehiclesList = stackingAndLoadingVehiclesMapper.selectList(
+				new QueryWrapper<StackingAndLoadingVehicles>()
+						.eq("ccm_no", ccmNo)
+						.eq("type_config_id", typeConfigId)
+						.isNotNull("heat_no")      // 添加 heatNo 不为 null 的条件
+						.isNotNull("size")         // 添加 size 不为 null 的条件
+						.isNotNull("billet_nos")); // 添加 billetNos 不为 null 的条件
+		if (oConvertUtils.listIsEmpty(stackingAndLoadingVehiclesList)){
+			return Result.OK(resultList);
+		}
+		// 根据 heatNo 分组
+		Map<String, List<StackingAndLoadingVehicles>> heatNoGroupMap = stackingAndLoadingVehiclesList.stream()
+				.collect(Collectors.groupingBy(StackingAndLoadingVehicles::getHeatNo));
+
+		// 处理每个炉号分组
+		for (Map.Entry<String, List<StackingAndLoadingVehicles>> heatNoEntry : heatNoGroupMap.entrySet()) {
+			String heatNo = heatNoEntry.getKey();
+			List<StackingAndLoadingVehicles> heatNoItems = heatNoEntry.getValue();
+
+			// 根据 size 进一步分组
+			Map<String, List<StackingAndLoadingVehicles>> sizeGroupMap = heatNoItems.stream()
+					.collect(Collectors.groupingBy(StackingAndLoadingVehicles::getSize));
+
+			// 初始化炉号总数量和总重量
+			int totalCount = 0;
+			BigDecimal totalWeight = BigDecimal.ZERO;
+
+			// 构建明细列表
+			JSONArray detailsArray = new JSONArray();
+
+			// 处理每个 size 分组
+			for (Map.Entry<String, List<StackingAndLoadingVehicles>> sizeEntry : sizeGroupMap.entrySet()) {
+				String size = sizeEntry.getKey();
+				List<StackingAndLoadingVehicles> sizeItems = sizeEntry.getValue();
+
+				// 计算该 size 的数量(记录数)
+				int sizeCount = sizeItems.size();
+
+				// 计算单根重量:size/1000 * 4 * 0.2265
+				BigDecimal sizeValue = new BigDecimal(size);
+				BigDecimal singleWeight = sizeValue.divide(BigDecimal.valueOf(1000), 10, RoundingMode.HALF_UP)
+						.multiply(BigDecimal.valueOf(4))
+						.multiply(BigDecimal.valueOf(0.2265));
+
+				// 计算该 size 的总重量
+				BigDecimal sizeTotalWeight = singleWeight.multiply(BigDecimal.valueOf(sizeCount))
+						.setScale(4, RoundingMode.HALF_UP);
+
+				// 更新炉号总数量和总重量
+				totalCount += sizeCount;
+				totalWeight = totalWeight.add(sizeTotalWeight);
+
+				// 添加明细项
+				JSONObject detail = new JSONObject();
+				detail.put("stackingCount", sizeCount * 4);
+				detail.put("stackingLength", size);
+				detail.put("stackingWeight", sizeTotalWeight.toString());
+				detailsArray.add(detail);
+			}
+
+			// 构建结果项
+			Map<String, Object> resultItem = new LinkedHashMap<>();
+			resultItem.put("heatNo", heatNo);
+			resultItem.put("totalCount", totalCount * 4);
+			resultItem.put("totalWeight", totalWeight.setScale(4, RoundingMode.HALF_UP).toString());
+			resultItem.put("details", detailsArray);
+
+			resultList.add(resultItem);
+		}
+		return Result.OK(resultList);
+	}
+
+
+	private List<Map<String, Object>> handleStorageBillPrintHotCharge(List<StorageBillPrint> storageBillPrintList, String heatNo) {
+		List<Map<String, Object>> hotChargeList = new ArrayList<>();
+		List<Map<String, Object>> finalResult = new ArrayList<>();
+		// 遍历列表,解析每个 heatNo JSON 并累加数量
+		for (StorageBillPrint print : storageBillPrintList) {
+			Map<String, Object> hotChargeMap = new HashMap<>();
+			String jsonHeatNo = print.getHeatNo();
+
+			// 初始化当前记录的数量和重量
+			Integer currentCount = 0;
+			BigDecimal currentWeight = BigDecimal.ZERO;
+			// 处理可能包含逗号的定尺值
+			String sizeValue = print.getSize();
+			String lengthValue = "0"; // 默认值
+
+			if (oConvertUtils.isNotEmpty(sizeValue)) {
+				lengthValue = sizeValue.contains(",")
+						? sizeValue.split(",")[0]  // 提取第一个值
+						: sizeValue;              // 否则使用原值
+			}
+
+			if (oConvertUtils.isNotEmpty(jsonHeatNo)) {
+				try {
+					// 解析 JSON 对象
+					JSONObject heatNoJson = JSON.parseObject(jsonHeatNo);
+
+					// 获取指定炉号对应的数量(如果存在)
+					if (heatNoJson.containsKey(heatNo)) {
+						Integer count = heatNoJson.getInteger(heatNo);
+						if (count != null) {
+							currentCount = count;
+							// 使用 BigDecimal 计算重量,避免精度丢失
+							BigDecimal size = new BigDecimal(lengthValue);
+							BigDecimal factor = new BigDecimal("0.2265");
+							currentWeight = size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
+									.multiply(factor)
+									.multiply(new BigDecimal(count))
+									.setScale(4, RoundingMode.HALF_UP);
+						}
+					}
+				} catch (Exception e) {
+					log.error("解析 heatNo JSON 失败: {}", jsonHeatNo, e);
+					continue; // 跳过当前记录
+				}
+			}
+			String btype = print.getBtype();
+			// 设置热装信息
+			hotChargeMap.put("hotChargeBtype", btype);
+			hotChargeMap.put("hotChargeLength", lengthValue);
+			hotChargeMap.put("hotChargeTotalCount", currentCount);
+			hotChargeMap.put("hotChargeTotalWeight", currentWeight.toPlainString());
+
+			// 设置目的地简称(添加默认值)
+			String destination = "未知";
+			if ("棒二".equals(print.getDestination())) {
+				destination = "roll_club_two";
+			} else if ("棒三".equals(print.getDestination())) {
+				destination = "roll_club_three";
+			} else if ("上若".equals(print.getDestination())) {
+				destination = "roll_out_shipp";
+			}
+			hotChargeMap.put("hotChargeDestination", destination);
+			// 将当前记录的热装信息添加到列表
+			hotChargeList.add(hotChargeMap);
+		}
+		// 按 hotChargeLength 和 hotChargeDestination 分组统计
+		Map<String, Map<String, Object>> groupedResult = new HashMap<>();
+
+		if (oConvertUtils.listIsNotEmpty(hotChargeList)) {
+			for (Map<String, Object> item : hotChargeList) {
+				// 使用 getOrDefault 避免空指针
+				String length = (String) item.getOrDefault("hotChargeLength", "未知");
+				String destination = (String) item.getOrDefault("hotChargeDestination", "未知");
+				String btype = (String) item.getOrDefault("hotChargeBtype", "未知");
+				Integer count = (Integer) item.getOrDefault("hotChargeTotalCount", 0);
+				BigDecimal weight = new BigDecimal(item.getOrDefault("hotChargeTotalWeight", "0").toString());
+
+				// **修改分组键:添加 btype**
+				String groupKey = length + "_" + destination + "_" + btype;
+
+				// 初始化或获取分组统计结果
+				groupedResult.computeIfAbsent(groupKey, k -> {
+					Map<String, Object> groupData = new HashMap<>();
+					groupData.put("hotChargeLength", length);
+					groupData.put("hotChargeDestination", destination);
+					groupData.put("hotChargeBtype", btype); // **添加 btype 到分组数据**
+					groupData.put("totalCount", 0);
+					groupData.put("totalWeight", BigDecimal.ZERO);
+					return groupData;
+				});
+
+				// 累加数量和重量
+				Map<String, Object> groupData = groupedResult.get(groupKey);
+				Integer totalCount = (Integer) groupData.get("totalCount") + count;
+				BigDecimal totalWeight = ((BigDecimal) groupData.get("totalWeight")).add(weight);
+
+				groupData.put("totalCount", totalCount);
+				groupData.put("totalWeight", totalWeight);
+
+			}
+			// 转换为列表并格式化重量
+			finalResult = groupedResult.values().stream()
+					.peek(data -> {
+						// 格式化重量为字符串,保留4位小数
+						data.put("totalWeight", ((BigDecimal) data.get("totalWeight")).toPlainString());
+					}).collect(Collectors.toList());
+		}
+		return finalResult;
+	}
+
+	@ApiOperation(value="钢坯棒一棒二棒三上若高线统计明细查询", notes="钢坯棒一棒二棒三上若统计明细查询")
+	@GetMapping(value = "/queryBilletStatisticsDetailByCcmNo")
+	public Result<List<BilletDetailsInfo>> queryBilletStatisticsDetailByCcmNo(@RequestParam(name="ccmNo") String ccmNo,
+																			  @RequestParam(name="changeShiftId", required = false, defaultValue = "") String changeShiftId,
+																			  @RequestParam(name="queryDate", required = false, defaultValue = "") String queryDate,
+																			  @RequestParam(name="startTime", required = false, defaultValue = "") String startTime,
+																			  @RequestParam(name="endTime", required = false, defaultValue = "") String endTime,
+																			  @RequestParam(name="queryType") String queryType,
+																			  @RequestParam(name="heatNo", required = false, defaultValue = "") String heatNo,
+																			  @RequestParam(name = "size", required = false, defaultValue = "") String size,
+																			  @RequestParam(name = "btype", required = false, defaultValue = "") String btype,
+																			  @RequestParam(name = "brandNum", required = false, defaultValue = "") String brandNum,
+																			  @RequestParam(name="licensePlate", required = false, defaultValue = "") String licensePlate) {
+		List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
+		if (queryType.equals("1") || queryType.equals("5")){
+			// 查询5号机棒一、6号机高线,指定日期的统计明细
+			billetDetailsInfoList = queryRollClubOneStatistics(ccmNo,  changeShiftId, queryDate, heatNo, startTime, endTime);
+		}else if(queryType.equals("2")){ // 查询棒二,指定班次的统计明细
+			billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "棒二", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
+		}else if(queryType.equals("3")){  // 查询棒三,指定班次的统计明细
+			billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "棒三", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
+		}else if(queryType.equals("4")){ // 查询上若,指定班次的统计明细
+			billetDetailsInfoList = querSstorageBillPrintStatistics(ccmNo, "上若", queryDate, changeShiftId, heatNo, licensePlate, startTime, endTime, size, btype, brandNum);
+		}
+		return Result.OK(billetDetailsInfoList);
+	}
+
+	@ApiOperation(value="推钢室当班炉次浇筑信息查询", notes="推钢室当班炉次浇筑信息查询")
+	@GetMapping(value = "/queryOriginalHeatInfoByCcmNo")
+	public Result<BilletOriginalInfo> queryHeatsActualsByCcmNo(@RequestParam(name="ccmNo", required = true) String ccmNo) {
+		BilletOriginalInfo billetOriginalInfo = new BilletOriginalInfo();
+		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)) : "";
+
+		if (oConvertUtils.isEmpty(shiftGroup) || oConvertUtils.isEmpty(shift)){
+			return Result.error("班组班别获取为空,查询失败!");
+		}
 		// 根据ccmNo、shift、shiftGroup查询最新的交班记录
-		 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-		 queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
-				 .eq(BilletHotsendChangeShift::getShift, shift)
-				 .eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
-				 .isNull(BilletHotsendChangeShift::getChangeShiftTime)
-				 .orderByDesc(BilletHotsendChangeShift::getCreateTime)
-				 .last("limit 1");
-		 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-		 if (billetHotsendChangeShift == null){
-			 return Result.error("交班记录为空,查询失败!");
-		 }
-
-		 Date startTime = billetHotsendChangeShift.getCreateTime();
-		 Date endTime = new Date();
-
-		 // 通过铸机号、开始时间、结束时间查询 钢坯原始生产记录
-		 QueryWrapper<BilletOriginalProductRecord> queryWrapper1 = new QueryWrapper<>();
-		 queryWrapper1.eq("ccm_no", ccmNo);
-		 queryWrapper1.eq("shift", shift);
-		 queryWrapper1.eq("shift_group", shiftGroup);
-		 queryWrapper1.between("create_time", startTime, endTime);
-		 queryWrapper1.orderByDesc("create_time");
-		 List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper1);
-		 if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
-			 return Result.OK(billetOriginalInfo);
-		 }
-		 String directRollingJson = calculateDirectRollingStatistics(billetOriginalProductRecordList);
-		 // 统计5#直轧棒一、6#热送高线
-		 billetOriginalInfo.setDirectRolling(directRollingJson);
-
-		 // 根据铸机号、开始时间、结束时间查询查询装运单打印表
-		 String hotChargeJson = "";
-		 String shiftAndShiftGroup = shift + "/" + shiftGroup;
-		 LambdaQueryWrapper<StorageBillPrint> querySbWrapper = new LambdaQueryWrapper<>();
-		 querySbWrapper.eq(StorageBillPrint::getCcmNo, ccmNo)
-				 .eq(StorageBillPrint::getClasses, shiftAndShiftGroup)
-				 .between(StorageBillPrint::getCreateTime, startTime, endTime)
-				 .orderByDesc(StorageBillPrint::getCreateTime);
-		 List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(querySbWrapper);
-		 if (oConvertUtils.listIsNotEmpty(storageBillPrintList)) {
-			 hotChargeJson = calculateHotChargeStatistics(storageBillPrintList);
-		     // 统计热装
-			 billetOriginalInfo.setHotCharge(hotChargeJson);
-		 }
-		 String stackingJson = calculateStackingStatistics(billetOriginalProductRecordList);
-		 // 统计堆垛
-		 billetOriginalInfo.setStacking(stackingJson);
-
-		 // 计算总重量
-		 double totalWeight = calculateTotalWeight(directRollingJson, hotChargeJson, stackingJson);
-		 billetOriginalInfo.setBlankOutputs(totalWeight);
-
-		 String brandNum = String.format("billet:basic:info:brand:num:%s", ccmNo); // 牌号
-		 String brandNumStr = !oConvertUtils.getString(redisTemplate.opsForValue().get(brandNum)).isEmpty() ? oConvertUtils.getString(redisTemplate.opsForValue().get(brandNum)) : "";
-		 billetOriginalInfo.setBrandNum(brandNumStr);
-
-		 billetOriginalInfo.setShift(shift);
-		 billetOriginalInfo.setShiftGroup(shiftGroup);
-
-		 // 遍历billetOriginalProductRecordList,获取BilletOriginalProductRecord中的三个json字段, hotChargeLength、stackLength、rollClubOneDetails,对所有定尺进行统计,统计出定尺、和对应的数量
-		 billetOriginalProductRecordList.forEach(y ->{
-			 Map<String, Integer> lengthCountMap = new HashMap<>();
-			 // 处理热装所有定尺字段
-			 processHotChargeLength(y.getHotChargeLength(), lengthCountMap);
-
-			 // 处理堆垛所有定尺字段
-			 processStackLength(y.getStackLength(), lengthCountMap);
-
-			 // 处理5#棒一、6#热送高线 所有定尺字段
-			 processRollClubOneDetails(y.getRollClubOneDetails(), lengthCountMap);
-
-			 y.setLengthDetails(JSON.toJSONString(lengthCountMap));
-		 });
-
-		 billetOriginalInfo.setBilletOriginalProductRecordList(billetOriginalProductRecordList);
-		 billetOriginalInfo.setTotalInfo(billetOriginalProductRecordList.stream().filter(x -> x.getAmount() != null)
-				 .mapToInt(BilletOriginalProductRecord::getAmount)
-				 .sum());
-		 return Result.OK(billetOriginalInfo);
-	 }
-	 /**
-	  * 计算5#直轧棒一、6#高线的统计信息
-	  */
-	 private String calculateDirectRollingStatistics(List<BilletOriginalProductRecord> records) {
-		 // 用于存储统计结果的Map,键为定尺,值为数量和重量
-		 Map<String, LengthStatistics> lengthStatsMap = new HashMap<>();
-
-		 // 遍历所有记录
-		 for (BilletOriginalProductRecord record : records) {
-			 String rollClubOneDetails = record.getRollClubOneDetails();
-			 if (oConvertUtils.isNotEmpty(rollClubOneDetails)) {
-				 try {
-					 // 解析JSON字符串
-					 JSONObject detailsJson = JSON.parseObject(rollClubOneDetails);
-					 // 获取lengthGroupCount对象
-					 JSONObject lengthGroupCount = detailsJson.getJSONObject("lengthGroupCount");
-					 if (lengthGroupCount != null) {
-						 // 遍历每个定尺及其数量
-						 for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
-							 String length = entry.getKey();
-							 Integer count = Integer.valueOf(entry.getValue().toString());
-							 // 累加到统计结果中
-							 lengthStatsMap.computeIfAbsent(length, k -> new LengthStatistics()).addCount(count);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.error("解析rollClubOneDetails、rollHeightDetails失败: {}", rollClubOneDetails, e);
-					 // 忽略解析失败的记录,继续处理其他记录
-				 }
-			 }
-		 }
-
-		 // 计算总重量并构建结果
-		 JSONObject resultJson = new JSONObject();
-		 JSONObject lengthGroupCountJson = new JSONObject();
-		 BigDecimal totalWeight = BigDecimal.ZERO;
-		 int totalCount = 0;
-
-		 // 计算每个定尺的重量并累加总重量
-		 for (Map.Entry<String, LengthStatistics> entry : lengthStatsMap.entrySet()) {
-			 String length = entry.getKey();
-			 LengthStatistics stats = entry.getValue();
-
-			 // 计算当前定尺的总重量
-			 BigDecimal size = new BigDecimal(length);
-			 BigDecimal weight = size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
-					 .multiply(new BigDecimal(stats.getCount()))
-					 .multiply(new BigDecimal("0.2265"))
-					 .setScale(4, RoundingMode.HALF_UP);
-
-			 // 更新统计信息
-			 stats.setWeight(weight);
-			 totalWeight = totalWeight.add(weight);
-			 totalCount += stats.getCount();
-
-			 // 构建定尺统计JSON
-			 JSONObject lengthStatsJson = new JSONObject();
-			 lengthStatsJson.put("count", stats.getCount());
-			 lengthStatsJson.put("weight", weight.toPlainString());
-			 lengthGroupCountJson.put(length, lengthStatsJson);
-		 }
-
-		 // 设置最终结果
-		 resultJson.put("lengthGroupCount", lengthGroupCountJson);
-		 resultJson.put("directRollingTotalCount", totalCount);
-		 resultJson.put("directRollingTotalWeight", totalWeight.toPlainString());
-
-		 return resultJson.toJSONString();
-	 }
-
-	 /**
-	  * 计算热装的统计信息
-	  */
-	 private String calculateHotChargeStatistics(List<StorageBillPrint> storageBillPrintList) {
-		 // 用于存储统计结果的Map,键为size,值为统计信息
-		 Map<String, SizeStatistics> sizeStatsMap = new HashMap<>();
-
-		 // 遍历所有记录
-		 for (StorageBillPrint print : storageBillPrintList) {
-			 String size = print.getSize();
-			 if (oConvertUtils.isNotEmpty(size)) {
-				 try {
-					 // 转换为数值并验证
-					 BigDecimal sizeDecimal = new BigDecimal(size.trim());
-
-					 // 累加数量和计算重量
-					 sizeStatsMap.computeIfAbsent(size, k -> new SizeStatistics())
-							 .addData(1, calculateWeight(sizeDecimal, 1));
-				 } catch (NumberFormatException e) {
-					 log.error("无效的size值: {}", size, e);
-					 // 忽略无效的size值,继续处理其他值
-				 }
-			 }
-		 }
-
-		 // 构建结果JSON (保持原有逻辑不变)
-		 JSONObject resultJson = new JSONObject();
-		 JSONObject sizeGroupJson = new JSONObject();
-		 int totalCount = 0;
-		 BigDecimal totalWeight = BigDecimal.ZERO;
-
-		 // 处理统计结果
-		 for (Map.Entry<String, SizeStatistics> entry : sizeStatsMap.entrySet()) {
-			 String size = entry.getKey();
-			 SizeStatistics stats = entry.getValue();
-
-			 // 构建单个size的统计JSON
-			 JSONObject sizeStatsJson = new JSONObject();
-			 sizeStatsJson.put("count", stats.getCount());
-			 sizeStatsJson.put("weight", stats.getWeight().toPlainString());
-
-			 // 添加到结果中
-			 sizeGroupJson.put(size, sizeStatsJson);
-			 totalCount += stats.getCount();
-			 totalWeight = totalWeight.add(stats.getWeight());
-		 }
-
-		 // 设置最终结果
-		 resultJson.put("sizeGroupCount", sizeGroupJson);
-		 resultJson.put("totalCount", totalCount);
-		 resultJson.put("totalWeight", totalWeight.toPlainString());
-		 return resultJson.toJSONString();
-	 }
-	 /**
-	  * 计算堆垛信息的统计
-	  */
-	 private String calculateStackingStatistics(List<BilletOriginalProductRecord> records) {
-		 // 用于存储统计结果的Map,键为定尺,值为统计信息
-		 Map<String, SizeStatistics> stackingStatsMap = new HashMap<>();
-
-		 // 遍历所有记录
-		 for (BilletOriginalProductRecord record : records) {
-			 String stackLengthJson = record.getStackLength();
-			 if (oConvertUtils.isNotEmpty(stackLengthJson)) {
-				 try {
-					 // 解析JSON数组
-					 JSONArray stackLengthArray = JSON.parseArray(stackLengthJson);
-
-					 // 遍历每个堆垛信息
-					 for (int i = 0; i < stackLengthArray.size(); i++) {
-						 JSONObject stackItem = stackLengthArray.getJSONObject(i);
-
-						 // 获取堆垛长度和数量
-						 String length = stackItem.getString("stackingLength");
-						 Integer count = stackItem.getInteger("stackingCount");
-						 BigDecimal weight = stackItem.getBigDecimal("stackingWeight");
-
-						 if (length != null && count != null && weight != null) {
-							 // 累加到统计结果中
-							 stackingStatsMap.computeIfAbsent(length, k -> new SizeStatistics()).addData(count, weight);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.error("解析stackLength失败: {}", stackLengthJson, e);
-					 // 忽略解析失败的记录,继续处理其他记录
-				 }
-			 }
-		 }
-
-		 // 构建结果JSON
-		 JSONObject resultJson = new JSONObject();
-		 JSONObject lengthGroupJson = new JSONObject();
-		 int totalCount = 0;
-		 BigDecimal totalWeight = BigDecimal.ZERO;
-
-		 // 处理统计结果
-		 for (Map.Entry<String, SizeStatistics> entry : stackingStatsMap.entrySet()) {
-			 String length = entry.getKey();
-			 SizeStatistics stats = entry.getValue();
-
-			 // 构建单个定尺的统计JSON
-			 JSONObject lengthStatsJson = new JSONObject();
-			 lengthStatsJson.put("count", stats.getCount());
-			 lengthStatsJson.put("weight", stats.getWeight().toPlainString());
-
-			 // 添加到结果中
-			 lengthGroupJson.put(length, lengthStatsJson);
-			 totalCount += stats.getCount();
-			 totalWeight = totalWeight.add(stats.getWeight());
-		 }
-
-		 // 设置最终结果
-		 resultJson.put("lengthGroupCount", lengthGroupJson);
-		 resultJson.put("stackingTotalCount", totalCount);
-		 resultJson.put("stackingTotalWeight", totalWeight.toPlainString());
-
-		 return resultJson.toJSONString();
-	 }
-	 /**
-	  * 从三个JSON中提取总重量并计算总和
-	  */
-	 private double calculateTotalWeight(String directRollingJson, String hotChargeJson, String stackingJson) {
-		 BigDecimal total = BigDecimal.ZERO;
-		 // 从直轧统计中提取总重量
-		 if (oConvertUtils.isNotEmpty(directRollingJson)) {
-			 try {
-				 JSONObject json = JSON.parseObject(directRollingJson);
-				 String weightStr = json.getString("directRollingTotalWeight");
-				 if (oConvertUtils.isNotEmpty(weightStr)) {
-					 total = total.add(new BigDecimal(weightStr));
-				 }
-			 } catch (Exception e) {
-				 log.error("从directRollingJson提取总重量失败", e);
-			 }
-		 }
-
-		 // 从热装统计中提取总重量
-		 if (oConvertUtils.isNotEmpty(hotChargeJson)) {
-			 try {
-				 JSONObject json = JSON.parseObject(hotChargeJson);
-				 String weightStr = json.getString("totalWeight");
-				 if (oConvertUtils.isNotEmpty(weightStr)) {
-					 total = total.add(new BigDecimal(weightStr));
-				 }
-			 } catch (Exception e) {
-				 log.error("从hotChargeJson提取总重量失败", e);
-			 }
-		 }
-
-		 // 从堆垛统计中提取总重量
-		 if (oConvertUtils.isNotEmpty(stackingJson)) {
-			 try {
-				 JSONObject json = JSON.parseObject(stackingJson);
-				 String weightStr = json.getString("stackingTotalWeight");
-				 if (oConvertUtils.isNotEmpty(weightStr)) {
-					 total = total.add(new BigDecimal(weightStr));
-				 }
-			 } catch (Exception e) {
-				 log.error("从stackingJson提取总重量失败", e);
-			 }
-		 }
-		 // 转换为double类型,保留4位小数
-		 return total.setScale(4, RoundingMode.HALF_UP).doubleValue();
-	 }
-	 // 保持原有计算方法不变
-	 private BigDecimal calculateWeight(BigDecimal size, int count) {
-		 return size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
-				 .multiply(new BigDecimal(count))
-				 .multiply(new BigDecimal("0.2265"))
-				 .setScale(4, RoundingMode.HALF_UP);
-	 }
-
-	 /**
-	  * 处理hotChargeLength字段,合并相同定尺
-	  */
-	 private void processHotChargeLength(String jsonStr, Map<String, Integer> lengthCountMap) {
-		 if (oConvertUtils.isNotEmpty(jsonStr)) {
-			 try {
-				 JSONArray jsonArray = JSON.parseArray(jsonStr);
-				 for (int i = 0; i < jsonArray.size(); i++) {
-					 JSONObject item = jsonArray.getJSONObject(i);
-					 String length = item.getString("hotChargeLength");
-					 Integer count = item.getInteger("totalCount");
-
-					 if (length != null && count != null) {
-						 // 使用merge方法自动合并相同定尺
-						 lengthCountMap.merge(length, count, Integer::sum);
-					 }
-				 }
-			 } catch (Exception e) {
-				 log.error("解析hotChargeLength失败: {}", jsonStr, e);
-			 }
-		 }
-	 }
-
-	 /**
-	  * 处理stackLength字段,合并相同定尺
-	  */
-	 private void processStackLength(String jsonStr, Map<String, Integer> lengthCountMap) {
-		 if (oConvertUtils.isNotEmpty(jsonStr)) {
-			 try {
-				 JSONArray jsonArray = JSON.parseArray(jsonStr);
-				 for (int i = 0; i < jsonArray.size(); i++) {
-					 JSONObject item = jsonArray.getJSONObject(i);
-					 String length = item.getString("stackingLength");
-					 Integer count = item.getInteger("stackingCount");
-
-					 if (length != null && count != null) {
-						 // 使用merge方法自动合并相同定尺
-						 lengthCountMap.merge(length, count, Integer::sum);
-					 }
-				 }
-			 } catch (Exception e) {
-				 log.error("解析stackLength失败: {}", jsonStr, e);
-			 }
-		 }
-	 }
-
-	 /**
-	  * 处理rollClubOneDetails字段,合并相同定尺
-	  */
-	 private void processRollClubOneDetails(String jsonStr, Map<String, Integer> lengthCountMap) {
-		 if (oConvertUtils.isNotEmpty(jsonStr)) {
-			 try {
-				 JSONObject jsonObj = JSON.parseObject(jsonStr);
-				 JSONObject lengthGroupCount = jsonObj.getJSONObject("lengthGroupCount");
-
-				 if (lengthGroupCount != null) {
-					 for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
-						 String length = entry.getKey();
-						 Integer count = Integer.valueOf(entry.getValue().toString());
-
-						 // 使用merge方法自动合并相同定尺
-						 lengthCountMap.merge(length, count, Integer::sum);
-					 }
-				 }
-			 } catch (Exception e) {
-				 log.error("解析rollClubOneDetails失败: {}", jsonStr, e);
-			 }
-		 }
-	 }
-
-	 /**
-	  * 5#棒一、6#高线统计明细查询
-	  * @param ccmNo
-	  * @param changeShiftId
-	  * @return
-	  */
-	 private List<BilletDetailsInfo> queryRollClubOneStatistics(String ccmNo, String changeShiftId, String queryDate, String heatNo, String startTimes, String endTimes) {
-		 List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
-		 LambdaQueryWrapper<BilletOriginalProductRecord> queryWrapper = new LambdaQueryWrapper<>();
-		 queryWrapper.eq(BilletOriginalProductRecord::getCcmNo, ccmNo);
-		 Boolean search = true; // 定义未传任何条件
-		 if(oConvertUtils.isNotEmpty(changeShiftId)) { // 班组为空取班组时间
-			 // 根据铸机号、交班记录ID,获取交班记录中的班别、班次、创建时间
-			 LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
-			 changeQueryWrapper.eq(BilletHotsendChangeShift::getId, changeShiftId).eq(BilletHotsendChangeShift::getCcmNo, ccmNo);
-			 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
-			 if (billetHotsendChangeShift == null){
-				 log.info("{}{}", "查询指定班次,交班记录为空!", ccmNo + "交班ID:" + changeShiftId);
-				 return billetDetailsInfoList;
-			 }
-			 String shift = billetHotsendChangeShift.getShift();
-			 String shiftGroup = billetHotsendChangeShift.getShiftGroup();
-			 Date startTime = billetHotsendChangeShift.getCreateTime();
-			 Date endTime = oConvertUtils.isNotEmpty(billetHotsendChangeShift.getChangeShiftTime()) ? billetHotsendChangeShift.getChangeShiftTime() : new Date();
-			 queryWrapper.eq(BilletOriginalProductRecord::getShift, shift);
-			 queryWrapper.eq(BilletOriginalProductRecord::getShiftGroup, shiftGroup);
-			 queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTime, endTime);
-			 search = false;
-		 } else if(oConvertUtils.isNotEmpty(startTimes) && oConvertUtils.isNotEmpty(endTimes)){ // 时间范围
-			 queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTimes, endTimes);
-			 search = false;
-		 }
-		 if (oConvertUtils.isNotEmpty(queryDate) || search == true) { // 独立时间处理
-			 // 如果时间给了空
-			 if(oConvertUtils.isEmpty(queryDate)) { // 查询最后一个班次
-				 String nowDate = DateUtils.getDate("yyyy-MM-dd");
-				 Date startOneTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(nowDate));
-				 // 查询最后一次交班记录时间
-				 LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
-				 changeQueryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo).orderByDesc(BilletHotsendChangeShift::getCreateTime).last("limit 1");
-				 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
-				 queryWrapper.ge(BilletOriginalProductRecord::getCreateTime, oConvertUtils.isNotEmpty(billetHotsendChangeShift.getCreateTime()) ? billetHotsendChangeShift.getCreateTime() : startOneTime);
-			 }else{
-				 queryDate = oConvertUtils.isNotEmpty(queryDate) ? queryDate : DateUtils.getDate("yyyy-MM-dd");
-				 Date startTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(queryDate));
-				 Date endTime = DateUtils.getEndOfDayByDate(startTime);
-				 queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTime, endTime);
-			 }
-		 }
-		 // 炉号查询
-		 if (oConvertUtils.isNotEmpty(heatNo)) {
-			 queryWrapper.like(BilletOriginalProductRecord::getHeatNo, heatNo);
-		 }
-
-		 List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper);
-		 if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
-			 log.info("{}{}", "查询数据为空!");
-			 BilletDetailsInfo info = new BilletDetailsInfo();
-			 info.setCcmNo(ccmNo);
-			 info.setCounts(0);
-			 info.setTotalWeight(0.00);
-			 List<BilletStatisticsDetail> detailsList = new ArrayList<>();
-			 info.setBilletStatisticList(detailsList);
-			 billetDetailsInfoList.add(info);
-			 return billetDetailsInfoList;
-		 }
-		 Map<String, BilletStatisticsDetail> statisticsMap = new HashMap<>();
-
-		 double grandTotalWeight = 0.0d;
-
-		 for (BilletOriginalProductRecord record : billetOriginalProductRecordList) {
-			 String rollClubOneDetails = record.getRollClubOneDetails();
-			 if (rollClubOneDetails != null && !rollClubOneDetails.isEmpty()) {
-				 try {
-					 JSONObject detailsJson = JSON.parseObject(rollClubOneDetails);
-					 JSONObject lengthGroupCount = detailsJson.getJSONObject("lengthGroupCount");
-					 if (lengthGroupCount != null) {
-						 for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
-							 String size = entry.getKey();
-							 // 增加类型检查,避免潜在的空指针异常
-							 int count = Integer.parseInt(entry.getValue().toString());
-							 double sizeValue = Double.parseDouble(size);
-							 updateStatistics(statisticsMap, size, count, sizeValue);
-						 }
-					 }
-				 } catch (Exception e) {
-					 log.error("解析rollClubOneDetails、rollHeightDetails失败: {}", rollClubOneDetails, e);
-				 }
-			 }
-		 }
-
-		 // 计算总数量和总重量
-		 int grandTotalCount = statisticsMap.values().stream()
-				 .mapToInt(BilletStatisticsDetail::getAmountTotal) // 修改为 getAmountTotal()
-				 .sum();
-		 grandTotalWeight = statisticsMap.values().stream()
-				 .mapToDouble(BilletStatisticsDetail::getBlankOutput)
-				 .sum();
-
-		 if (!statisticsMap.isEmpty()) {
-			 BilletDetailsInfo info = new BilletDetailsInfo();
-			 info.setCcmNo(ccmNo);
-			 info.setCounts(grandTotalCount);
-			 info.setTotalWeight(grandTotalWeight);
-			 List<BilletStatisticsDetail> detailsList = new ArrayList<>(statisticsMap.values());
-			 info.setBilletStatisticList(detailsList);
-			 billetDetailsInfoList.add(info);
-		 }
-		 return billetDetailsInfoList;
-	 }
-
-	 /**
-	  * 装运单统计明细查询
-	  * @param ccmNo
-	  * @param queryDate
-	  * @return
-	  */
-	 private List<BilletDetailsInfo> querSstorageBillPrintStatistics(String ccmNo, String destination, String queryDate, String changeShiftId, String heatNo, String licensePlate, String startTimes, String endTimes, String sizes, String btype, String brandNum) {
-		 List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
-		 // 根据铸机号、开始时间、结束时间查询查询装运单打印表
-		 LambdaQueryWrapper<StorageBillPrint> queryWrapper = new LambdaQueryWrapper<>();
-		 queryWrapper.eq(StorageBillPrint::getCcmNo, ccmNo)
-				 .eq(StorageBillPrint::getDestination, destination)
-				 .orderByDesc(StorageBillPrint::getArrivalTime);
-		 Boolean search = true; // 定义未传任何条件
-		 if(oConvertUtils.isNotEmpty(changeShiftId)) { // 班组为空取班组时间
-			 // 根据铸机号、交班记录ID,获取交班记录中的班别、班次、创建时间
-			 LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
-			 changeQueryWrapper.eq(BilletHotsendChangeShift::getId, changeShiftId).eq(BilletHotsendChangeShift::getCcmNo, ccmNo);
-			 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
-			 if (billetHotsendChangeShift == null){
-				 log.info("{}{}", "查询指定班次,交班记录为空!", ccmNo + "交班ID:" + changeShiftId);
-				 return billetDetailsInfoList;
-			 }
-			 String shift = billetHotsendChangeShift.getShift();
-			 String shiftGroup = billetHotsendChangeShift.getShiftGroup();
-			 Date startTime = billetHotsendChangeShift.getCreateTime();
-			 Date endTime = oConvertUtils.isNotEmpty(billetHotsendChangeShift.getChangeShiftTime()) ? billetHotsendChangeShift.getChangeShiftTime() : new Date();
-			 String shiftAndShiftGroup = shift + "/" + shiftGroup;
-			 queryWrapper.between(StorageBillPrint::getArrivalTime, startTime, endTime).eq(StorageBillPrint::getClasses, shiftAndShiftGroup);
-			 search = false;
-		 } else if(oConvertUtils.isNotEmpty(startTimes) && oConvertUtils.isNotEmpty(endTimes)){ // 时间范围
-			 queryWrapper.between(StorageBillPrint::getArrivalTime, startTimes, endTimes);
-			 search = false;
-		 }
-		 if ((oConvertUtils.isNotEmpty(queryDate)) || search == true) { // 独立时间处理
-			 // 如果时间给了空
-			 if(oConvertUtils.isEmpty(queryDate)) { // 查询最后一个班次
-				 String nowDate = DateUtils.getDate("yyyy-MM-dd");
-				 Date startArrivalTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(nowDate));
-				 // 查询最后一次交班记录时间
-				 LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
-				 changeQueryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo).orderByDesc(BilletHotsendChangeShift::getCreateTime).last("limit 1");
-				 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
-				 // 查询确认时间为 null 或者  班次记录
-				 queryWrapper.and(wrapper ->
-						 wrapper
-								 .isNull(StorageBillPrint::getConfirmTime)
-								 .or(
-										 wrapper2 -> wrapper2
-												 .ge(StorageBillPrint::getArrivalTime, oConvertUtils.isNotEmpty(billetHotsendChangeShift.getCreateTime()) ? billetHotsendChangeShift.getCreateTime() : startArrivalTime)
-								 )
-				 );
-			 }else{
-				 Date startTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(queryDate));
-				 Date endTime = DateUtils.getEndOfDayByDate(startTime);
-				 queryWrapper.between(StorageBillPrint::getArrivalTime, startTime, endTime);
-			 }
-		 }
-		 // 炉号查询
-		 if (oConvertUtils.isNotEmpty(heatNo)) {
-			 queryWrapper.like(StorageBillPrint::getHeatNo, heatNo);
-		 }
-		 // 车牌号查询
-		 if (oConvertUtils.isNotEmpty(licensePlate)) {
-			 queryWrapper.eq(StorageBillPrint::getLicensePlate, licensePlate);
-		 }
-		 // 定尺
-		 if (oConvertUtils.isNotEmpty(sizes)) {
-			 queryWrapper.eq(StorageBillPrint::getSize, sizes);
-		 }
-		 // 热凉
-		 if (oConvertUtils.isNotEmpty(btype)) {
-			 queryWrapper.eq(StorageBillPrint::getBtype, btype);
-		 }
-		 // 牌号
-		 if (oConvertUtils.isNotEmpty(brandNum)) {
-			 queryWrapper.eq(StorageBillPrint::getBrandNum, brandNum);
-		 }
-
-		 List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(queryWrapper);
-		 if (oConvertUtils.listIsEmpty(storageBillPrintList)) {
-			 log.info("{}", "工作台统计明细查询数据为空!");
-			 return billetDetailsInfoList;
-		 }
-		 // 创建并初始化BilletDetailsInfo对象
-		 BilletDetailsInfo billetDetailsInfo = new BilletDetailsInfo();
-		 billetDetailsInfo.setCcmNo(ccmNo); // 设置铸机号
-
-		 // 按定尺(size)分组统计
-		 Map<String, List<StorageBillPrint>> sizeGroupMap = storageBillPrintList.stream()
-				 .filter(item -> item.getSize() != null && item.getAmountTotal() != null)
-				 .collect(Collectors.groupingBy(StorageBillPrint::getSize));
-
-		 // 计算每个分组的统计结果
-		 List<BilletStatisticsDetail> statisticsDetails = new ArrayList<>();
-		 for (Map.Entry<String, List<StorageBillPrint>> entry : sizeGroupMap.entrySet()) {
-			 String size = entry.getKey();
-			 List<StorageBillPrint> groupItems = entry.getValue();
-
-			 // 计算总支数
-			 Integer totalAmount = groupItems.stream()
-					 .mapToInt(StorageBillPrint::getAmountTotal)
-					 .sum();
-
-			 // 计算总重量: (size/1000) * amountTotal * 0.2265,保留4位小数
-			 double totalWeight = groupItems.stream()
-					 .filter(item -> item.getAmountTotal() != null)
-					 .mapToDouble(item -> {
-						 try {
-							 double sizeValue = Double.parseDouble(size);
-							 return (sizeValue / 1000) * item.getAmountTotal() * 0.2265;
-						 } catch (NumberFormatException e) {
-							 return 0.0;
-						 }
-					 }).sum();
-
-			 // 保留4位小数
-			 totalWeight = Math.round(totalWeight * 10000.0) / 10000.0;
-
-			 // 创建统计明细对象并添加到结果列表
-			 BilletStatisticsDetail detail = new BilletStatisticsDetail(totalAmount, totalWeight, size);
-			 statisticsDetails.add(detail);
-		 }
-
-		 // 设置统计结果到BilletDetailsInfo对象
-		 billetDetailsInfo.setBilletStatisticList(statisticsDetails);
-
-		 // 计算并设置总车次、总支数和总重量
-		 billetDetailsInfo.setAllCarNum(storageBillPrintList.size()); // 总车次为记录数
-		 billetDetailsInfo.setCounts(statisticsDetails.stream().mapToInt(BilletStatisticsDetail::getAmountTotal).sum());
-		 billetDetailsInfo.setTotalWeight(statisticsDetails.stream().mapToDouble(BilletStatisticsDetail::getBlankOutput).sum());
-
-		 // 添加到结果列表
-		 billetDetailsInfoList.add(billetDetailsInfo);
-
-		 return billetDetailsInfoList;
-	 }
-
-	 /**
-	  * 筛选指定流号的数据
-	  * @param billetList 钢坯信息列表
-	  * @param strandNo 流号
-	  * @return 指定流号的钢坯信息列表
-	  */
-	 private List<BilletBasicInfo> filterByStrandNo(List<BilletBasicInfo> billetList, Integer strandNo) {
-		 if (CollectionUtils.isEmpty(billetList) || strandNo == null) {
-			 return Collections.emptyList();
-		 }
-
-		 return billetList.stream()
-				 .filter(info -> info.getStrandNo() != null && info.getStrandNo().equals(strandNo))
-				 .collect(Collectors.toList());
-	 }
-
-	 /**
-	  * 按定尺长度分组并统计数量
-	  * @param billetList 钢坯信息列表
-	  * @return 定尺长度到数量的映射
-	  */
-	 private Map<String, Long> groupByLength(List<BilletBasicInfo> billetList) {
-		 if (CollectionUtils.isEmpty(billetList)) {
-			 return Collections.emptyMap();
-		 }
-
-		 return billetList.stream()
-				 .filter(info -> info.getLength() != null)
-				 .collect(Collectors.groupingBy(
-						 info -> String.valueOf(info.getLength()),
-						 Collectors.counting()
-				 ));
-	 }
-
-
-	 /**
-	  * 将总数按顺序循环分配到指定数量的流中
-	  * @param total 总数
-	  * @param numStrands 流的数量
-	  * @return 分配结果映射(键为流的名称,值为分配的数量)
-	  */
-	 private Map<String, Integer> allocateRandomly(int total, int numStrands) {
-		 // 初始化每个流分配0个
-		 List<Integer> allocation = new ArrayList<>(Collections.nCopies(numStrands, 0));
-
-		 // 按顺序循环分配所有数量
-		 for (int i = 0; i < total; i++) {
-			 // 计算当前应该分配的流索引(循环使用)
-			 int index = i % numStrands;
-			 allocation.set(index, allocation.get(index) + 1);
-		 }
-
-		 // 构建结果映射
-		 Map<String, Integer> result = new HashMap<>();
-		 result.put("oneStrandSum", numStrands > 0 ? allocation.get(0) : 0);
-		 result.put("twoStrandSum", numStrands > 1 ? allocation.get(1) : 0);
-		 result.put("threeStrandSum", numStrands > 2 ? allocation.get(2) : 0);
-		 result.put("fourStrandSum", numStrands > 3 ? allocation.get(3) : 0);
-		 result.put("fiveStrandSum", numStrands > 4 ? allocation.get(4) : 0);
-		 result.put("sixStrandSum", numStrands > 5 ? allocation.get(5) : 0);
-		 result.put("sevenStrandSum", numStrands > 6 ? allocation.get(6) : 0);
-		 result.put("eightStrandSum", numStrands > 7 ? allocation.get(7) : 0);
-
-		 return result;
-	 }
-
-	 private void applyConfirmInfo(BilletOriginalProductRecord record, LoginUser user) {
-		 if (oConvertUtils.isNotEmpty(record.getConfirmTime())) {
-			 record.setConfirmBy(user.getRealname());
-			 record.setConfirmTime(new Date());
-			 record.setRemark(record.getRemark());
-		 }
-	 }
-
-	 // 提取的计算方法
-	 private void updateStatistics(Map<String, BilletStatisticsDetail> statisticsMap,
-								   String size, int count, double sizeValue) {
-		 statisticsMap.compute(size, (k, v) -> {
-			 // 计算weight
-			 double localWeight = (sizeValue / 1000) * count * 0.2265;
-			 localWeight = BigDecimal.valueOf(localWeight)
-					 .setScale(4, RoundingMode.HALF_UP)
-					 .doubleValue();
-			 
-			 BilletStatisticsDetail detail = v != null ? v : new BilletStatisticsDetail(count, localWeight, size);
-
-			 if (v != null) {
-				 detail.setAmountTotal(detail.getAmountTotal() + count);
-				 detail.setBlankOutput(detail.getBlankOutput() + localWeight);
-			 }
-			 return detail;
-		 });
-	 }
-
-	 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 count 需要计算的位置数量
-	  * @return 包含可用位置的对象列表
-	  */
-	 private List<StackingAndLoadingVehicles> calculateNextPositions(
-			 StackingAndLoadingVehicles highAddressSALV,
-			 int count,
-			 String ccmNo,
-			 String typeConfigId) {
-
-		 List<StackingAndLoadingVehicles> nextPositions = new ArrayList<>();
-
-		 // 获取参考位置的address和layer
-		 int currentAddress = Integer.valueOf(highAddressSALV.getAddress());
-		 int currentLayer =  Integer.valueOf(highAddressSALV.getLayer());
-
-		 // 如果参考位置为空(首次起垛),从1.1开始
-		 if (currentAddress == 0 && currentLayer == 0) {
-			 currentAddress = 1;
-			 currentLayer = 1;
-		 } else {
-			 // 从参考位置的下一个位置开始计算
-			 if (currentAddress == 9) {
-				 currentAddress = 1;
-				 currentLayer++;
-			 } else {
-				 currentAddress++;
-			 }
-		 }
-
-		 // 生成指定数量的位置
-		 for (int i = 0; i < count; i++) {
-			 // 检查是否超出最大层数
-			 if (currentLayer > 20) {
-				 log.warn("已超出最大层数(20),无法生成更多位置");
-				 break;
-			 }
-
-			 // 创建新位置
-			 StackingAndLoadingVehicles newPosition = new StackingAndLoadingVehicles();
-			 newPosition.setCcmNo(ccmNo);
-			 newPosition.setAddress(String.valueOf(currentAddress));
-			 newPosition.setLayer(String.valueOf(currentLayer));
-			 newPosition.setTypeConfigId(typeConfigId);
-
-			 nextPositions.add(newPosition);
-
-			 // 更新下一个位置的address和layer
-			 if (currentAddress == 9) {
-				 currentAddress = 1;
-				 currentLayer++;
-			 } else {
-				 currentAddress++;
-			 }
-		 }
-
-		 return nextPositions;
-	 }
-
-
-	 /**
-	  * 生成短格式唯一坯号(炉号+铸机号+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);
-	 }
-
-
-	 /**
-	  * 生成综合唯一编码
-	  * @param  date
-	  * @param  ccmNo
-	  * @param  shift
-	  * @param  shiftGroup
-	  * @return uniqueCode
-	  */
-	 public String generateUniqueCode(Date date, String ccmNo, String shift, String shiftGroup) {
-		 // 将日期转换为指定格式的字符串
-		 String dateStr = DateUtils.date2Str(date, DateUtils.yyyymmddhhmmss.get());
-		 // 将 shift 转换为 ShiftEnum 的名称
-		 String shiftName = ShiftEnum.fromCode(shift).name();
-		 // 将 shiftGroup 转换为 ShiftGroupEnum 的名称
-		 String shiftGroupName = ShiftGroupEnum.fromCode(shiftGroup).name();
-		 // 组合生成唯一代码
-		 String uniqueCode = dateStr + "-" + ccmNo + "#" + shiftName + "-" + shiftGroupName;
-		 return uniqueCode;
-	 }
-
-	 /**
-	  * 从Redis中获取班组班别
-	  * @param ccmNo
-	  * @param keyFormat
-	  * @return
-	  */
-	 private String getShiftInfo(String ccmNo, String keyFormat) {
-		 String key = String.format(keyFormat, ccmNo);
-		 return oConvertUtils.getString(redisTemplate.opsForValue().get(key));
-	 }
-
-	 /**
-	  * 更新交班记录
-	  * @param ccmNo
-	  * @param shiftGroup
-	  * @param shift
-	  */
-	 private void updateBilletHotsendChangeShift(String ccmNo, String shiftGroup, String shift) {
-		 LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
-		 queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
-				 .eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
-				 .eq(BilletHotsendChangeShift::getShift, shift)
-				 .isNull(BilletHotsendChangeShift::getChangeShiftTime)
-				 .orderByDesc(BilletHotsendChangeShift::getCreateTime)
-				 .last("limit 1");
-		 BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
-		 if (oConvertUtils.isEmpty(billetHotsendChangeShift)) {
-			 log.info("推钢室界面创建装运单交班记录不存在,车次数维护失败:{}", ccmNo+shiftGroup+shift);
-			 return;
-		 }
-		 billetHotsendChangeShift.setOutCarNum(billetHotsendChangeShift.getOutCarNum() + 1);
-		 billetHotsendChangeShiftService.updateById(billetHotsendChangeShift);
-	 }
- }
+		LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
+				.eq(BilletHotsendChangeShift::getShift, shift)
+				.eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
+				.isNull(BilletHotsendChangeShift::getChangeShiftTime)
+				.orderByDesc(BilletHotsendChangeShift::getCreateTime)
+				.last("limit 1");
+		BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+		if (billetHotsendChangeShift == null){
+			return Result.error("交班记录为空,查询失败!");
+		}
+
+		Date startTime = billetHotsendChangeShift.getCreateTime();
+		Date endTime = new Date();
+
+		// 通过铸机号、开始时间、结束时间查询 钢坯原始生产记录
+		QueryWrapper<BilletOriginalProductRecord> queryWrapper1 = new QueryWrapper<>();
+		queryWrapper1.eq("ccm_no", ccmNo);
+		queryWrapper1.eq("shift", shift);
+		queryWrapper1.eq("shift_group", shiftGroup);
+		queryWrapper1.between("create_time", startTime, endTime);
+		queryWrapper1.orderByDesc("create_time");
+		List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper1);
+		if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
+			return Result.OK(billetOriginalInfo);
+		}
+		String directRollingJson = calculateDirectRollingStatistics(billetOriginalProductRecordList);
+		// 统计5#直轧棒一、6#热送高线
+		billetOriginalInfo.setDirectRolling(directRollingJson);
+
+		// 根据铸机号、开始时间、结束时间查询查询装运单打印表
+		String hotChargeJson = "";
+		String shiftAndShiftGroup = shift + "/" + shiftGroup;
+		LambdaQueryWrapper<StorageBillPrint> querySbWrapper = new LambdaQueryWrapper<>();
+		querySbWrapper.eq(StorageBillPrint::getCcmNo, ccmNo)
+				.eq(StorageBillPrint::getClasses, shiftAndShiftGroup)
+				.between(StorageBillPrint::getCreateTime, startTime, endTime)
+				.orderByDesc(StorageBillPrint::getCreateTime);
+		List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(querySbWrapper);
+		if (oConvertUtils.listIsNotEmpty(storageBillPrintList)) {
+			hotChargeJson = calculateHotChargeStatistics(storageBillPrintList);
+			// 统计热装
+			billetOriginalInfo.setHotCharge(hotChargeJson);
+		}
+		String stackingJson = calculateStackingStatistics(billetOriginalProductRecordList);
+		// 统计堆垛
+		billetOriginalInfo.setStacking(stackingJson);
+
+		// 计算总重量
+		double totalWeight = calculateTotalWeight(directRollingJson, hotChargeJson, stackingJson);
+		billetOriginalInfo.setBlankOutputs(totalWeight);
+
+		String brandNum = String.format("billet:basic:info:brand:num:%s", ccmNo); // 牌号
+		String brandNumStr = !oConvertUtils.getString(redisTemplate.opsForValue().get(brandNum)).isEmpty() ? oConvertUtils.getString(redisTemplate.opsForValue().get(brandNum)) : "";
+		billetOriginalInfo.setBrandNum(brandNumStr);
+
+		billetOriginalInfo.setShift(shift);
+		billetOriginalInfo.setShiftGroup(shiftGroup);
+
+		// 遍历billetOriginalProductRecordList,获取BilletOriginalProductRecord中的三个json字段, hotChargeLength、stackLength、rollClubOneDetails,对所有定尺进行统计,统计出定尺、和对应的数量
+		billetOriginalProductRecordList.forEach(y ->{
+			Map<String, Integer> lengthCountMap = new HashMap<>();
+			// 处理热装所有定尺字段
+			processHotChargeLength(y.getHotChargeLength(), lengthCountMap);
+
+			// 处理堆垛所有定尺字段
+			processStackLength(y.getStackLength(), lengthCountMap);
+
+			// 处理5#棒一、6#热送高线 所有定尺字段
+			processRollClubOneDetails(y.getRollClubOneDetails(), lengthCountMap);
+
+			y.setLengthDetails(JSON.toJSONString(lengthCountMap));
+		});
+
+		billetOriginalInfo.setBilletOriginalProductRecordList(billetOriginalProductRecordList);
+		billetOriginalInfo.setTotalInfo(billetOriginalProductRecordList.stream().filter(x -> x.getAmount() != null)
+				.mapToInt(BilletOriginalProductRecord::getAmount)
+				.sum());
+		return Result.OK(billetOriginalInfo);
+	}
+	/**
+	 * 计算5#直轧棒一、6#高线的统计信息
+	 */
+	private String calculateDirectRollingStatistics(List<BilletOriginalProductRecord> records) {
+		// 用于存储统计结果的Map,键为定尺,值为数量和重量
+		Map<String, LengthStatistics> lengthStatsMap = new HashMap<>();
+
+		// 遍历所有记录
+		for (BilletOriginalProductRecord record : records) {
+			String rollClubOneDetails = record.getRollClubOneDetails();
+			if (oConvertUtils.isNotEmpty(rollClubOneDetails)) {
+				try {
+					// 解析JSON字符串
+					JSONObject detailsJson = JSON.parseObject(rollClubOneDetails);
+					// 获取lengthGroupCount对象
+					JSONObject lengthGroupCount = detailsJson.getJSONObject("lengthGroupCount");
+					if (lengthGroupCount != null) {
+						// 遍历每个定尺及其数量
+						for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
+							String length = entry.getKey();
+							Integer count = Integer.valueOf(entry.getValue().toString());
+							// 累加到统计结果中
+							lengthStatsMap.computeIfAbsent(length, k -> new LengthStatistics()).addCount(count);
+						}
+					}
+				} catch (Exception e) {
+					log.error("解析rollClubOneDetails、rollHeightDetails失败: {}", rollClubOneDetails, e);
+					// 忽略解析失败的记录,继续处理其他记录
+				}
+			}
+		}
+
+		// 计算总重量并构建结果
+		JSONObject resultJson = new JSONObject();
+		JSONObject lengthGroupCountJson = new JSONObject();
+		BigDecimal totalWeight = BigDecimal.ZERO;
+		int totalCount = 0;
+
+		// 计算每个定尺的重量并累加总重量
+		for (Map.Entry<String, LengthStatistics> entry : lengthStatsMap.entrySet()) {
+			String length = entry.getKey();
+			LengthStatistics stats = entry.getValue();
+
+			// 计算当前定尺的总重量
+			BigDecimal size = new BigDecimal(length);
+			BigDecimal weight = size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
+					.multiply(new BigDecimal(stats.getCount()))
+					.multiply(new BigDecimal("0.2265"))
+					.setScale(4, RoundingMode.HALF_UP);
+
+			// 更新统计信息
+			stats.setWeight(weight);
+			totalWeight = totalWeight.add(weight);
+			totalCount += stats.getCount();
+
+			// 构建定尺统计JSON
+			JSONObject lengthStatsJson = new JSONObject();
+			lengthStatsJson.put("count", stats.getCount());
+			lengthStatsJson.put("weight", weight.toPlainString());
+			lengthGroupCountJson.put(length, lengthStatsJson);
+		}
+
+		// 设置最终结果
+		resultJson.put("lengthGroupCount", lengthGroupCountJson);
+		resultJson.put("directRollingTotalCount", totalCount);
+		resultJson.put("directRollingTotalWeight", totalWeight.toPlainString());
+
+		return resultJson.toJSONString();
+	}
+
+	/**
+	 * 计算热装的统计信息
+	 */
+	private String calculateHotChargeStatistics(List<StorageBillPrint> storageBillPrintList) {
+		// 用于存储统计结果的Map,键为size,值为统计信息
+		Map<String, SizeStatistics> sizeStatsMap = new HashMap<>();
+
+		// 遍历所有记录
+		for (StorageBillPrint print : storageBillPrintList) {
+			String size = print.getSize();
+			if (oConvertUtils.isNotEmpty(size)) {
+				try {
+					// 转换为数值并验证
+					BigDecimal sizeDecimal = new BigDecimal(size.trim());
+
+					// 累加数量和计算重量
+					sizeStatsMap.computeIfAbsent(size, k -> new SizeStatistics())
+							.addData(1, calculateWeight(sizeDecimal, 1));
+				} catch (NumberFormatException e) {
+					log.error("无效的size值: {}", size, e);
+					// 忽略无效的size值,继续处理其他值
+				}
+			}
+		}
+
+		// 构建结果JSON (保持原有逻辑不变)
+		JSONObject resultJson = new JSONObject();
+		JSONObject sizeGroupJson = new JSONObject();
+		int totalCount = 0;
+		BigDecimal totalWeight = BigDecimal.ZERO;
+
+		// 处理统计结果
+		for (Map.Entry<String, SizeStatistics> entry : sizeStatsMap.entrySet()) {
+			String size = entry.getKey();
+			SizeStatistics stats = entry.getValue();
+
+			// 构建单个size的统计JSON
+			JSONObject sizeStatsJson = new JSONObject();
+			sizeStatsJson.put("count", stats.getCount());
+			sizeStatsJson.put("weight", stats.getWeight().toPlainString());
+
+			// 添加到结果中
+			sizeGroupJson.put(size, sizeStatsJson);
+			totalCount += stats.getCount();
+			totalWeight = totalWeight.add(stats.getWeight());
+		}
+
+		// 设置最终结果
+		resultJson.put("sizeGroupCount", sizeGroupJson);
+		resultJson.put("totalCount", totalCount);
+		resultJson.put("totalWeight", totalWeight.toPlainString());
+		return resultJson.toJSONString();
+	}
+	/**
+	 * 计算堆垛信息的统计
+	 */
+	private String calculateStackingStatistics(List<BilletOriginalProductRecord> records) {
+		// 用于存储统计结果的Map,键为定尺,值为统计信息
+		Map<String, SizeStatistics> stackingStatsMap = new HashMap<>();
+
+		// 遍历所有记录
+		for (BilletOriginalProductRecord record : records) {
+			String stackLengthJson = record.getStackLength();
+			if (oConvertUtils.isNotEmpty(stackLengthJson)) {
+				try {
+					// 解析JSON数组
+					JSONArray stackLengthArray = JSON.parseArray(stackLengthJson);
+
+					// 遍历每个堆垛信息
+					for (int i = 0; i < stackLengthArray.size(); i++) {
+						JSONObject stackItem = stackLengthArray.getJSONObject(i);
+
+						// 获取堆垛长度和数量
+						String length = stackItem.getString("stackingLength");
+						Integer count = stackItem.getInteger("stackingCount");
+						BigDecimal weight = stackItem.getBigDecimal("stackingWeight");
+
+						if (length != null && count != null && weight != null) {
+							// 累加到统计结果中
+							stackingStatsMap.computeIfAbsent(length, k -> new SizeStatistics()).addData(count, weight);
+						}
+					}
+				} catch (Exception e) {
+					log.error("解析stackLength失败: {}", stackLengthJson, e);
+					// 忽略解析失败的记录,继续处理其他记录
+				}
+			}
+		}
+
+		// 构建结果JSON
+		JSONObject resultJson = new JSONObject();
+		JSONObject lengthGroupJson = new JSONObject();
+		int totalCount = 0;
+		BigDecimal totalWeight = BigDecimal.ZERO;
+
+		// 处理统计结果
+		for (Map.Entry<String, SizeStatistics> entry : stackingStatsMap.entrySet()) {
+			String length = entry.getKey();
+			SizeStatistics stats = entry.getValue();
+
+			// 构建单个定尺的统计JSON
+			JSONObject lengthStatsJson = new JSONObject();
+			lengthStatsJson.put("count", stats.getCount());
+			lengthStatsJson.put("weight", stats.getWeight().toPlainString());
+
+			// 添加到结果中
+			lengthGroupJson.put(length, lengthStatsJson);
+			totalCount += stats.getCount();
+			totalWeight = totalWeight.add(stats.getWeight());
+		}
+
+		// 设置最终结果
+		resultJson.put("lengthGroupCount", lengthGroupJson);
+		resultJson.put("stackingTotalCount", totalCount);
+		resultJson.put("stackingTotalWeight", totalWeight.toPlainString());
+
+		return resultJson.toJSONString();
+	}
+	/**
+	 * 从三个JSON中提取总重量并计算总和
+	 */
+	private double calculateTotalWeight(String directRollingJson, String hotChargeJson, String stackingJson) {
+		BigDecimal total = BigDecimal.ZERO;
+		// 从直轧统计中提取总重量
+		if (oConvertUtils.isNotEmpty(directRollingJson)) {
+			try {
+				JSONObject json = JSON.parseObject(directRollingJson);
+				String weightStr = json.getString("directRollingTotalWeight");
+				if (oConvertUtils.isNotEmpty(weightStr)) {
+					total = total.add(new BigDecimal(weightStr));
+				}
+			} catch (Exception e) {
+				log.error("从directRollingJson提取总重量失败", e);
+			}
+		}
+
+		// 从热装统计中提取总重量
+		if (oConvertUtils.isNotEmpty(hotChargeJson)) {
+			try {
+				JSONObject json = JSON.parseObject(hotChargeJson);
+				String weightStr = json.getString("totalWeight");
+				if (oConvertUtils.isNotEmpty(weightStr)) {
+					total = total.add(new BigDecimal(weightStr));
+				}
+			} catch (Exception e) {
+				log.error("从hotChargeJson提取总重量失败", e);
+			}
+		}
+
+		// 从堆垛统计中提取总重量
+		if (oConvertUtils.isNotEmpty(stackingJson)) {
+			try {
+				JSONObject json = JSON.parseObject(stackingJson);
+				String weightStr = json.getString("stackingTotalWeight");
+				if (oConvertUtils.isNotEmpty(weightStr)) {
+					total = total.add(new BigDecimal(weightStr));
+				}
+			} catch (Exception e) {
+				log.error("从stackingJson提取总重量失败", e);
+			}
+		}
+		// 转换为double类型,保留4位小数
+		return total.setScale(4, RoundingMode.HALF_UP).doubleValue();
+	}
+	// 保持原有计算方法不变
+	private BigDecimal calculateWeight(BigDecimal size, int count) {
+		return size.divide(new BigDecimal("1000"), 4, RoundingMode.HALF_UP)
+				.multiply(new BigDecimal(count))
+				.multiply(new BigDecimal("0.2265"))
+				.setScale(4, RoundingMode.HALF_UP);
+	}
+
+	/**
+	 * 处理hotChargeLength字段,合并相同定尺
+	 */
+	private void processHotChargeLength(String jsonStr, Map<String, Integer> lengthCountMap) {
+		if (oConvertUtils.isNotEmpty(jsonStr)) {
+			try {
+				JSONArray jsonArray = JSON.parseArray(jsonStr);
+				for (int i = 0; i < jsonArray.size(); i++) {
+					JSONObject item = jsonArray.getJSONObject(i);
+					String length = item.getString("hotChargeLength");
+					Integer count = item.getInteger("totalCount");
+
+					if (length != null && count != null) {
+						// 使用merge方法自动合并相同定尺
+						lengthCountMap.merge(length, count, Integer::sum);
+					}
+				}
+			} catch (Exception e) {
+				log.error("解析hotChargeLength失败: {}", jsonStr, e);
+			}
+		}
+	}
+
+	/**
+	 * 处理stackLength字段,合并相同定尺
+	 */
+	private void processStackLength(String jsonStr, Map<String, Integer> lengthCountMap) {
+		if (oConvertUtils.isNotEmpty(jsonStr)) {
+			try {
+				JSONArray jsonArray = JSON.parseArray(jsonStr);
+				for (int i = 0; i < jsonArray.size(); i++) {
+					JSONObject item = jsonArray.getJSONObject(i);
+					String length = item.getString("stackingLength");
+					Integer count = item.getInteger("stackingCount");
+
+					if (length != null && count != null) {
+						// 使用merge方法自动合并相同定尺
+						lengthCountMap.merge(length, count, Integer::sum);
+					}
+				}
+			} catch (Exception e) {
+				log.error("解析stackLength失败: {}", jsonStr, e);
+			}
+		}
+	}
+
+	/**
+	 * 处理rollClubOneDetails字段,合并相同定尺
+	 */
+	private void processRollClubOneDetails(String jsonStr, Map<String, Integer> lengthCountMap) {
+		if (oConvertUtils.isNotEmpty(jsonStr)) {
+			try {
+				JSONObject jsonObj = JSON.parseObject(jsonStr);
+				JSONObject lengthGroupCount = jsonObj.getJSONObject("lengthGroupCount");
+
+				if (lengthGroupCount != null) {
+					for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
+						String length = entry.getKey();
+						Integer count = Integer.valueOf(entry.getValue().toString());
+
+						// 使用merge方法自动合并相同定尺
+						lengthCountMap.merge(length, count, Integer::sum);
+					}
+				}
+			} catch (Exception e) {
+				log.error("解析rollClubOneDetails失败: {}", jsonStr, e);
+			}
+		}
+	}
+
+	/**
+	 * 5#棒一、6#高线统计明细查询
+	 * @param ccmNo
+	 * @param changeShiftId
+	 * @return
+	 */
+	private List<BilletDetailsInfo> queryRollClubOneStatistics(String ccmNo, String changeShiftId, String queryDate, String heatNo, String startTimes, String endTimes) {
+		List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
+		LambdaQueryWrapper<BilletOriginalProductRecord> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(BilletOriginalProductRecord::getCcmNo, ccmNo);
+		Boolean search = true; // 定义未传任何条件
+		if(oConvertUtils.isNotEmpty(changeShiftId)) { // 班组为空取班组时间
+			// 根据铸机号、交班记录ID,获取交班记录中的班别、班次、创建时间
+			LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
+			changeQueryWrapper.eq(BilletHotsendChangeShift::getId, changeShiftId).eq(BilletHotsendChangeShift::getCcmNo, ccmNo);
+			BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
+			if (billetHotsendChangeShift == null){
+				log.info("{}{}", "查询指定班次,交班记录为空!", ccmNo + "交班ID:" + changeShiftId);
+				return billetDetailsInfoList;
+			}
+			String shift = billetHotsendChangeShift.getShift();
+			String shiftGroup = billetHotsendChangeShift.getShiftGroup();
+			Date startTime = billetHotsendChangeShift.getCreateTime();
+			Date endTime = oConvertUtils.isNotEmpty(billetHotsendChangeShift.getChangeShiftTime()) ? billetHotsendChangeShift.getChangeShiftTime() : new Date();
+			queryWrapper.eq(BilletOriginalProductRecord::getShift, shift);
+			queryWrapper.eq(BilletOriginalProductRecord::getShiftGroup, shiftGroup);
+			queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTime, endTime);
+			search = false;
+		} else if(oConvertUtils.isNotEmpty(startTimes) && oConvertUtils.isNotEmpty(endTimes)){ // 时间范围
+			queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTimes, endTimes);
+			search = false;
+		}
+		if (oConvertUtils.isNotEmpty(queryDate) || search == true) { // 独立时间处理
+			// 如果时间给了空
+			if(oConvertUtils.isEmpty(queryDate)) { // 查询最后一个班次
+				String nowDate = DateUtils.getDate("yyyy-MM-dd");
+				Date startOneTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(nowDate));
+				// 查询最后一次交班记录时间
+				LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
+				changeQueryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo).orderByDesc(BilletHotsendChangeShift::getCreateTime).last("limit 1");
+				BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
+				queryWrapper.ge(BilletOriginalProductRecord::getCreateTime, oConvertUtils.isNotEmpty(billetHotsendChangeShift.getCreateTime()) ? billetHotsendChangeShift.getCreateTime() : startOneTime);
+			}else{
+				queryDate = oConvertUtils.isNotEmpty(queryDate) ? queryDate : DateUtils.getDate("yyyy-MM-dd");
+				Date startTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(queryDate));
+				Date endTime = DateUtils.getEndOfDayByDate(startTime);
+				queryWrapper.between(BilletOriginalProductRecord::getCreateTime, startTime, endTime);
+			}
+		}
+		// 炉号查询
+		if (oConvertUtils.isNotEmpty(heatNo)) {
+			queryWrapper.like(BilletOriginalProductRecord::getHeatNo, heatNo);
+		}
+
+		List<BilletOriginalProductRecord> billetOriginalProductRecordList = billetOriginalProductRecordService.list(queryWrapper);
+		if (oConvertUtils.listIsEmpty(billetOriginalProductRecordList)){
+			log.info("{}{}", "查询数据为空!");
+			BilletDetailsInfo info = new BilletDetailsInfo();
+			info.setCcmNo(ccmNo);
+			info.setCounts(0);
+			info.setTotalWeight(0.00);
+			List<BilletStatisticsDetail> detailsList = new ArrayList<>();
+			info.setBilletStatisticList(detailsList);
+			billetDetailsInfoList.add(info);
+			return billetDetailsInfoList;
+		}
+		Map<String, BilletStatisticsDetail> statisticsMap = new HashMap<>();
+
+		double grandTotalWeight = 0.0d;
+
+		for (BilletOriginalProductRecord record : billetOriginalProductRecordList) {
+			String rollClubOneDetails = record.getRollClubOneDetails();
+			if (rollClubOneDetails != null && !rollClubOneDetails.isEmpty()) {
+				try {
+					JSONObject detailsJson = JSON.parseObject(rollClubOneDetails);
+					JSONObject lengthGroupCount = detailsJson.getJSONObject("lengthGroupCount");
+					if (lengthGroupCount != null) {
+						for (Map.Entry<String, Object> entry : lengthGroupCount.entrySet()) {
+							String size = entry.getKey();
+							// 增加类型检查,避免潜在的空指针异常
+							int count = Integer.parseInt(entry.getValue().toString());
+							double sizeValue = Double.parseDouble(size);
+							updateStatistics(statisticsMap, size, count, sizeValue);
+						}
+					}
+				} catch (Exception e) {
+					log.error("解析rollClubOneDetails、rollHeightDetails失败: {}", rollClubOneDetails, e);
+				}
+			}
+		}
+
+		// 计算总数量和总重量
+		int grandTotalCount = statisticsMap.values().stream()
+				.mapToInt(BilletStatisticsDetail::getAmountTotal) // 修改为 getAmountTotal()
+				.sum();
+		grandTotalWeight = statisticsMap.values().stream()
+				.mapToDouble(BilletStatisticsDetail::getBlankOutput)
+				.sum();
+
+		if (!statisticsMap.isEmpty()) {
+			BilletDetailsInfo info = new BilletDetailsInfo();
+			info.setCcmNo(ccmNo);
+			info.setCounts(grandTotalCount);
+			info.setTotalWeight(grandTotalWeight);
+			List<BilletStatisticsDetail> detailsList = new ArrayList<>(statisticsMap.values());
+			info.setBilletStatisticList(detailsList);
+			billetDetailsInfoList.add(info);
+		}
+		return billetDetailsInfoList;
+	}
+
+	/**
+	 * 装运单统计明细查询
+	 * @param ccmNo
+	 * @param queryDate
+	 * @return
+	 */
+	private List<BilletDetailsInfo> querSstorageBillPrintStatistics(String ccmNo, String destination, String queryDate, String changeShiftId, String heatNo, String licensePlate, String startTimes, String endTimes, String sizes, String btype, String brandNum) {
+		List<BilletDetailsInfo> billetDetailsInfoList = new ArrayList<>();
+		// 根据铸机号、开始时间、结束时间查询查询装运单打印表
+		LambdaQueryWrapper<StorageBillPrint> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(StorageBillPrint::getCcmNo, ccmNo)
+				.eq(StorageBillPrint::getDestination, destination)
+				.orderByDesc(StorageBillPrint::getArrivalTime);
+		Boolean search = true; // 定义未传任何条件
+		if(oConvertUtils.isNotEmpty(changeShiftId)) { // 班组为空取班组时间
+			// 根据铸机号、交班记录ID,获取交班记录中的班别、班次、创建时间
+			LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
+			changeQueryWrapper.eq(BilletHotsendChangeShift::getId, changeShiftId).eq(BilletHotsendChangeShift::getCcmNo, ccmNo);
+			BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
+			if (billetHotsendChangeShift == null){
+				log.info("{}{}", "查询指定班次,交班记录为空!", ccmNo + "交班ID:" + changeShiftId);
+				return billetDetailsInfoList;
+			}
+			String shift = billetHotsendChangeShift.getShift();
+			String shiftGroup = billetHotsendChangeShift.getShiftGroup();
+			Date startTime = billetHotsendChangeShift.getCreateTime();
+			Date endTime = oConvertUtils.isNotEmpty(billetHotsendChangeShift.getChangeShiftTime()) ? billetHotsendChangeShift.getChangeShiftTime() : new Date();
+			String shiftAndShiftGroup = shift + "/" + shiftGroup;
+			queryWrapper.between(StorageBillPrint::getArrivalTime, startTime, endTime).eq(StorageBillPrint::getClasses, shiftAndShiftGroup);
+			search = false;
+		} else if(oConvertUtils.isNotEmpty(startTimes) && oConvertUtils.isNotEmpty(endTimes)){ // 时间范围
+			queryWrapper.between(StorageBillPrint::getArrivalTime, startTimes, endTimes);
+			search = false;
+		}
+		if ((oConvertUtils.isNotEmpty(queryDate)) || search == true) { // 独立时间处理
+			// 如果时间给了空
+			if(oConvertUtils.isEmpty(queryDate)) { // 查询最后一个班次
+				String nowDate = DateUtils.getDate("yyyy-MM-dd");
+				Date startArrivalTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(nowDate));
+				// 查询最后一次交班记录时间
+				LambdaQueryWrapper<BilletHotsendChangeShift> changeQueryWrapper = new LambdaQueryWrapper<>();
+				changeQueryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo).orderByDesc(BilletHotsendChangeShift::getCreateTime).last("limit 1");
+				BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(changeQueryWrapper);
+				// 查询确认时间为 null 或者  班次记录
+				queryWrapper.and(wrapper ->
+						wrapper
+								.isNull(StorageBillPrint::getConfirmTime)
+								.or(
+										wrapper2 -> wrapper2
+												.ge(StorageBillPrint::getArrivalTime, oConvertUtils.isNotEmpty(billetHotsendChangeShift.getCreateTime()) ? billetHotsendChangeShift.getCreateTime() : startArrivalTime)
+								)
+				);
+			}else{
+				Date startTime = DateUtils.getStartOfDayByDate(DateUtils.getStartOfDay(queryDate));
+				Date endTime = DateUtils.getEndOfDayByDate(startTime);
+				queryWrapper.between(StorageBillPrint::getArrivalTime, startTime, endTime);
+			}
+		}
+		// 炉号查询
+		if (oConvertUtils.isNotEmpty(heatNo)) {
+			queryWrapper.like(StorageBillPrint::getHeatNo, heatNo);
+		}
+		// 车牌号查询
+		if (oConvertUtils.isNotEmpty(licensePlate)) {
+			queryWrapper.eq(StorageBillPrint::getLicensePlate, licensePlate);
+		}
+		// 定尺
+		if (oConvertUtils.isNotEmpty(sizes)) {
+			queryWrapper.eq(StorageBillPrint::getSize, sizes);
+		}
+		// 热凉
+		if (oConvertUtils.isNotEmpty(btype)) {
+			queryWrapper.eq(StorageBillPrint::getBtype, btype);
+		}
+		// 牌号
+		if (oConvertUtils.isNotEmpty(brandNum)) {
+			queryWrapper.eq(StorageBillPrint::getBrandNum, brandNum);
+		}
+
+		List<StorageBillPrint> storageBillPrintList = storageBillPrintService.list(queryWrapper);
+		if (oConvertUtils.listIsEmpty(storageBillPrintList)) {
+			log.info("{}", "工作台统计明细查询数据为空!");
+			return billetDetailsInfoList;
+		}
+		// 创建并初始化BilletDetailsInfo对象
+		BilletDetailsInfo billetDetailsInfo = new BilletDetailsInfo();
+		billetDetailsInfo.setCcmNo(ccmNo); // 设置铸机号
+
+		// 按定尺(size)分组统计
+		Map<String, List<StorageBillPrint>> sizeGroupMap = storageBillPrintList.stream()
+				.filter(item -> item.getSize() != null && item.getAmountTotal() != null)
+				.collect(Collectors.groupingBy(StorageBillPrint::getSize));
+
+		// 计算每个分组的统计结果
+		List<BilletStatisticsDetail> statisticsDetails = new ArrayList<>();
+		for (Map.Entry<String, List<StorageBillPrint>> entry : sizeGroupMap.entrySet()) {
+			String size = entry.getKey();
+			List<StorageBillPrint> groupItems = entry.getValue();
+
+			// 计算总支数
+			Integer totalAmount = groupItems.stream()
+					.mapToInt(StorageBillPrint::getAmountTotal)
+					.sum();
+
+			// 计算总重量: (size/1000) * amountTotal * 0.2265,保留4位小数
+			double totalWeight = groupItems.stream()
+					.filter(item -> item.getAmountTotal() != null)
+					.mapToDouble(item -> {
+						try {
+							double sizeValue = Double.parseDouble(size);
+							return (sizeValue / 1000) * item.getAmountTotal() * 0.2265;
+						} catch (NumberFormatException e) {
+							return 0.0;
+						}
+					}).sum();
+
+			// 保留4位小数
+			totalWeight = Math.round(totalWeight * 10000.0) / 10000.0;
+
+			// 创建统计明细对象并添加到结果列表
+			BilletStatisticsDetail detail = new BilletStatisticsDetail(totalAmount, totalWeight, size);
+			statisticsDetails.add(detail);
+		}
+
+		// 设置统计结果到BilletDetailsInfo对象
+		billetDetailsInfo.setBilletStatisticList(statisticsDetails);
+
+		// 计算并设置总车次、总支数和总重量
+		billetDetailsInfo.setAllCarNum(storageBillPrintList.size()); // 总车次为记录数
+		billetDetailsInfo.setCounts(statisticsDetails.stream().mapToInt(BilletStatisticsDetail::getAmountTotal).sum());
+		billetDetailsInfo.setTotalWeight(statisticsDetails.stream().mapToDouble(BilletStatisticsDetail::getBlankOutput).sum());
+
+		// 添加到结果列表
+		billetDetailsInfoList.add(billetDetailsInfo);
+
+		return billetDetailsInfoList;
+	}
+
+	/**
+	 * 筛选指定流号的数据
+	 * @param billetList 钢坯信息列表
+	 * @param strandNo 流号
+	 * @return 指定流号的钢坯信息列表
+	 */
+	private List<BilletBasicInfo> filterByStrandNo(List<BilletBasicInfo> billetList, Integer strandNo) {
+		if (CollectionUtils.isEmpty(billetList) || strandNo == null) {
+			return Collections.emptyList();
+		}
+
+		return billetList.stream()
+				.filter(info -> info.getStrandNo() != null && info.getStrandNo().equals(strandNo))
+				.collect(Collectors.toList());
+	}
+
+	/**
+	 * 按定尺长度分组并统计数量
+	 * @param billetList 钢坯信息列表
+	 * @return 定尺长度到数量的映射
+	 */
+	private Map<String, Long> groupByLength(List<BilletBasicInfo> billetList) {
+		if (CollectionUtils.isEmpty(billetList)) {
+			return Collections.emptyMap();
+		}
+
+		return billetList.stream()
+				.filter(info -> info.getLength() != null)
+				.collect(Collectors.groupingBy(
+						info -> String.valueOf(info.getLength()),
+						Collectors.counting()
+				));
+	}
+
+
+	/**
+	 * 将总数按顺序循环分配到指定数量的流中
+	 * @param total 总数
+	 * @param numStrands 流的数量
+	 * @return 分配结果映射(键为流的名称,值为分配的数量)
+	 */
+	private Map<String, Integer> allocateRandomly(int total, int numStrands) {
+		// 初始化每个流分配0个
+		List<Integer> allocation = new ArrayList<>(Collections.nCopies(numStrands, 0));
+
+		// 按顺序循环分配所有数量
+		for (int i = 0; i < total; i++) {
+			// 计算当前应该分配的流索引(循环使用)
+			int index = i % numStrands;
+			allocation.set(index, allocation.get(index) + 1);
+		}
+
+		// 构建结果映射
+		Map<String, Integer> result = new HashMap<>();
+		result.put("oneStrandSum", numStrands > 0 ? allocation.get(0) : 0);
+		result.put("twoStrandSum", numStrands > 1 ? allocation.get(1) : 0);
+		result.put("threeStrandSum", numStrands > 2 ? allocation.get(2) : 0);
+		result.put("fourStrandSum", numStrands > 3 ? allocation.get(3) : 0);
+		result.put("fiveStrandSum", numStrands > 4 ? allocation.get(4) : 0);
+		result.put("sixStrandSum", numStrands > 5 ? allocation.get(5) : 0);
+		result.put("sevenStrandSum", numStrands > 6 ? allocation.get(6) : 0);
+		result.put("eightStrandSum", numStrands > 7 ? allocation.get(7) : 0);
+
+		return result;
+	}
+
+	private void applyConfirmInfo(BilletOriginalProductRecord record, LoginUser user) {
+		if (oConvertUtils.isNotEmpty(record.getConfirmTime())) {
+			record.setConfirmBy(user.getRealname());
+			record.setConfirmTime(new Date());
+			record.setRemark(record.getRemark());
+		}
+	}
+
+	// 提取的计算方法
+	private void updateStatistics(Map<String, BilletStatisticsDetail> statisticsMap,
+								  String size, int count, double sizeValue) {
+		statisticsMap.compute(size, (k, v) -> {
+			// 计算weight
+			double localWeight = (sizeValue / 1000) * count * 0.2265;
+			localWeight = BigDecimal.valueOf(localWeight)
+					.setScale(4, RoundingMode.HALF_UP)
+					.doubleValue();
+
+			BilletStatisticsDetail detail = v != null ? v : new BilletStatisticsDetail(count, localWeight, size);
+
+			if (v != null) {
+				detail.setAmountTotal(detail.getAmountTotal() + count);
+				detail.setBlankOutput(detail.getBlankOutput() + localWeight);
+			}
+			return detail;
+		});
+	}
+
+	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 count 需要计算的位置数量
+	 * @return 包含可用位置的对象列表
+	 */
+	private List<StackingAndLoadingVehicles> calculateNextPositions(
+			StackingAndLoadingVehicles highAddressSALV,
+			int count,
+			String ccmNo,
+			String typeConfigId) {
+
+		List<StackingAndLoadingVehicles> nextPositions = new ArrayList<>();
+
+		// 获取参考位置的address和layer
+		int currentAddress = Integer.valueOf(highAddressSALV.getAddress());
+		int currentLayer =  Integer.valueOf(highAddressSALV.getLayer());
+
+		// 如果参考位置为空(首次起垛),从1.1开始
+		if (currentAddress == 0 && currentLayer == 0) {
+			currentAddress = 1;
+			currentLayer = 1;
+		} else {
+			// 从参考位置的下一个位置开始计算
+			if (currentAddress == 9) {
+				currentAddress = 1;
+				currentLayer++;
+			} else {
+				currentAddress++;
+			}
+		}
+
+		// 生成指定数量的位置
+		for (int i = 0; i < count; i++) {
+			// 检查是否超出最大层数
+			if (currentLayer > 20) {
+				log.warn("已超出最大层数(20),无法生成更多位置");
+				break;
+			}
+
+			// 创建新位置
+			StackingAndLoadingVehicles newPosition = new StackingAndLoadingVehicles();
+			newPosition.setCcmNo(ccmNo);
+			newPosition.setAddress(String.valueOf(currentAddress));
+			newPosition.setLayer(String.valueOf(currentLayer));
+			newPosition.setTypeConfigId(typeConfigId);
+
+			nextPositions.add(newPosition);
+
+			// 更新下一个位置的address和layer
+			if (currentAddress == 9) {
+				currentAddress = 1;
+				currentLayer++;
+			} else {
+				currentAddress++;
+			}
+		}
+
+		return nextPositions;
+	}
+
+
+	/**
+	 * 生成短格式唯一坯号(炉号+铸机号+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);
+	}
+
+
+	/**
+	 * 生成综合唯一编码
+	 * @param  date
+	 * @param  ccmNo
+	 * @param  shift
+	 * @param  shiftGroup
+	 * @return uniqueCode
+	 */
+	public String generateUniqueCode(Date date, String ccmNo, String shift, String shiftGroup) {
+		// 将日期转换为指定格式的字符串
+		String dateStr = DateUtils.date2Str(date, DateUtils.yyyymmddhhmmss.get());
+		// 将 shift 转换为 ShiftEnum 的名称
+		String shiftName = ShiftEnum.fromCode(shift).name();
+		// 将 shiftGroup 转换为 ShiftGroupEnum 的名称
+		String shiftGroupName = ShiftGroupEnum.fromCode(shiftGroup).name();
+		// 组合生成唯一代码
+		String uniqueCode = dateStr + "-" + ccmNo + "#" + shiftName + "-" + shiftGroupName;
+		return uniqueCode;
+	}
+
+	/**
+	 * 从Redis中获取班组班别
+	 * @param ccmNo
+	 * @param keyFormat
+	 * @return
+	 */
+	private String getShiftInfo(String ccmNo, String keyFormat) {
+		String key = String.format(keyFormat, ccmNo);
+		return oConvertUtils.getString(redisTemplate.opsForValue().get(key));
+	}
+
+	/**
+	 * 更新交班记录
+	 * @param ccmNo
+	 * @param shiftGroup
+	 * @param shift
+	 */
+	private void updateBilletHotsendChangeShift(String ccmNo, String shiftGroup, String shift) {
+		LambdaQueryWrapper<BilletHotsendChangeShift> queryWrapper = new LambdaQueryWrapper<>();
+		queryWrapper.eq(BilletHotsendChangeShift::getCcmNo, ccmNo)
+				.eq(BilletHotsendChangeShift::getShiftGroup, shiftGroup)
+				.eq(BilletHotsendChangeShift::getShift, shift)
+				.isNull(BilletHotsendChangeShift::getChangeShiftTime)
+				.orderByDesc(BilletHotsendChangeShift::getCreateTime)
+				.last("limit 1");
+		BilletHotsendChangeShift billetHotsendChangeShift = billetHotsendChangeShiftService.getOne(queryWrapper);
+		if (oConvertUtils.isEmpty(billetHotsendChangeShift)) {
+			log.info("推钢室界面创建装运单交班记录不存在,车次数维护失败:{}", ccmNo+shiftGroup+shift);
+			return;
+		}
+		billetHotsendChangeShift.setOutCarNum(billetHotsendChangeShift.getOutCarNum() + 1);
+		billetHotsendChangeShiftService.updateById(billetHotsendChangeShift);
+	}
+}