package com.ruoyi.system.service.impl; import com.ruoyi.common.config.LegacySystemConfig; import com.ruoyi.system.domain.DispatchOrd; import com.ruoyi.system.domain.SysTask; import com.ruoyi.system.domain.SysTaskEmergency; import com.ruoyi.system.domain.enums.TaskStatus; import com.ruoyi.system.mapper.SysTaskMapper; import com.ruoyi.system.service.IDispatchOrdService; import com.ruoyi.system.service.ISysTaskEmergencyService; import com.ruoyi.system.service.ITaskStatusSyncService; import com.ruoyi.system.utils.TaskStatusConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; /** * 任务状态同步Service业务层处理 * 负责从旧系统同步任务状态到新系统 * * @author ruoyi * @date 2024-01-16 */ @Service public class TaskStatusSyncServiceImpl implements ITaskStatusSyncService { private static final Logger log = LoggerFactory.getLogger(TaskStatusSyncServiceImpl.class); @Autowired private LegacySystemConfig legacyConfig; @Autowired private SysTaskMapper sysTaskMapper; @Autowired private ISysTaskEmergencyService sysTaskEmergencyService; @Autowired private IDispatchOrdService dispatchOrdService; /** * 从旧系统同步单个任务状态到新系统 * * @param taskId 任务ID * @return 是否同步成功 */ @Override @Transactional public boolean syncTaskStatusFromLegacy(Long taskId) { if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用,跳过状态同步,任务ID: {}", taskId); return false; } try { // 查询任务信息 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { log.error("任务不存在,任务ID: {}", taskId); return false; } // 只同步急救转运任务 if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) { log.info("非急救转运任务,跳过状态同步,任务ID: {}", taskId); return false; } // 查询急救转运扩展信息 SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency == null) { log.error("急救转运扩展信息不存在,任务ID: {}", taskId); return false; } // 必须已经同步过调度单 if (emergency.getLegacyDispatchOrdId() == null || emergency.getLegacyDispatchOrdId() <= 0) { log.warn("调度单未同步,无法同步状态,任务ID: {}", taskId); return false; } // 查询旧系统状态(直接查询SQL Server数据库) Integer legacyStatus = dispatchOrdService.selectDispatchOrdStateByID(emergency.getLegacyDispatchOrdId()); if (legacyStatus == null) { log.error("查询旧系统状态失败,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); return false; } // 调用内部方法同步状态 return syncTaskStatusWithLegacyState(taskId, legacyStatus); } catch (Exception e) { log.error("同步任务状态异常,任务ID: {}", taskId, e); return false; } } /** * 批量同步已同步调度单的任务状态(从旧系统到新系统) * 使用分页查询,批量查询SQL Server数据库,减少网络请求次数 * * @return 成功同步的任务数量 */ @Override public int batchSyncTaskStatusFromLegacy() { if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用"); return 0; } try { int totalSuccessCount = 0; int pageSize = 200; // 每页200条 int offset = 0; while (true) { // 1. 分页查询新系统中需要同步状态的任务(已同步调度单且状态未完成) List syncedTasks = sysTaskEmergencyService.selectSyncedTasksForStatusUpdate(offset, pageSize); if (syncedTasks == null || syncedTasks.isEmpty()) { log.info("没有更多需要同步状态的任务,offset: {}", offset); break; // 没有更多数据,退出循环 } log.info("开始同步状态第 {} 页,任务数量: {}", (offset / pageSize) + 1, syncedTasks.size()); // 2. 提取调度单ID列表 List dispatchOrdIDs = new ArrayList<>(); Map dispatchIdToTaskMap = new HashMap<>(); for (SysTaskEmergency emergency : syncedTasks) { Long dispatchOrdId = emergency.getLegacyDispatchOrdId(); if (dispatchOrdId != null && dispatchOrdId > 0) { dispatchOrdIDs.add(dispatchOrdId); dispatchIdToTaskMap.put(dispatchOrdId, emergency); } } if (dispatchOrdIDs.isEmpty()) { log.warn("本页没有有效的调度单ID"); offset += pageSize; continue; } // 3. 批量查询旧系统调度单状态(直接查询SQL Server数据库) List dispatchOrds = dispatchOrdService.selectDispatchOrdStatesByIDs(dispatchOrdIDs); if (dispatchOrds == null || dispatchOrds.isEmpty()) { log.warn("未查询到旧系统调度单状态"); offset += pageSize; continue; } // 4. 构建调度单ID到状态的映射 Map dispatchIdToStateMap = new HashMap<>(); for (DispatchOrd dispatchOrd : dispatchOrds) { try { Long dispatchOrdId = Long.parseLong(dispatchOrd.getDispatchOrdID()); Integer dispatchOrdState = Integer.parseInt(dispatchOrd.getDispatchOrdState()); if (dispatchOrdState != null) { dispatchIdToStateMap.put(dispatchOrdId, dispatchOrdState); } } catch (NumberFormatException e) { log.error("解析调度单ID失败: {}", dispatchOrd.getDispatchOrdID(), e); } } // 5. 遍历任务,同步状态 int pageSuccessCount = 0; for (Map.Entry entry : dispatchIdToTaskMap.entrySet()) { Long dispatchOrdId = entry.getKey(); SysTaskEmergency emergency = entry.getValue(); // 获取旧系统状态 Integer legacyStatus = dispatchIdToStateMap.get(dispatchOrdId); if (legacyStatus == null) { log.warn("未找到调度单状态,DispatchOrdID: {}", dispatchOrdId); continue; } // 同步单个任务状态 boolean result = syncTaskStatusWithLegacyState(emergency.getTaskId(), legacyStatus); if (result) { pageSuccessCount++; } } totalSuccessCount += pageSuccessCount; log.info("状态第 {} 页同步完成,总数: {}, 成功: {}", (offset / pageSize) + 1, syncedTasks.size(), pageSuccessCount); // 如果本页数据少于每页大小,说明已经是最后一页 if (syncedTasks.size() < pageSize) { log.info("已到达最后一页,状态同步结束"); break; } offset += pageSize; // 下一页 } log.info("批量同步任务状态完成,总成功数: {}", totalSuccessCount); return totalSuccessCount; } catch (Exception e) { log.error("批量同步任务状态异常", e); return 0; } } /** * 同步单个任务状态(已知旧系统状态码) * 增加状态对比逻辑:当旧系统状态落后于新系统状态时,不进行同步 * * @param taskId 任务ID * @param legacyStatus 旧系统状态码 * @return 是否成功 */ @Transactional private boolean syncTaskStatusWithLegacyState(Long taskId, Integer legacyStatus) { try { // 查询任务信息 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { log.error("任务不存在,任务ID: {}", taskId); return false; } // 转换为新系统状态 TaskStatus newStatus = TaskStatusConverter.convertFromLegacyStatus(legacyStatus); if (newStatus == null) { log.debug("旧系统状态码 > 10 或无法转换,跳过同步,任务ID: {}, 状态码: {} ({})", taskId, legacyStatus, TaskStatusConverter.getLegacyStatusDescription(legacyStatus)); return false; } // 检查状态是否变化 if (newStatus.getCode().equals(task.getTaskStatus())) { log.debug("任务状态未变化,任务ID: {}, 当前状态: {}", taskId, newStatus.getInfo()); return true; } // 比较新旧系统状态的优先级,防止状态倒退 TaskStatus currentStatus = TaskStatus.getByCode(task.getTaskStatus()); if (currentStatus != null && !shouldSyncStatus(currentStatus, newStatus, legacyStatus)) { log.info("【旧系统更新到新系统】 旧系统状态落后于新系统状态,跳过同步,任务ID: {}, 新系统状态: {} ({}), 旧系统状态: {} ({})", taskId, task.getTaskStatus(), currentStatus.getInfo(), newStatus.getCode(), TaskStatusConverter.getLegacyStatusDescription(legacyStatus)); return false; } // 更新任务状态 String oldStatus = task.getTaskStatus(); task.setTaskStatus(newStatus.getCode()); // 根据状态设置时间 Date now = new Date(); switch (newStatus) { case DEPARTING: case ARRIVED: case IN_PROGRESS: // 如果实际开始时间为空,设置实际开始时间 if (task.getActualStartTime() == null) { task.setActualStartTime(now); } break; case COMPLETED: case CANCELLED: // 设置实际结束时间 if (task.getActualEndTime() == null) { task.setActualEndTime(now); } // 如果实际开始时间为空,也设置一下 if (task.getActualStartTime() == null) { task.setActualStartTime(now); } break; default: break; } sysTaskMapper.updateSysTask(task); log.info("任务状态同步成功,任务ID: {}, 旧状态: {}, 新状态: {}, 旧系统状态码: {} ({})", taskId, oldStatus, newStatus.getCode(), legacyStatus, TaskStatusConverter.getLegacyStatusDescription(legacyStatus)); return true; } catch (Exception e) { log.error("同步任务状态异常,任务ID: {}", taskId, e); return false; } } /** * 判断是否应该同步状态 * 规则:旧系统状态码需要大于等于新系统当前状态对应的旧系统状态码 * 防止因为时间差导致新系统状态比旧系统更新,而被旧系统的旧状态覆盖 * * @param currentStatus 新系统当前状态 * @param targetStatus 旧系统转换后的目标状态 * @param legacyStatusCode 旧系统状态码 * @return true-应该同步,false-不应该同步 */ private boolean shouldSyncStatus(TaskStatus currentStatus, TaskStatus targetStatus, Integer legacyStatusCode) { // 获取新系统当前状态对应的旧系统状态码 Integer currentLegacyCode = TaskStatusConverter.convertToLegacyStatus(currentStatus); if (currentLegacyCode == null) { // 如果当前状态无法转换为旧系统状态码,允许同步 log.warn("新系统当前状态无法转换为旧系统状态码,允许同步,当前状态: {}", currentStatus.getCode()); return true; } // 比较状态码大小 // 旧系统状态码 >= 新系统当前状态对应的旧系统状态码,才允许同步 // 例如:新系统已经是"出发中"(4),旧系统还是"待处理"(3),则不同步 // 新系统是"出发中"(4),旧系统是"已到达"(5)或"出发中"(4),则同步 boolean shouldSync = legacyStatusCode >= currentLegacyCode; if (!shouldSync) { log.debug("状态对比:旧系统状态码({}) < 新系统当前状态对应码({})", legacyStatusCode, currentLegacyCode); } return shouldSync; } }