修复充电

This commit is contained in:
2025-06-07 21:37:31 +08:00
parent fb27dc6f29
commit 20e35b3fd1
6 changed files with 78 additions and 253 deletions

View File

@@ -227,14 +227,27 @@ public class ChargingRobotServiceImpl extends ServiceImpl<ChargingRobotMapper, C
}
@Override
@Transactional
public boolean releaseRobot(Long robotId) {
ChargingRobot robot = getById(robotId);
if (robot == null) {
log.warn("尝试释放机器人失败,机器人不存在: {}", robotId);
return false;
}
// 将机器人状态设置为空闲并清除当前任务ID
return updateRobotStatus(robot.getRobotUid(), RobotStatusEnum.IDLE, null, null, null, null); // 第二个参数传null以清除任务ID
// 关键修复:确保释放机器人时,原子性地更新其状态和任务ID
ChargingRobot robotToUpdate = new ChargingRobot();
robotToUpdate.setId(robotId);
robotToUpdate.setStatus(RobotStatusEnum.IDLE.getValue());
robotToUpdate.setCurrentTaskId(null); // 显式清除任务ID
boolean success = this.updateById(robotToUpdate);
if (success) {
log.info("成功释放机器人 {}状态设置为IDLE任务ID已清除。", robot.getRobotUid());
} else {
log.error("数据库操作失败,未能释放机器人 {}", robot.getRobotUid());
}
return success;
}
@Override

View File

@@ -352,24 +352,6 @@ public class ChargingSessionServiceImpl extends ServiceImpl<ChargingSessionMappe
log.info("会话 {} 费用计算完成: {}元. 状态更新为 PAYMENT_PENDING", sessionId, cost);
// 此处可以触发通知用户支付
}
// 在计费完成后如果会话已标记为COMPLETED但尚未支付并且车位状态不是AVAILABLE则将其设置为空闲
// 这主要覆盖了 handleChargingEnd 中可能未完全释放车位的情况(例如,如果计费失败)
// 或者如果 calculateCostAndFinalizeSession 是独立调用的。
String sessionStatus = session.getStatus();
String paymentStatus = session.getPaymentStatus();
if (ChargingSessionStatusEnum.CHARGING_COMPLETED.getValue().equals(sessionStatus) ||
PaymentStatusEnum.PAID.getValue().equals(paymentStatus) ||
PaymentStatusEnum.FAILED.getValue().equals(paymentStatus)) {
ParkingSpot spot = parkingSpotService.getById(session.getSpotId());
if (spot != null && !ParkingSpotStatusEnum.AVAILABLE.getValue().equals(spot.getStatus())) {
log.info("在 finalizeSession for session {} 时,车位 {} (UID: {}) 状态为 {},将其更新为 AVAILABLE。",
sessionId, spot.getId(), spot.getSpotUid(), spot.getStatus());
parkingSpotService.updateSpotStatus(spot.getSpotUid(), ParkingSpotStatusEnum.AVAILABLE, null);
}
}
return updated;
}

View File

@@ -68,34 +68,34 @@ public class MqttMessageHandler implements IMqttMessageListener {
statusMessage.getStatus(), statusMessage.getTaskId(), robotUIDFromTopicSource, payloadJson);
// Do not return, general status might still need processing.
} else {
boolean taskUpdated; // Defined outside switch
switch (taskNewStatus) {
case PROCESSING:
taskUpdated = robotTaskService.markTaskAsProcessing(statusMessage.getTaskId(), new Date(), statusMessage.getMessage());
break;
case COMPLETED:
taskUpdated = robotTaskService.markTaskAsCompleted(statusMessage.getTaskId(), new Date(), statusMessage.getMessage());
break;
case FAILED:
String combinedTaskErrorMessage = statusMessage.getErrorCode() != null ?
statusMessage.getErrorCode() + ": " + statusMessage.getMessage() :
statusMessage.getMessage();
taskUpdated = robotTaskService.markTaskAsFailed(statusMessage.getTaskId(), combinedTaskErrorMessage, new Date());
break;
default:
log.warn("Received unhandled RobotTaskStatusEnum: {} for task {} from robot {}. Ignoring.",
taskNewStatus, statusMessage.getTaskId(), robotUIDFromTopicSource);
boolean taskUpdated; // Defined outside switch
switch (taskNewStatus) {
case PROCESSING:
taskUpdated = robotTaskService.markTaskAsProcessing(statusMessage.getTaskId(), new Date(), statusMessage.getMessage());
break;
case COMPLETED:
taskUpdated = robotTaskService.markTaskAsCompleted(statusMessage.getTaskId(), new Date(), statusMessage.getMessage());
break;
case FAILED:
String combinedTaskErrorMessage = statusMessage.getErrorCode() != null ?
statusMessage.getErrorCode() + ": " + statusMessage.getMessage() :
statusMessage.getMessage();
taskUpdated = robotTaskService.markTaskAsFailed(statusMessage.getTaskId(), combinedTaskErrorMessage, new Date());
break;
default:
log.warn("Received unhandled RobotTaskStatusEnum: {} for task {} from robot {}. Ignoring.",
taskNewStatus, statusMessage.getTaskId(), robotUIDFromTopicSource);
taskUpdated = false; // To prevent logging success
break;
}
if (taskUpdated) {
log.info("Successfully updated task {} to status {} for robot {} based on MQTT message.",
statusMessage.getTaskId(), taskNewStatus, robotUIDFromTopicSource);
} else {
log.warn("Failed to update task {} to status {} for robot {} (or task not found/invalid state transition). Message: {}",
statusMessage.getTaskId(), taskNewStatus, robotUIDFromTopicSource, statusMessage.getMessage());
}
}
if (taskUpdated) {
log.info("Successfully updated task {} to status {} for robot {} based on MQTT message.",
statusMessage.getTaskId(), taskNewStatus, robotUIDFromTopicSource);
} else {
log.warn("Failed to update task {} to status {} for robot {} (or task not found/invalid state transition). Message: {}",
statusMessage.getTaskId(), taskNewStatus, robotUIDFromTopicSource, statusMessage.getMessage());
}
}
}
// Scenario 2: Message contains a general robot status update.

