chore: 【ops】保洁员状态管理
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package com.viewsh.module.ops.environment.integration.adapter;
|
||||
|
||||
import com.viewsh.module.ops.core.dispatch.model.AssigneeStatus;
|
||||
import com.viewsh.module.ops.environment.dal.dataobject.cleaner.OpsCleanerStatusDO;
|
||||
import com.viewsh.module.ops.enums.CleanerStatusEnum;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 保洁员状态适配器
|
||||
* <p>
|
||||
* 将 {@link OpsCleanerStatusDO} 适配为通用的 {@link AssigneeStatus} 接口
|
||||
* <p>
|
||||
* 设计说明:
|
||||
* - 适配器模式:将保洁业务特定的状态对象转换为通用接口
|
||||
* - 解耦设计:调度引擎通过通用接口访问保洁员状态,不依赖具体业务实现
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
public class CleanerAssigneeStatusAdapter implements AssigneeStatus {
|
||||
|
||||
private final OpsCleanerStatusDO cleanerStatus;
|
||||
private final Long waitingTaskCount;
|
||||
|
||||
public CleanerAssigneeStatusAdapter(OpsCleanerStatusDO cleanerStatus) {
|
||||
this(cleanerStatus, 0L);
|
||||
}
|
||||
|
||||
public CleanerAssigneeStatusAdapter(OpsCleanerStatusDO cleanerStatus, Long waitingTaskCount) {
|
||||
this.cleanerStatus = cleanerStatus;
|
||||
this.waitingTaskCount = waitingTaskCount != null ? waitingTaskCount : 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return cleanerStatus.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIdle() {
|
||||
CleanerStatusEnum statusEnum = cleanerStatus.getStatusEnum();
|
||||
return statusEnum == CleanerStatusEnum.IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBusy() {
|
||||
CleanerStatusEnum statusEnum = cleanerStatus.getStatusEnum();
|
||||
return statusEnum == CleanerStatusEnum.BUSY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
CleanerStatusEnum statusEnum = cleanerStatus.getStatusEnum();
|
||||
return statusEnum != CleanerStatusEnum.OFFLINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCurrentTaskCount() {
|
||||
// 有正在执行的工单则返回1,否则返回0
|
||||
return cleanerStatus.getCurrentOpsOrderId() != null ? 1L : 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getWaitingTaskCount() {
|
||||
return waitingTaskCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getAssigneeId() {
|
||||
return cleanerStatus.getUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssigneeName() {
|
||||
return cleanerStatus.getUserName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getAreaId() {
|
||||
return cleanerStatus.getCurrentAreaId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime getLastHeartbeatTime() {
|
||||
return cleanerStatus.getLastHeartbeatTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getBatteryLevel() {
|
||||
return cleanerStatus.getBatteryLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getExtension(String key) {
|
||||
// 支持业务特定的扩展属性
|
||||
switch (key) {
|
||||
case "deviceId":
|
||||
return cleanerStatus.getDeviceId();
|
||||
case "deviceCode":
|
||||
return cleanerStatus.getDeviceCode();
|
||||
case "currentAreaName":
|
||||
return cleanerStatus.getCurrentAreaName();
|
||||
case "currentOrderId":
|
||||
return cleanerStatus.getCurrentOpsOrderId();
|
||||
case "currentOrderCode":
|
||||
return cleanerStatus.getCurrentOpsOrderCode();
|
||||
case "statusChangeTime":
|
||||
return cleanerStatus.getStatusChangeTime();
|
||||
case "offlineReason":
|
||||
return cleanerStatus.getOfflineReason();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始的保洁员状态对象
|
||||
*/
|
||||
public OpsCleanerStatusDO getCleanerStatus() {
|
||||
return cleanerStatus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.viewsh.module.ops.environment.integration.listener;
|
||||
|
||||
import com.viewsh.module.ops.core.event.OrderCompletedEvent;
|
||||
import com.viewsh.module.ops.core.event.OrderStateChangedEvent;
|
||||
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||
import com.viewsh.module.ops.environment.service.cleaner.CleanerStatusService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 保洁员状态变更监听器
|
||||
* <p>
|
||||
* 职责:订阅工单状态变更事件,同步更新保洁员状态
|
||||
* <p>
|
||||
* 设计说明:
|
||||
* - 使用 @EventListener 订阅领域事件
|
||||
* - 业务逻辑同步执行(保证状态一致性)
|
||||
* - 通过事件驱动解耦通用层与业务层
|
||||
* - 只处理保洁类型的工单(orderType = "CLEAN")
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CleanerStateChangeListener {
|
||||
|
||||
@Resource
|
||||
private CleanerStatusService cleanerStatusService;
|
||||
|
||||
/**
|
||||
* 订阅状态变更事件
|
||||
* <p>
|
||||
* 只处理保洁类型的工单(orderType = "CLEAN")
|
||||
*/
|
||||
@EventListener
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void onOrderStateChanged(OrderStateChangedEvent event) {
|
||||
// 只处理保洁类型的工单
|
||||
if (!"CLEAN".equals(event.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("保洁工单状态变更: orderId={}, {} -> {}, assigneeId={}",
|
||||
event.getOrderId(), event.getOldStatus(), event.getNewStatus(), event.getOperatorId());
|
||||
|
||||
Long assigneeId = event.getOperatorId();
|
||||
if (assigneeId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.getNewStatus()) {
|
||||
case DISPATCHED:
|
||||
// 派单:不改变保洁员状态(等待保洁员确认)
|
||||
log.debug("工单已派发,等待保洁员确认: orderId={}, assigneeId={}",
|
||||
event.getOrderId(), assigneeId);
|
||||
break;
|
||||
|
||||
case CONFIRMED:
|
||||
// 确认:保洁员变更为 BUSY
|
||||
updateCleanerStatus(assigneeId, com.viewsh.module.ops.enums.CleanerStatusEnum.BUSY,
|
||||
"确认工单: " + event.getOrderId());
|
||||
// 设置当前工单
|
||||
cleanerStatusService.setCurrentWorkOrder(assigneeId, event.getOrderId(),
|
||||
event.getOrderCode());
|
||||
break;
|
||||
|
||||
case ARRIVED:
|
||||
// 到岗:保洁员保持 BUSY
|
||||
updateCleanerStatus(assigneeId, com.viewsh.module.ops.enums.CleanerStatusEnum.BUSY,
|
||||
"开始作业: " + event.getOrderId());
|
||||
break;
|
||||
|
||||
case PAUSED:
|
||||
// 暂停:根据暂停原因决定状态
|
||||
handlePausedStatus(event, assigneeId);
|
||||
break;
|
||||
|
||||
case COMPLETED:
|
||||
case CANCELLED:
|
||||
// 完成/取消:清理当前工单,状态由 autoDispatchNext 决定
|
||||
cleanerStatusService.clearCurrentWorkOrder(assigneeId);
|
||||
log.info("工单完成或取消,已清理当前工单: assigneeId={}, orderId={}",
|
||||
assigneeId, event.getOrderId());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅工单完成事件
|
||||
* <p>
|
||||
* 在工单完成后自动推送下一个任务或设置保洁员为空闲
|
||||
*/
|
||||
@EventListener
|
||||
@Async("ops-task-executor")
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
|
||||
public void onOrderCompleted(OrderCompletedEvent event) {
|
||||
// 只处理保洁类型的工单
|
||||
if (!"CLEAN".equals(event.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("保洁工单完成事件: orderId={}, assigneeId={}, workDuration={}秒",
|
||||
event.getOrderId(), event.getAssigneeId(), event.getWorkDuration());
|
||||
|
||||
Long assigneeId = event.getAssigneeId();
|
||||
if (assigneeId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理当前工单
|
||||
cleanerStatusService.clearCurrentWorkOrder(assigneeId);
|
||||
|
||||
// 注意:状态更新(IDLE/BUSY)由 autoDispatchNextOrder 处理
|
||||
// 这里只负责清理当前工单记录
|
||||
}
|
||||
|
||||
// ==================== 私有方法 ====================
|
||||
|
||||
/**
|
||||
* 处理暂停状态
|
||||
*/
|
||||
private void handlePausedStatus(OrderStateChangedEvent event, Long assigneeId) {
|
||||
String interruptReason = event.getPayloadString("interruptReason");
|
||||
|
||||
if ("P0_TASK_INTERRUPT".equals(interruptReason)) {
|
||||
// P0任务打断:释放保洁员资源
|
||||
log.warn("保洁任务被P0任务打断: orderId={}, assigneeId={}",
|
||||
event.getOrderId(), assigneeId);
|
||||
cleanerStatusService.clearCurrentWorkOrder(assigneeId);
|
||||
// 状态保持 BUSY,因为有P0任务要处理
|
||||
} else {
|
||||
// 普通暂停:保洁员变更为 PAUSED
|
||||
updateCleanerStatus(assigneeId, com.viewsh.module.ops.enums.CleanerStatusEnum.PAUSED,
|
||||
event.getRemark() != null ? event.getRemark() : "任务暂停");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新保洁员状态
|
||||
*/
|
||||
private void updateCleanerStatus(Long userId, com.viewsh.module.ops.enums.CleanerStatusEnum newStatus,
|
||||
String remark) {
|
||||
try {
|
||||
cleanerStatusService.updateStatus(userId, newStatus, remark);
|
||||
log.info("保洁员状态已更新: userId={}, newStatus={}, remark={}",
|
||||
userId, newStatus, remark);
|
||||
} catch (Exception e) {
|
||||
log.error("更新保洁员状态失败: userId={}, newStatus={}", userId, newStatus, e);
|
||||
// 不抛出异常,避免影响主流程
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user