From 8e2427369f1559e255a7dfedbc1a13a46ba4b468 Mon Sep 17 00:00:00 2001 From: ljw Date: Sun, 4 Jan 2026 11:56:55 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cst/order/config/TruckWeighingConfig.java | 27 + .../cst/order/constant/VoiceConstants.java | 24 + .../cst/order/controller/OrderController.java | 6 +- .../cst/order/mapper/OrderTransMapper.java | 7 + .../cst/order/service/OrderService.java | 57 --- .../service/TruckWeighingBusinessService.java | 481 ++++++++++++++++++ .../service/TruckWeighingEventListener.java | 50 ++ .../mapper/cst/order/OrderTransMapper.xml | 14 + 8 files changed, 606 insertions(+), 60 deletions(-) create mode 100644 njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/config/TruckWeighingConfig.java create mode 100644 njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/constant/VoiceConstants.java create mode 100644 njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingBusinessService.java create mode 100644 njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingEventListener.java diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/config/TruckWeighingConfig.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/config/TruckWeighingConfig.java new file mode 100644 index 0000000..de43320 --- /dev/null +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/config/TruckWeighingConfig.java @@ -0,0 +1,27 @@ +package com.njzscloud.dispose.cst.order.config; + +import com.njzscloud.dispose.cst.order.service.TruckWeighingEventListener; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Configuration; + +/** + * 车辆称重配置 + * 用于初始化车辆称重事件监听器 + * + * @author ljw + */ +@Slf4j +@Configuration +@RequiredArgsConstructor +public class TruckWeighingConfig implements CommandLineRunner { + + private final TruckWeighingEventListener truckWeighingEventListener; + + @Override + public void run(String... args) { + log.info("启动车辆称重事件监听器"); + truckWeighingEventListener.init(); + } +} diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/constant/VoiceConstants.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/constant/VoiceConstants.java new file mode 100644 index 0000000..aab3546 --- /dev/null +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/constant/VoiceConstants.java @@ -0,0 +1,24 @@ +package com.njzscloud.dispose.cst.order.constant; + +/** + * 语音提示常量 + * + * @author ljw + */ +public class VoiceConstants { + + private VoiceConstants() { + // 工具类,防止实例化 + } + + public static final String VOICE_WELCOME = "欢迎光临"; + public static final String VOICE_WEIGHING = "正在称重请稍候"; + public static final String VOICE_PLEASE_PASS = "请通行"; + public static final String VOICE_WEIGH_COMPLETE = "称重完成"; + public static final String VOICE_ORDER_NOT_FOUND = "订单不存在"; + public static final String VOICE_SYSTEM_ERROR = "系统异常"; + public static final String VOICE_WEIGH_FAILED = "称重失败"; + public static final String VOICE_STATUS_ERROR = "状态异常"; + public static final String VOICE_SETTLEMENT_ERROR = "结算异常"; + public static final String VOICE_UNCHECKED = "未看料"; +} diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/controller/OrderController.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/controller/OrderController.java index d6cdb43..857e211 100644 --- a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/controller/OrderController.java +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/controller/OrderController.java @@ -109,7 +109,7 @@ public class OrderController { * 车辆进场 */ @PostMapping("/truck_coming") - public R truckComing(@RequestBody TruckComingParam param) { + public synchronized R truckComing(@RequestBody TruckComingParam param) { orderService.truckComing(param); return R.success(); } @@ -118,7 +118,7 @@ public class OrderController { * 看料 */ @PostMapping("/check") - public R check(@RequestBody CheckGoodsParam checkGoodsParam) { + public synchronized R check(@RequestBody CheckGoodsParam checkGoodsParam) { orderService.check(checkGoodsParam); return R.success(); } @@ -127,7 +127,7 @@ public class OrderController { * 车辆出场 */ @PostMapping("/truck_leaving") - public R truckLeaving(@RequestBody TruckLeavingParam leavingParam) { + public synchronized R truckLeaving(@RequestBody TruckLeavingParam leavingParam) { orderService.truckLeaving(leavingParam); return R.success(); } diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/mapper/OrderTransMapper.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/mapper/OrderTransMapper.java index 794b648..1f6b9c2 100644 --- a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/mapper/OrderTransMapper.java +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/mapper/OrderTransMapper.java @@ -21,4 +21,11 @@ public interface OrderTransMapper extends BaseMapper { IPage paging(Page page, @Param("ew") QueryWrapper ew); + /** + * 根据车牌号查找运输订单 + * @param licensePlate 车牌号 + * @return 运输订单结果 + */ + OrderTransResult getByLicensePlate(@Param("licensePlate") String licensePlate); + } diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/OrderService.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/OrderService.java index fa72647..af0520d 100644 --- a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/OrderService.java +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/OrderService.java @@ -6,7 +6,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.njzscloud.common.core.ex.Exceptions; import com.njzscloud.common.core.fastjson.Fastjson; -import com.njzscloud.common.core.tuple.Tuple2; import com.njzscloud.common.mp.support.PageParam; import com.njzscloud.common.mp.support.PageResult; import com.njzscloud.common.security.util.SecurityUtil; @@ -27,9 +26,6 @@ import com.njzscloud.dispose.cst.order.pojo.result.OrderTransResult; import com.njzscloud.dispose.cst.order.pojo.vo.Scope; import com.njzscloud.dispose.cst.truck.mapper.TruckMapper; import com.njzscloud.dispose.cst.truck.pojo.entity.TruckEntity; -import com.njzscloud.dispose.dev.DiscoverTruckMsg; -import com.njzscloud.dispose.dev.ObtainTruckDataResultMsg; -import com.njzscloud.dispose.dev.WbsHandle; import com.njzscloud.dispose.finance.constant.ScopeStrategy; import com.njzscloud.dispose.finance.pojo.entity.ExpenseItemEntity; import com.njzscloud.dispose.finance.service.ExpenseItemService; @@ -42,12 +38,8 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; -import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import static com.njzscloud.dispose.dev.DevMittEvent.DISCOVER_TRUCK; -import static com.njzscloud.dispose.dev.DevMittEvent.OBTAIN_TRUCK_DATA_REPLY; - /** * 收/销订单 * @@ -66,55 +58,6 @@ public class OrderService extends ServiceImpl { private final CustomerMapper customerMapper; private final OrderExpenseItemsService orderExpenseItemsService; - { - DISCOVER_TRUCK.on(this::a); - OBTAIN_TRUCK_DATA_REPLY.on(this::b); - } - - - public void a(Tuple2 param) { - DiscoverTruckMsg param0 = param.get_0(); - WbsHandle param1 = param.get_1(); - - // 车头照 - String image = param0.getImage(); - // 写库要加锁 - String licensePlate = param0.getLicensePlate(); - // 找订单 - - // 发语音 - - // 进前置、出前置 - - // 进场 - - // 获取磅重、车斗照片 - param1.obtainTruckData(1L); - param1.playVoice(image, 2); - param1.open(); - return; - // 出场 - - } - - ReentrantLock reentrantLock = new ReentrantLock(); - - public void b(Tuple2 param) { - ObtainTruckDataResultMsg it0 = param.get_0(); - WbsHandle it1 = param.get_1(); - // 车斗照 - Long orderId = it0.getOrderId(); - String image = it0.getImage(); - Integer weight = it0.getWeight(); - it1.open(); - it1.playVoice(image, 2); - - synchronized (this) { - // 写库要加锁 - } - } - - @Transactional(rollbackFor = Exception.class) public void add(CreateOrderParam param) { // 订单信息 diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingBusinessService.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingBusinessService.java new file mode 100644 index 0000000..668deef --- /dev/null +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingBusinessService.java @@ -0,0 +1,481 @@ +package com.njzscloud.dispose.cst.order.service; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.njzscloud.common.core.tuple.Tuple2; +import com.njzscloud.common.oss.util.AliOSS; +import com.njzscloud.dispose.cst.order.constant.*; +import com.njzscloud.dispose.cst.order.mapper.OrderTransMapper; +import com.njzscloud.dispose.cst.order.pojo.entity.OrderEntity; +import com.njzscloud.dispose.cst.order.pojo.entity.OrderTransEntity; +import com.njzscloud.dispose.cst.order.pojo.result.OrderTransResult; +import com.njzscloud.dispose.dev.DiscoverTruckMsg; +import com.njzscloud.dispose.dev.ObtainTruckDataResultMsg; +import com.njzscloud.dispose.dev.WbsHandle; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayInputStream; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.List; + +/** + * 车辆称重业务服务 + * 处理磅房称重相关的所有业务逻辑 + * + * @author ljw + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TruckWeighingBusinessService { + + private final OrderService orderService; + private final OrderTransMapper orderTransMapper; + + /** + * 请求数据 - 处理车辆识别 + */ + public void requestData(Tuple2 param) { + DiscoverTruckMsg truckMsg = param.get_0(); + WbsHandle handle = param.get_1(); + // 车牌号 + String licensePlate = truckMsg.getLicensePlate(); + // 是否为前置道闸 + boolean isFront = truckMsg.isFront(); + // 根据车牌号查找运输订单 + OrderTransResult orderTrans = orderTransMapper.getByLicensePlate(licensePlate); + if (orderTrans == null) { + log.warn("未找到车牌号 {} 对应的运输订单", licensePlate); + handle.playVoice(VoiceConstants.VOICE_ORDER_NOT_FOUND); + return; + } + + // 验证订单业务状态 + if (!validateOrderBusinessStatus(orderTrans)) { + handle.playVoice(VoiceConstants.VOICE_STATUS_ERROR); + return; + } + + // 使用同步锁确保数据一致性 + synchronized (this) { + try { + log.info("开始处理车辆 {} 进出场请求,前置道闸: {}", licensePlate, isFront ? "是" : "否"); + + // 判断是进场还是出场 + boolean isComing = isTruckComing(orderTrans); + boolean isLeaving = isTruckLeaving(orderTrans); + if (isLeaving) { + // 出场时检查是否已看料 + if (!CheckStatus.YiKanLiao.equals(orderTrans.getCheckStatus())) { + handle.playVoice(licensePlate + VoiceConstants.VOICE_UNCHECKED); + return; + } + } + if (!isComing && !isLeaving) { + log.warn("订单 {} 状态不允许进出场操作,当前状态:订单={},运输={}", + orderTrans.getId(), orderTrans.getOrderStatus(), orderTrans.getTransStatus()); + handle.playVoice(VoiceConstants.VOICE_STATUS_ERROR); + return; + } + + if (isFront) { + // 前置道闸:还未上磅,只负责开门让车辆通过 + log.info("前置道闸开门,车辆 {} 进入磅区", licensePlate); + handle.playVoice(VoiceConstants.VOICE_WELCOME); + handle.open(); + } else { + // 后置道闸:车辆已过磅,负责称重和算账,但不开门 + log.info("后置道闸开始称重,车辆 {},订单ID: {}", licensePlate, orderTrans.getId()); + handle.playVoice(VoiceConstants.VOICE_WEIGHING); + handle.obtainTruckData(orderTrans.getId()); + } + } catch (Exception e) { + log.error("处理车辆 {} 识别异常", licensePlate, e); + handle.playVoice(VoiceConstants.VOICE_SYSTEM_ERROR); + } + } + } + + /** + * 处理数据 - 处理磅重数据 + */ + public void disposeData(Tuple2 param) { + ObtainTruckDataResultMsg dataMsg = param.get_0(); + WbsHandle wbsHandle = param.get_1(); + + Long orderTransId = dataMsg.getOrderId(); + String image = dataMsg.getImage(); + Integer weight = dataMsg.getWeight(); + Boolean success = dataMsg.getSuccess(); + + // 检查数据获取是否成功 + if (!Boolean.TRUE.equals(success) || weight == null || weight <= 0) { + log.warn("获取车辆数据失败或重量无效,订单ID: {}, 重量: {}", orderTransId, weight); + wbsHandle.playVoice(VoiceConstants.VOICE_WEIGH_FAILED); + return; + } + + synchronized (this) { + try { + log.info("开始处理称重数据,运输ID: {}, 重量: {}kg", orderTransId, weight); + + // 根据运输ID获取订单信息 + OrderTransResult orderTrans = orderTransMapper.getById(orderTransId); + if (orderTrans == null) { + log.warn("未找到运输订单 {}", orderTransId); + wbsHandle.playVoice(VoiceConstants.VOICE_ORDER_NOT_FOUND); + return; + } + if (!CheckStatus.YiKanLiao.equals(orderTrans.getCheckStatus())) { + wbsHandle.playVoice(orderTrans.getTruckLicensePlate() + VoiceConstants.VOICE_UNCHECKED); + return; + } + + // 根据当前状态处理称重数据 + processWeighingData(orderTrans, weight, image, wbsHandle); + + } catch (Exception e) { + log.error("处理车辆称重数据异常,订单ID: {}", orderTransId, e); + wbsHandle.playVoice(VoiceConstants.VOICE_SYSTEM_ERROR); + } + } + } + + /** + * 处理称重数据 + */ + private void processWeighingData(OrderTransResult orderTrans, Integer weight, String image, WbsHandle wbsHandle) { + // 根据当前状态判断是进场还是出场 + if (TransStatus.YunShuZhong.equals(orderTrans.getTransStatus())) { + // 进场:设置相应重量,完成后开门 + handleTruckComingData(orderTrans, weight, image); + wbsHandle.playVoice(VoiceConstants.VOICE_PLEASE_PASS); + wbsHandle.open(); + } else if (TransStatus.YiJinChang.equals(orderTrans.getTransStatus())) { + // 出场:设置相应重量并计算净重、账目,等待支付完成后再开门 + handleTruckLeavingData(orderTrans, weight, image); + wbsHandle.playVoice(VoiceConstants.VOICE_WEIGH_COMPLETE); + // TODO: 触发算账流程,支付完成后调用 completePaymentAndOpenGate 方法开门 + processSettlementAndWaitForPayment(orderTrans, wbsHandle); + } else { + log.warn("运输订单 {} 状态 {} 不支持称重操作", orderTrans.getId(), orderTrans.getTransStatus()); + wbsHandle.playVoice(VoiceConstants.VOICE_STATUS_ERROR); + } + } + + /** + * 处理进场称重数据 + */ + private void handleTruckComingData(OrderTransResult orderTrans, Integer weight, String bodyPhoto) { + OrderTransEntity transEntity = new OrderTransEntity(); + transEntity.setId(orderTrans.getId()); + transEntity.setTransStatus(TransStatus.YiJinChang); + transEntity.setInTime(LocalDateTime.now()); + + // 上传车斗照片并设置URL + if (bodyPhoto != null && !bodyPhoto.trim().isEmpty()) { + String photoUrl = uploadBase64Image(bodyPhoto, "truck_body_in_" + orderTrans.getId()); + transEntity.setInBodyPhoto(photoUrl); + } + + // 设置重量(进场) + setWeightByOrderType(transEntity, orderTrans, weight, true); + + orderTransMapper.updateById(transEntity); + log.info("车辆进场称重完成,订单ID: {}, 重量: {}kg", orderTrans.getId(), weight); + } + + /** + * 处理出场称重数据 + */ + private void handleTruckLeavingData(OrderTransResult orderTrans, Integer weight, String bodyPhoto) { + OrderTransEntity transEntity = new OrderTransEntity(); + transEntity.setId(orderTrans.getId()); + transEntity.setTransStatus(TransStatus.YiChuChang); + transEntity.setOutTime(LocalDateTime.now()); + + // 上传车斗照片并设置URL + if (bodyPhoto != null && !bodyPhoto.trim().isEmpty()) { + String photoUrl = uploadBase64Image(bodyPhoto, "truck_body_out_" + orderTrans.getId()); + transEntity.setOutBodyPhoto(photoUrl); + } + + // 设置重量(出场) + setWeightByOrderType(transEntity, orderTrans, weight, false); + + // 计算净重 + calculateAndSetNetWeight(transEntity, orderTrans); + + orderTransMapper.updateById(transEntity); + Integer settleWeight = transEntity.getSettleWeight(); + log.info("车辆出场称重完成,订单ID: {}, 重量: {}kg, 净重: {}kg", + orderTrans.getId(), weight, settleWeight); + } + + /** + * 根据订单类型设置重量 + */ + private void setWeightByOrderType(OrderTransEntity transEntity, OrderTransResult orderTrans, Integer weight, boolean isComing) { + if (OrderCategory.HuiShouYuYue.equals(orderTrans.getOrderCategory())) { + // 回收预约单:进场称毛重,出场称皮重 + if (isComing) { + transEntity.setRoughWeight(weight); + } else { + transEntity.setTareWeight(weight); + // 更新车辆皮重 + orderService.updateTruckHisTareWeight(orderTrans.getTruckId(), weight); + } + } else if (OrderCategory.XiaoShouYuYue.equals(orderTrans.getOrderCategory())) { + // 销售预约单:进场称皮重,出场称毛重 + if (isComing) { + transEntity.setTareWeight(weight); + // 更新车辆皮重 + orderService.updateTruckHisTareWeight(orderTrans.getTruckId(), weight); + } else { + transEntity.setRoughWeight(weight); + } + } + } + + /** + * 计算并设置净重 + */ + private void calculateAndSetNetWeight(OrderTransEntity transEntity, OrderTransResult orderTrans) { + Integer roughWeight = transEntity.getRoughWeight() != null ? transEntity.getRoughWeight() : orderTrans.getRoughWeight(); + Integer tareWeight = transEntity.getTareWeight() != null ? transEntity.getTareWeight() : orderTrans.getTareWeight(); + + if (roughWeight != null && tareWeight != null && roughWeight > tareWeight) { + Integer settleWeight = roughWeight - tareWeight; + transEntity.setSettleWeight(settleWeight); + log.debug("计算净重完成,毛重: {}kg, 皮重: {}kg, 净重: {}kg", roughWeight, tareWeight, settleWeight); + } else { + log.warn("无法计算净重,毛重: {}, 皮重: {}", roughWeight, tareWeight); + } + } + + /** + * 上传base64编码的图片到阿里云OSS + */ + private String uploadBase64Image(String base64Image, String fileNamePrefix) { + if (base64Image == null || base64Image.trim().isEmpty()) { + return null; + } + + try { + // 移除base64前缀(如"data:image/jpeg;base64,") + String base64Data; + if (base64Image.contains(",")) { + base64Data = base64Image.substring(base64Image.indexOf(",") + 1); + } else { + base64Data = base64Image; + } + + // 解码base64字符串为字节数组 + byte[] imageBytes = Base64.getDecoder().decode(base64Data); + + // 生成文件名 + String fileName = fileNamePrefix + "_" + System.currentTimeMillis() + ".jpg"; + + // 创建ByteArrayInputStream并上传到OSS + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes)) { + // 使用AliOSS直接上传 + String url = AliOSS.uploadFile(fileName, "image/jpeg", inputStream); + + log.info("车斗照片上传成功: {}", url); + return url; + } + + } catch (Exception e) { + log.error("上传base64车斗照片失败", e); + // 上传失败时返回原始base64字符串作为降级方案 + return base64Image; + } + } + + /** + * 判断是否为进场操作 + * 订单状态为进行中,运输状态为运输中 + */ + private boolean isTruckComing(OrderTransResult orderTrans) { + return OrderStatus.JinXingZhong.equals(orderTrans.getOrderStatus()) && + TransStatus.YunShuZhong.equals(orderTrans.getTransStatus()); + } + + /** + * 判断是否为出场操作 + * 订单状态为进行中,运输状态为已进场 + */ + private boolean isTruckLeaving(OrderTransResult orderTrans) { + return OrderStatus.JinXingZhong.equals(orderTrans.getOrderStatus()) && + TransStatus.YiJinChang.equals(orderTrans.getTransStatus()); + } + + /** + * 验证订单业务状态 + */ + private boolean validateOrderBusinessStatus(OrderTransResult orderTrans) { + // 检查订单状态 + if (!OrderStatus.JinXingZhong.equals(orderTrans.getOrderStatus())) { + log.warn("订单状态异常,订单ID: {}, 当前状态: {}", orderTrans.getId(), orderTrans.getOrderStatus()); + return false; + } + + // 检查运输状态 + TransStatus transStatus = orderTrans.getTransStatus(); + if (!TransStatus.YunShuZhong.equals(transStatus) && !TransStatus.YiJinChang.equals(transStatus)) { + log.warn("运输状态异常,订单ID: {}, 当前状态: {}", orderTrans.getId(), transStatus); + return false; + } + + // 检查订单类型 + if (orderTrans.getOrderCategory() == null) { + log.warn("订单类型为空,订单ID: {}", orderTrans.getId()); + return false; + } + + return true; + } + + /** + * 检查订单下所有运输记录是否都已完成 + */ + private boolean checkAllTransCompleted(Long orderId) { + try { + // 查询该订单下的所有运输记录 + List transList = orderTransMapper.selectList( + Wrappers.lambdaQuery() + .eq(OrderTransEntity::getOrderId, orderId) + .eq(OrderTransEntity::getDeleted, Boolean.FALSE) + ); + + if (transList.isEmpty()) { + log.warn("订单 {} 下没有找到运输记录", orderId); + return false; + } + + // 检查所有运输记录的状态是否都为已完成 + boolean allCompleted = transList.stream() + .allMatch(trans -> TransStatus.YiWanCheng.equals(trans.getTransStatus())); + + if (allCompleted) { + log.info("订单 {} 下所有 {} 条运输记录都已完成", orderId, transList.size()); + } else { + long completedCount = transList.stream() + .filter(trans -> TransStatus.YiWanCheng.equals(trans.getTransStatus())) + .count(); + log.info("订单 {} 下 {}/{} 条运输记录已完成", orderId, completedCount, transList.size()); + } + + return allCompleted; + + } catch (Exception e) { + log.error("检查订单 {} 运输完成状态异常", orderId, e); + // 出现异常时保守处理,返回false + return false; + } + } + + /** + * 处理结算并等待支付完成 + */ + private void processSettlementAndWaitForPayment(OrderTransResult orderTrans, WbsHandle wbsHandle) { + try { + log.info("开始处理订单 {} 的结算流程", orderTrans.getId()); + + // TODO: 执行算账逻辑 + // 这里应该调用财务结算服务,计算费用并生成支付订单 + // calculateSettlement(orderTrans); + + // 模拟支付完成通知(实际应该通过支付回调或消息队列处理) + // 在实际生产环境中,应该: + // 1. 调用财务服务计算费用 + // 2. 生成支付订单 + // 3. 等待支付完成的通知(通过消息队列或回调) + // 4. 支付完成后调用 completePaymentAndOpenGate 方法 + + log.info("订单 {} 结算流程启动,等待支付完成", orderTrans.getId()); + + // TODO: 在实际支付完成后调用以下方法 + // completePaymentAndOpenGate(orderTrans, wbsHandle); + + // 临时实现:直接完成(用于测试) + simulatePaymentCompletion(orderTrans, wbsHandle); + + } catch (Exception e) { + log.error("处理订单 {} 结算异常", orderTrans.getId(), e); + handleBusinessException(wbsHandle, "结算处理失败", e); + } + } + + /** + * 模拟支付完成(测试用) + */ + private void simulatePaymentCompletion(OrderTransResult orderTrans, WbsHandle wbsHandle) { + // 在实际应用中,这里应该通过消息队列或定时任务等待支付完成 + // 这里只是为了演示流程,实际应该移除 + try { + // 模拟支付处理时间 + Thread.sleep(2000); + completePaymentAndOpenGate(orderTrans, wbsHandle); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("模拟支付完成被中断", e); + } + } + + /** + * 支付完成并开门 + */ + @Transactional(rollbackFor = Exception.class) + public void completePaymentAndOpenGate(OrderTransResult orderTrans, WbsHandle wbsHandle) { + synchronized (this) { + try { + // 更新运输状态为已完成 + OrderTransEntity transEntity = new OrderTransEntity(); + transEntity.setId(orderTrans.getId()); + transEntity.setTransStatus(TransStatus.YiWanCheng); + transEntity.setFinishTime(LocalDateTime.now()); + orderTransMapper.updateById(transEntity); + + // 检查该订单下所有运输记录是否都已完成 + boolean allTransCompleted = checkAllTransCompleted(orderTrans.getOrderId()); + + if (allTransCompleted) { + // 更新订单状态为已完成 + OrderEntity orderEntity = new OrderEntity(); + orderEntity.setId(orderTrans.getOrderId()); + orderEntity.setOrderStatus(OrderStatus.YiWanCheng); + orderEntity.setFinishTime(LocalDateTime.now()); + orderService.updateById(orderEntity); + log.info("订单 {} 所有运输记录已完成,订单状态更新为已完成", orderTrans.getOrderId()); + } else { + log.info("订单 {} 还有未完成的运输记录,暂不更新订单状态", orderTrans.getOrderId()); + } + + // 开门放行 + wbsHandle.playVoice(VoiceConstants.VOICE_PLEASE_PASS); + wbsHandle.open(); + + log.info("运输记录 {} 支付完成,开门放行", orderTrans.getId()); + + } catch (Exception e) { + handleBusinessException(wbsHandle, "完成订单 " + orderTrans.getId() + " 支付并开门异常", e); + } + } + } + + /** + * 处理业务异常 + */ + private void handleBusinessException(WbsHandle wbsHandle, String message, Exception e) { + log.error("业务处理异常: {}", message, e); + try { + wbsHandle.playVoice(VoiceConstants.VOICE_SYSTEM_ERROR); + } catch (Exception voiceException) { + log.error("播放语音失败", voiceException); + } + } +} diff --git a/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingEventListener.java b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingEventListener.java new file mode 100644 index 0000000..6ac42ad --- /dev/null +++ b/njzscloud-svr/src/main/java/com/njzscloud/dispose/cst/order/service/TruckWeighingEventListener.java @@ -0,0 +1,50 @@ +package com.njzscloud.dispose.cst.order.service; + +import com.njzscloud.common.core.tuple.Tuple2; +import com.njzscloud.dispose.dev.DiscoverTruckMsg; +import com.njzscloud.dispose.dev.ObtainTruckDataResultMsg; +import com.njzscloud.dispose.dev.WbsHandle; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static com.njzscloud.dispose.dev.DevMittEvent.DISCOVER_TRUCK; +import static com.njzscloud.dispose.dev.DevMittEvent.OBTAIN_TRUCK_DATA_REPLY; + +/** + * 车辆称重事件监听器 + * 负责处理磅房设备的车辆识别和称重数据事件 + * + * @author ljw + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class TruckWeighingEventListener { + + private final TruckWeighingBusinessService businessService; + + + /** + * 初始化事件监听器 + */ + public void init() { + log.info("初始化车辆称重事件监听器"); + DISCOVER_TRUCK.on(this::requestData); + OBTAIN_TRUCK_DATA_REPLY.on(this::disposeData); + } + + /** + * 请求数据 - 处理车辆识别 + */ + public void requestData(Tuple2 param) { + businessService.requestData(param); + } + + /** + * 处理数据 - 处理磅重数据 + */ + public void disposeData(Tuple2 param) { + businessService.disposeData(param); + } +} diff --git a/njzscloud-svr/src/main/resources/mapper/cst/order/OrderTransMapper.xml b/njzscloud-svr/src/main/resources/mapper/cst/order/OrderTransMapper.xml index 1acbd14..1812d14 100644 --- a/njzscloud-svr/src/main/resources/mapper/cst/order/OrderTransMapper.xml +++ b/njzscloud-svr/src/main/resources/mapper/cst/order/OrderTransMapper.xml @@ -140,4 +140,18 @@ ${ew.customSqlSegment} + +