View File

@@ -127,41 +127,51 @@ public class ParkingSpotServiceImpl extends ServiceImpl<ParkingSpotMapper, Parki
return false;
}
ParkingSpot parkingSpot = this.findBySpotUid(spotUID);
ParkingSpot parkingSpot = this.findBySpotUid(spotUID);
if (parkingSpot == null) {
log.warn("更新车位状态失败:未找到 UID 为 {} 的车位。", spotUID);
return false;
}
ParkingSpot spotToUpdate = new ParkingSpot();
spotToUpdate.setId(parkingSpot.getId());
boolean changed = false;
// Compare enum with String value from entity
if (newStatus != null && !newStatus.getValue().equals(parkingSpot.getStatus())) {
spotToUpdate.setStatus(newStatus.getValue()); // Set String value to entity
changed = true;
// 彻底重构:创建一个包含所有最终状态的更新对象,避免复杂的条件逻辑。
// 这是解决顽固的 "empty set clause" 问题的最稳健方法。
boolean needsUpdate = false;
// 检查状态是否需要更新
if (!newStatus.getValue().equals(parkingSpot.getStatus())) {
needsUpdate = true;
}
if (currentSessionId == null && parkingSpot.getCurrentSessionId() != null) {
spotToUpdate.setCurrentSessionId(null);
changed = true;
} else if (currentSessionId != null && !currentSessionId.equals(parkingSpot.getCurrentSessionId())) {
// 检查会话ID是否需要更新
Long targetSessionId = (newStatus == ParkingSpotStatusEnum.AVAILABLE) ? null : currentSessionId;
if (targetSessionId == null && parkingSpot.getCurrentSessionId() != null) {
needsUpdate = true;
} else if (targetSessionId != null && !targetSessionId.equals(parkingSpot.getCurrentSessionId())) {
needsUpdate = true;
}
if (!needsUpdate) {
log.info("车位 {} 的状态与数据库一致 (状态: {}, 会话ID: {}),无需更新。",
spotUID, newStatus, currentSessionId == null ? "null" : currentSessionId);
return true; // 数据一致,操作成功
}
// 创建一个完整的更新实体
ParkingSpot spotToUpdate = new ParkingSpot();
spotToUpdate.setId(parkingSpot.getId());
spotToUpdate.setStatus(newStatus.getValue());
if (newStatus == ParkingSpotStatusEnum.AVAILABLE) {
spotToUpdate.setCurrentSessionId(null);
} else {
spotToUpdate.setCurrentSessionId(currentSessionId);
changed = true;
}
if (!changed) {
log.info("车位 {} 的状态与数据库一致 (状态: {}, 会话ID: {}),无需更新。",
spotUID, newStatus, currentSessionId == null ? "null" : currentSessionId);
return true; // Data is consistent, operation considered successful
}
// updateTime will be auto-filled
boolean success = this.updateById(spotToUpdate);
if (success) {
log.info("成功更新车位 {} 的状态。新状态: {}, 当前会话ID: {}",
spotUID, newStatus, currentSessionId == null ? "null" : currentSessionId);
log.info("成功更新车位 {} 的状态。新状态: {}, 当前会话ID: {}",
spotUID, spotToUpdate.getStatus(), spotToUpdate.getCurrentSessionId() == null ? "null" : spotToUpdate.getCurrentSessionId());
} else {
log.error("更新车位 {} 的状态失败 (数据库操作失败)。", spotUID);
}