app/pages/index.vue
@@ -89,7 +89,11 @@ </view> <!-- 正在运行的任务列表 --> <scroll-view class="running-tasks-section" scroll-y="true"> <scroll-view class="running-tasks-section" scroll-y="true" @scrolltolower="onScrollToLower" > <view class="task-list"> <view class="task-item" v-for="task in runningTasks" :key="task.id"> <view class="task-main" @click="viewTaskDetail(task)"> @@ -215,6 +219,15 @@ <uni-icons type="info" size="40" color="#ccc"></uni-icons> <text>暂无正在运行的任务</text> </view> <!-- 加载更多提示 --> <view class="load-more" v-if="runningTasks.length > 0 && hasMore && loading"> <uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons> <text>正在加载更多数据...</text> </view> <view class="load-more no-more" v-else-if="runningTasks.length > 0 && !hasMore"> <text>没有更多数据了</text> </view> </view> </scroll-view> </view> @@ -241,11 +254,17 @@ unreadMessageCount: 0, // 正在运行的任务列表 taskList: [], allTaskList: [], // 存储所有任务数据 displayedTaskList: [], // 存储当前显示的任务数据 loading: false, // 订阅状态 hasSubscribed: false, // 前端分页相关 currentPage: 1, pageSize: 10, hasMore: true, }; }, computed: { @@ -256,7 +275,7 @@ // 正在运行的任务(待处理和各种处理中的任务) runningTasks() { return this.taskList.filter((task) => { return this.displayedTaskList.filter((task) => { // 包含待处理、出发中、已到达、返程中等所有未完成的状态 return [ "PENDING", @@ -299,10 +318,16 @@ // 每次显示页面时刷新任务列表、绑定车辆和消息数量 this.loadUserVehicle(); // 重新加载任务列表时重置分页 this.currentPage = 1; this.hasMore = true; this.loadRunningTasks(); this.loadUnreadMessageCount(); }, onPullDownRefresh() { // 下拉刷新时重置分页参数 this.currentPage = 1; this.hasMore = true; // 下拉刷新 this.loadRunningTasks(); setTimeout(() => { @@ -310,6 +335,13 @@ }, 1000); }, methods: { // 滚动到底部时加载更多 onScrollToLower() { if (this.hasMore && !this.loading) { this.loadMoreTasks(); } }, // 自动订阅(小程序启动时调用) autoSubscribeOnLaunch() { subscribeManager.autoSubscribe() @@ -438,9 +470,16 @@ this.loading = false; // 根据后端返回的数据结构进行解析 const data = response.data || response.rows || response || []; // 过滤出未完成的任务 const allTasks = Array.isArray(data) ? data : []; this.taskList = allTasks // 如果是第一页,直接替换数据;否则追加数据 if (this.currentPage === 1) { this.allTaskList = data; } else { this.allTaskList = [...this.allTaskList, ...data]; } // 格式化任务数据 this.allTaskList = this.allTaskList .filter((task) => { // 只显示未完成和未取消的任务 return ( @@ -480,11 +519,30 @@ status: this.convertStatus(task.taskStatus), // 转换状态格式以兼容旧UI }; }); // 更新显示的任务列表 this.updateDisplayedTaskList(); }) .catch((error) => { this.loading = false; console.error("加载任务列表失败:", error); }); }, // 更新显示的任务列表(前端分页) updateDisplayedTaskList() { const start = 0; const end = this.currentPage * this.pageSize; this.displayedTaskList = this.allTaskList.slice(start, end); this.hasMore = end < this.allTaskList.length; }, // 加载更多任务(前端分页) loadMoreTasks() { if (!this.hasMore || this.loading) return; this.currentPage++; this.updateDisplayedTaskList(); }, // 格式化地址 - 只显示-前面的部分 @@ -1149,6 +1207,19 @@ margin-top: 20rpx; } } .load-more { display: flex; justify-content: center; align-items: center; padding: 20rpx 0; color: #999; font-size: 28rpx; &.no-more { color: #666; } } } } </style> app/pages/task/index.vue
@@ -213,6 +213,14 @@ <uni-icons type="info" size="40" color="#ccc"></uni-icons> <text>暂无任务数据</text> </view> <!-- 加载更多提示 --> <view class="load-more" v-if="filteredTaskList.length > 0 && hasMore"> <uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons> <text>正在加载更多数据...</text> </view> <view class="load-more no-more" v-else-if="filteredTaskList.length > 0 && !hasMore"> <text>没有更多数据了</text> </view> </view> </scroll-view> </view> @@ -251,7 +259,13 @@ // 任务列表 taskList: [], loading: false, refreshing: false refreshing: false, // 分页相关 currentPage: 1, pageSize: 10, total: 0, hasMore: true } }, computed: { @@ -342,6 +356,12 @@ onPullDownRefresh() { this.refreshList() }, // 监听滚动到底部事件 onReachBottom() { if (this.hasMore && !this.loading) { this.loadMore() } }, methods: { // 处理刷新事件 handleRefreshEvent() { @@ -352,16 +372,27 @@ // 加载任务列表 loadTaskList() { this.loading = true // 重置分页参数 this.currentPage = 1 this.hasMore = true this.taskList = [] // 后端会自动获取当前用户信息,实现综合查询 // 综合查询:当前用户所在机构任务 + 当前用户创建的任务 + 分配给当前用户的任务 const queryParams = { pageNum: 1, pageSize: 100 pageNum: this.currentPage, pageSize: this.pageSize, orderByColumn: 'create_time', isAsc: 'desc' } listTask(queryParams).then(response => { this.loading = false const data = response.data || response.rows || [] // 设置总数和是否有更多数据 this.total = response.total || data.length || 0 this.hasMore = data.length === this.pageSize this.taskList = data.map(task => { // 从assignedVehicles数组中获取车辆信息 let vehicleInfo = '未分配车辆' @@ -389,6 +420,60 @@ this.loading = false console.error('加载任务列表失败:', error) this.$modal.showToast('加载任务列表失败') }) }, // 加载更多数据 loadMore() { if (!this.hasMore || this.loading) return this.loading = true this.currentPage++ const queryParams = { pageNum: this.currentPage, pageSize: this.pageSize, orderByColumn: 'create_time', isAsc: 'desc' } listTask(queryParams).then(response => { this.loading = false const data = response.data || response.rows || [] // 更新是否有更多数据 this.hasMore = data.length === this.pageSize const newTasks = data.map(task => { // 从assignedVehicles数组中获取车辆信息 let vehicleInfo = '未分配车辆' if (task.assignedVehicles && task.assignedVehicles.length > 0) { // 如果有多个车辆,显示第一个,并标注数量 const firstVehicle = task.assignedVehicles[0] vehicleInfo = firstVehicle.vehicleNo || '未知车牌' if (task.assignedVehicles.length > 1) { vehicleInfo += ` 等${task.assignedVehicles.length}辆` } } return { ...task, // 格式化显示字段 - 使用后端返回的assignedVehicles数据 vehicle: vehicleInfo, vehicleList: task.assignedVehicles || [], startLocation: this.formatAddress(task.departureAddress || task.startLocation || '未设置'), endLocation: this.formatAddress(task.destinationAddress || task.endLocation || '未设置'), startTime: task.plannedStartTime ? formatDateTime(task.plannedStartTime, 'YYYY-MM-DD HH:mm') : '未设置', assignee: task.assigneeName || '未分配' } }) // 将新数据追加到现有列表中 this.taskList = [...this.taskList, ...newTasks] }).catch(error => { this.loading = false this.currentPage-- // 出错时回退页码 console.error('加载更多任务失败:', error) this.$modal.showToast('加载更多任务失败') }) }, @@ -1080,5 +1165,18 @@ margin-top: 20rpx; } } .load-more { display: flex; justify-content: center; align-items: center; padding: 20rpx 0; color: #999; font-size: 28rpx; &.no-more { color: #666; } } } </style> app/pagesTask/components/DepartmentSelector.vue
@@ -100,10 +100,11 @@ departmentOptions: { immediate: true, handler() { if (this.value) { this.updateSelectedIndex(this.value) } else if (this.departmentId) { // 优先使用科室ID进行匹配,如果没有科室ID再使用科室名称 if (this.departmentId) { this.updateSelectedIndexById(this.departmentId) } else if (this.value) { this.updateSelectedIndex(this.value) } } } @@ -225,6 +226,4 @@ color: #999; } } } </style> } app/pagesTask/edit-emergency.vue
@@ -231,7 +231,7 @@ import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue' import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue' import { getTask, updateTask } from "@/api/task" import { baiduDistanceByAddress } from "@/api/map" import { tiandituDistanceByAddress } from "@/api/map" import { calculateTransferPrice } from "@/api/price" import MapSelector from './components/map-selector.vue' import VehicleSelector from './components/VehicleSelector.vue' @@ -569,6 +569,7 @@ this.taskForm.hospitalOut.department = '其它' this.taskForm.hospitalOut.departmentId = null } // 注意:选择新的医院时,不自动更新科室信息,保持用户已选择的科室 // 如果转入地址已填写,自动计算距离 if (this.taskForm.hospitalIn.address) { @@ -599,6 +600,7 @@ this.taskForm.hospitalIn.department = '其它' this.taskForm.hospitalIn.departmentId = null } // 注意:选择新的医院时,不自动更新科室信息,保持用户已选择的科室 // 如果转出地址已填写,自动计算距离 if (this.taskForm.hospitalOut.address) { @@ -621,6 +623,7 @@ // 转出科室变化 onHospitalOutDepartmentChange(data) { console.log('转出科室变化:', data) if (data && typeof data === 'object') { this.taskForm.hospitalOut.department = data.department this.taskForm.hospitalOut.departmentId = data.departmentId @@ -632,6 +635,7 @@ // 转入科室变化 onHospitalInDepartmentChange(data) { console.log('转入科室变化:', data) if (data && typeof data === 'object') { this.taskForm.hospitalIn.department = data.department this.taskForm.hospitalIn.departmentId = data.departmentId @@ -826,6 +830,12 @@ return false } // 验证联系电话格式 if (this.taskForm.patient.phone && !/^1[3-9]\d{9}$/.test(this.taskForm.patient.phone)) { this.$modal.showToast('请输入正确的手机号码') return false } if (!this.taskForm.hospitalOut.name) { this.$modal.showToast('请输入转出医院名称') return false @@ -836,6 +846,11 @@ return false } if (!this.taskForm.hospitalOut.department) { this.$modal.showToast('请选择转出科室') return false } if (!this.taskForm.hospitalIn.name) { this.$modal.showToast('请输入转入医院名称') return false @@ -843,6 +858,46 @@ if (!this.taskForm.hospitalIn.address) { this.$modal.showToast('请选择转入医院地址') return false } if (!this.taskForm.hospitalIn.department) { this.$modal.showToast('请选择转入科室') return false } // 验证成交价必填 if (!this.taskForm.price || this.taskForm.price.trim() === '') { this.$modal.showToast('请输入成交价') return false } // 验证成交价格式(必须是数字) if (isNaN(this.taskForm.price) || parseFloat(this.taskForm.price) < 0) { this.$modal.showToast('请输入有效的成交价') return false } // 验证患者身份证格式(如果填写了) if (this.taskForm.patient.idCard && this.taskForm.patient.idCard.trim() !== '') { const idCard = this.taskForm.patient.idCard.trim() // 简单验证18位身份证 if (!/^\d{17}[\dXx]$/.test(idCard)) { this.$modal.showToast('请输入正确的18位身份证号码') return false } } // 验证病情至少选择一项或填写其他描述 if ((!this.selectedDiseases || this.selectedDiseases.length === 0) && (!this.taskForm.patient.otherCondition || this.taskForm.patient.otherCondition.trim() === '')) { this.$modal.showToast('请选择病情或填写其他病情描述') return false } // 验证执行人员至少选择一个 if (!this.selectedStaff || this.selectedStaff.length === 0) { this.$modal.showToast('请至少选择一个执行人员') return false } @@ -1008,7 +1063,8 @@ // 调用百度地图API计算距离 const region = this.selectedRegion || '广州' baiduDistanceByAddress(fromAddress, region, toAddress, region) //baiduDistanceByAddress(fromAddress, region, toAddress, region) tiandituDistanceByAddress(fromAddress,toAddress) .then(response => { uni.hideLoading() @@ -1333,5 +1389,4 @@ } } } } </style> } ruoyi-admin/src/main/resources/application-dev.yml
@@ -119,6 +119,7 @@ # 急救转运创建接口路径 (可选,默认值如下) emergency-create-path: /admin_save_19.gds emergency-update-path: /admin_save_20.asp # HTTP连接超时时间(毫秒) (可选,默认30秒) connect-timeout: 30000 ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java
@@ -17,6 +17,8 @@ /** 急救转运创建接口路径 */ private String emergencyCreatePath = "/admin_save_19.gds"; private String emergencyUpdatePath="/admin_save_20.asp"; /** 调度单创建接口路径 */ private String dispatchCreatePath = "/admin_save_24.gds"; @@ -129,6 +131,10 @@ public String getEmergencyCreateUrl() { return baseUrl + emergencyCreatePath; } public String getEmergencyUpdateUrl(){ return baseUrl+emergencyUpdatePath; } /** * 获取完整的调度单创建URL ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java
@@ -78,8 +78,7 @@ /** 转入医院信息 */ private HospitalInfo hospitalIn; /** 转运公里数 */ private BigDecimal transferDistance; /** 成交价 */ private BigDecimal price; @@ -473,13 +472,6 @@ this.hospitalIn = hospitalIn; } public BigDecimal getTransferDistance() { return transferDistance; } public void setTransferDistance(BigDecimal transferDistance) { this.transferDistance = transferDistance; } public BigDecimal getPrice() { return price; ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java
@@ -1,10 +1,16 @@ package com.ruoyi.system.event; import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.BOBYQAOptimizer; /** * 服务单同步任务成功后触发事件 */ public class TaskServiceOrderSyncEvent extends TaskEvent{ private Boolean needSync; public Boolean getNeedSync(){ return this.needSync; } private Long serviceOrderId; public Long getServiceOrderId(){ return this.serviceOrderId; @@ -17,8 +23,9 @@ * @param taskCode * @param serviceOrderId */ public TaskServiceOrderSyncEvent(Object source, Long taskId, String taskCode,Long serviceOrderId) { public TaskServiceOrderSyncEvent(Object source, Long taskId, String taskCode,Long serviceOrderId,Boolean isNeedSync) { super(source, taskId, taskCode); this.serviceOrderId=serviceOrderId; this.needSync=isNeedSync; } } ruoyi-system/src/main/java/com/ruoyi/system/event/TaskUpdateEvent.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.event; /** * 任务更新事件 */ public class TaskUpdateEvent extends TaskEvent{ private String taskType; public String getTaskType(){ return this.taskType; } public TaskUpdateEvent(Object source, Long taskId, String taskCode,String taskType) { super(source, taskId, taskCode); this.taskType = taskType; } } ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java
@@ -2,10 +2,10 @@ import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.utils.DeptUtil; import com.ruoyi.common.utils.LongUtil; import com.ruoyi.system.domain.*; import com.ruoyi.system.event.TaskDispatchSyncEvent; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysTaskAssigneeService; import com.ruoyi.system.event.*; import com.ruoyi.system.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,16 +14,11 @@ import org.springframework.stereotype.Component; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.event.TaskCreatedEvent; import com.ruoyi.system.event.TaskAssignedEvent; import com.ruoyi.system.event.TaskStatusChangedEvent; import com.ruoyi.system.mapper.SysMessageMapper; import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.system.mapper.SysTaskMapper; import com.ruoyi.system.mapper.SysTaskEmergencyMapper; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.system.service.INotifyTaskService; import com.ruoyi.system.service.INotifyDispatchService; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -85,6 +80,12 @@ sendDispatchNotify(assigneeIds, task.getCreatorId(), event.getTaskId(),task.getShowTaskCode(), buildNotifyContent(task, emergency)); } } Long taskId= event.getTaskId(); Long dispatchOrdId= event.getDispatchOrderId(); Long serviceOrdId= event.getServiceOrderId(); Integer oaUserID= event.getOaUserId(); legacySystemSyncService.syncTaskAttachment(taskId, dispatchOrdId, serviceOrdId, oaUserID); }catch (Exception ex){ log.error("处理任务派发同步事件失败", ex); @@ -221,6 +222,31 @@ } @Autowired private ILegacySystemSyncService legacySystemSyncService; @Async @EventListener public void handleTaskUpdateEvent(TaskUpdateEvent event){ log.info("收到任务更新事件,任务ID:{},任务编号:{}", event.getTaskId(), event.getTaskCode()); legacySystemSyncService.resyncDispatchOrderToLegacy(event.getTaskId()); } //在这里监听派发的事件 @Async @EventListener public void handleTaskServiceOrderSyncEvent(TaskServiceOrderSyncEvent event) { // log.info("收到任务服务单同步事件,任务ID:{},任务编号:{},服务单ID:{}", event.getTaskId(), event.getTaskCode(), event.getServiceOrderId()); Long dispatchOrderId= legacySystemSyncService.syncDispatchOrderToLegacy(event.getTaskId()); // if(LongUtil.isNotEmpty(dispatchOrderId)){ // //更新needsync为0 // // } } /** * 监听任务分配事件 * 创建通知任务,由通知分发服务决定发送渠道 ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacySystemSyncService.java
@@ -9,7 +9,8 @@ * @date 2024-01-20 */ public interface ILegacySystemSyncService { /** * 同步急救转运任务到旧系统 * @@ -40,7 +41,9 @@ * @return 旧系统返回的DispatchOrdID,失败返回null */ Long syncDispatchOrderToLegacy(Long taskId); void syncTaskAttachment(Long taskId, Long dispatchOrdId, Long serviceOrdId, Integer oaUserID); /** * 批量同步未同步的调度单 * ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskDispatchSyncService.java
New file @@ -0,0 +1,16 @@ package com.ruoyi.system.service; /** * 新系统中同步调度到旧系统 */ public interface ITaskDispatchSyncService { Long syncDispatch(Long taskId); /** * 同步调度单的数据 * @param taskId * @return */ boolean resyncDispatchOrderToLegacy(Long taskId); } ruoyi-system/src/main/java/com/ruoyi/system/service/TaskEmergencySyncService.java
New file @@ -0,0 +1,13 @@ package com.ruoyi.system.service; /** * 新系统同步到旧系统(服务单 )同步 */ public interface TaskEmergencySyncService { /** * 新系统同步到旧系统(服务单 )同步 */ Long syncEmergency(Long taskId); } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java
@@ -1,25 +1,10 @@ package com.ruoyi.system.service.impl; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; import com.ruoyi.common.utils.MapValueUtils; import com.ruoyi.common.utils.LongUtil; import com.ruoyi.system.domain.*; import com.ruoyi.system.event.TaskDispatchSyncEvent; import com.ruoyi.system.event.TaskServiceOrderSyncEvent; import com.ruoyi.system.mapper.*; import com.ruoyi.system.service.*; import com.ruoyi.system.task.ITaskAttachmentService; @@ -27,18 +12,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.config.LegacySystemConfig; import com.ruoyi.common.utils.MapValueUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.system.domain.vo.TaskCreateVO; import com.ruoyi.system.utils.TaskStatusConverter; import org.springframework.util.CollectionUtils; /** * 旧系统同步Service业务层处理 @@ -96,141 +72,23 @@ @Autowired private LegacyTransferSyncMapper legacyTransferSyncMapper; public Map<String,Object> getLegacyDispatchByDispatchId(Long dispatchId) { List<Map<String, Object>> result = legacyTransferSyncMapper.selectByDispatchId(dispatchId); if(!CollectionUtils.isEmpty(result)){ return result.get(0); }else{ return null; } } private Map<String,Object> getLegacyByServiceOrdId(Long serviceOrdId) { List<Map<String, Object>> result = legacyTransferSyncMapper.selectByServiceOrdId(serviceOrdId); if(!CollectionUtils.isEmpty(result)){ return result.get(0); }else{ return null; } } /** * 同步急救转运任务到旧系统 */ @Autowired private TaskEmergencySyncService taskEmergencySyncService; @Autowired private ITaskDispatchSyncService taskDispatchSyncService; @Override public Long syncEmergencyTaskToLegacy(Long taskId) { if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用,跳过任务ID: {}", taskId); return null; } try { // 查询任务信息 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { log.error("任务不存在,任务ID: {}", taskId); return null; } // 只同步急救转运任务 if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) { log.info("非急救转运任务,跳过同步,任务ID: {}", taskId); return null; } // 查询急救转运扩展信息 SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency == null) { log.error("急救转运扩展信息不存在,任务ID: {}", taskId); return null; } // 如果已经同步过,不再重复同步 if (emergency.getLegacyServiceOrdId() != null && emergency.getLegacyServiceOrdId() > 0) { // log.info("任务已同步过,任务ID: {}, ServiceOrdID: {}", taskId, emergency.getLegacyServiceOrdId()); return emergency.getLegacyServiceOrdId(); } // 更新同步状态为同步中 emergency.setSyncStatus(1); sysTaskEmergencyService.updateSysTaskEmergency(emergency); // 构建请求参数 Map<String, String> params = buildSyncParams(task, emergency); // 发送HTTP请求 String response = sendHttpPost(legacyConfig.getEmergencyCreateUrl(), params); // 解析响应 Long serviceOrdId = parseResponse(response); if (serviceOrdId != null && serviceOrdId > 0) { // 同步成功,更新记录 emergency.setLegacyServiceOrdId(serviceOrdId); emergency.setSyncStatus(2); // 同步成功 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg(null); Map<String, Object> legacy = getLegacyByServiceOrdId(serviceOrdId); String serviceOrdNo = MapValueUtils.getStringValue(legacy, "ServiceOrdNo"); if(serviceOrdNo!=null) { emergency.setLegacyServiceOrdNo(serviceOrdNo); } String serviceOrdClass = MapValueUtils.getStringValue(legacy, "ServiceOrdClass"); if(serviceOrdClass!=null) { emergency.setLegacyServiceOrdClass(serviceOrdClass); } Date serviceCCTime = MapValueUtils.getDateValue(legacy, "ServiceOrd_CC_Time"); if(serviceCCTime!=null) { emergency.setLegacyServiceNsTime(serviceCCTime); } sysTaskEmergencyService.updateSysTaskEmergency(emergency); // 更新任务主表同步标记 task.setLegacySynced(1); sysTaskMapper.updateSysTask(task); eventPublisher.publishEvent(new TaskServiceOrderSyncEvent(this, taskId, task.getTaskCode(), serviceOrdId)); // log.info("任务同步成功,任务ID: {}, ServiceOrdID: {}", taskId, serviceOrdId); return serviceOrdId; } else { // 同步失败 emergency.setSyncStatus(3); // 同步失败 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg("旧系统返回无效的ServiceOrdID: " + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("任务同步失败,任务ID: {}, 响应: {}", taskId, response); return null; } } catch (Exception e) { log.error("同步任务到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setSyncStatus(3); // 同步失败 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg("同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新同步状态失败", ex); } return null; } return taskEmergencySyncService.syncEmergency(taskId); } //在这里监听派发的事件 @EventListener public void handleTaskServiceOrderSyncEvent(TaskServiceOrderSyncEvent event) { // log.info("收到任务服务单同步事件,任务ID:{},任务编号:{},服务单ID:{}", event.getTaskId(), event.getTaskCode(), event.getServiceOrderId()); syncDispatchOrderToLegacy(event.getTaskId()); } /** * 批量同步未同步的急救转运任务 * 使用分页查询,确保所有符合条件的任务都能被同步 @@ -261,7 +119,7 @@ int pageSuccessCount = 0; for (SysTaskEmergency emergency : pendingTasks) { Long serviceOrdId = syncEmergencyTaskToLegacy(emergency.getTaskId()); if (serviceOrdId != null && serviceOrdId > 0) { if (LongUtil.isNotEmpty(serviceOrdId)) { pageSuccessCount++; } @@ -314,12 +172,17 @@ // 重新同步 Long serviceOrdId = syncEmergencyTaskToLegacy(taskId); return serviceOrdId != null && serviceOrdId > 0; return LongUtil.isNotEmpty(serviceOrdId); } catch (Exception e) { log.error("重新同步任务失败,任务ID: {}", taskId, e); return false; } } @Override public Long syncDispatchOrderToLegacy(Long taskId) { return taskDispatchSyncService.syncDispatch(taskId); } @@ -342,196 +205,17 @@ } }); } /** * 同步调度单到旧系统(admin_save_24.asp) */ @Override public Long syncDispatchOrderToLegacy(Long taskId) { if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用,跳过调度单同步,任务ID: {}", taskId); return null; } try { // 查询任务信息 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { log.error("任务不存在,任务ID: {}", taskId); return null; } // 只同步急救转运任务 if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) { log.info("非急救转运任务,跳过调度单同步,任务ID: {}", taskId); return null; } // 查询急救转运扩展信息 SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency == null) { log.error("急救转运扩展信息不存在,任务ID: {}", taskId); return null; } // 如果已经同步过,不再重复同步 if (emergency.getLegacyDispatchOrdId() != null && emergency.getLegacyDispatchOrdId() > 0) { // log.info("调度单已同步过,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); return emergency.getLegacyDispatchOrdId(); } Long serviceOrdId=emergency.getLegacyServiceOrdId(); // 必须先同步服务单 if (serviceOrdId == null || serviceOrdId <= 0) { log.warn("服务单未同步,无法同步调度单,任务ID: {}", taskId); return null; } // ====== 前置校验:确保任务数据完整 ====== // 1. 检查是否已分配车辆 List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles == null || taskVehicles.isEmpty()) { log.warn("任务未分配车辆,跳过调度单同步,任务ID: {}", taskId); return null; } // 2. 检查是否已分配执行人员 List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees == null || taskAssignees.isEmpty()) { log.warn("任务未分配执行人员,跳过调度单同步,任务ID: {}", taskId); return null; } // 3. 检查预约时间是否有效(必须大于1970年) if (task.getPlannedStartTime() == null) { log.warn("任务未设置预约时间,跳过调度单同步,任务ID: {}", taskId); return null; } // 检查预约时间是否大于1970-01-01(时间戳0对应1970-01-01 00:00:00) long timestamp1970 = 0L; if (task.getPlannedStartTime().getTime() <= timestamp1970) { log.warn("任务预约时间无效(小于等于1970年),跳过调度单同步,任务ID: {}, 预约时间: {}", taskId, task.getPlannedStartTime()); return null; } // 4. 检查转出医院信息 if (StringUtils.isEmpty(emergency.getHospitalOutName())) { log.warn("任务未设置转出医院,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getHospitalOutAddress())) { log.warn("任务未设置转出医院地址,跳过调度单同步,任务ID: {}", taskId); return null; } // 5. 检查转入医院信息 if (StringUtils.isEmpty(emergency.getHospitalInName())) { log.warn("任务未设置转入医院,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getHospitalInAddress())) { log.warn("任务未设置转入医院地址,跳过调度单同步,任务ID: {}", taskId); return null; } // 6. 检查患者基本信息 if (StringUtils.isEmpty(emergency.getPatientName())) { log.warn("任务未设置患者姓名,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getPatientPhone())) { log.warn("任务未设置患者电话,跳过调度单同步,任务ID: {}", taskId); return null; } log.info("任务数据校验通过,开始同步调度单,任务ID: {}", taskId); // 更新同步状态为同步中 emergency.setDispatchSyncStatus(1); sysTaskEmergencyService.updateSysTaskEmergency(emergency); SysUser u=sysUserMapper.selectUserById(task.getCreatorId()); Integer oaUserID= u.getOaUserId(); // 构建请求参数 Map<String, String> params = buildDispatchOrderParams(task, emergency); // 发送HTTP请求 String response = sendHttpPost(legacyConfig.getDispatchCreateUrl(), params); // 解析响应 Long dispatchOrdId = parseResponse(response); if (dispatchOrdId != null && dispatchOrdId > 0) { // 同步成功,更新记录 emergency.setLegacyDispatchOrdId(dispatchOrdId); emergency.setDispatchSyncStatus(2); // 同步成功 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg(null); //更新调度单信息开到新系统 Map<String,Object> dispatchInfo = this.getLegacyDispatchByDispatchId(dispatchOrdId); if (dispatchInfo != null) { emergency.setLegacyDispatchNsTime(MapValueUtils.getDateValue(dispatchInfo, "DispatchOrd_NS_Time")); // 同步成功 emergency.setLegacyDispatchOrdClass(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdClass")); // 同步成功 emergency.setLegacyDispatchOrdNo(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdNo")); // 同步成功 emergency.setLegacyServiceNsTime(MapValueUtils.getDateValue(dispatchInfo, "ServiceOrd_CC_Time")); // 同步成功 emergency.setLegacyServiceOrdClass(MapValueUtils.getStringValue(dispatchInfo, "ServiceOrdClass")); // 同步成功 } sysTaskEmergencyService.updateSysTaskEmergency(emergency); eventPublisher.publishEvent(new TaskDispatchSyncEvent(this, taskId, task.getTaskCode(),serviceOrdId, dispatchOrdId, oaUserID)); // log.info("调度单同步成功,任务ID: {}, DispatchOrdID: {}", taskId, dispatchOrdId); return dispatchOrdId; } else { // 同步失败 emergency.setDispatchSyncStatus(3); // 同步失败 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg("旧系统返回无效的DispatchOrdID: " + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("调度单同步失败,任务ID: {}, 响应: {}", taskId, response); return null; } } catch (Exception e) { log.error("同步调度单到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setDispatchSyncStatus(3); // 同步失败 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg("同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新调度单同步状态失败", ex); } return null; } } @EventListener public void handleTaskDispatchSyncEvent(TaskDispatchSyncEvent event) { Long taskId = event.getTaskId(); Long dispatchOrdId = event.getDispatchOrderId(); Long serviceOrdId = event.getServiceOrderId(); Integer oaUserID = event.getOaUserId(); public void syncTaskAttachment(Long taskId, Long dispatchOrdId, Long serviceOrdId, Integer oaUserID){ List<SysTaskAttachment> taskAttachments= sysTaskService.getAttachmentsByTaskId(taskId); if (taskAttachments != null && !taskAttachments.isEmpty()) { //同步附件 this.syncAttachmentToLegacy(taskAttachments,serviceOrdId,dispatchOrdId,oaUserID); } } /** * 批量同步未同步的调度单 * 使用分页查询,确保所有符合条件的任务都能被同步 @@ -599,915 +283,27 @@ return 0; } } /** * 构建调度单同步参数 */ private Map<String, String> buildDispatchOrderParams(SysTask task, SysTaskEmergency emergency) { Map<String, String> params = new HashMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 获取管理员ID(创建人ID对应的OA_UserID) String adminID = this.getAdminID(task); // 获取调度单类型(从任务所属部门的调度单编码获取) String dispatchOrdClass = "SA"; // 默认值 if (task.getDeptId() != null) { try { SysDept dept = sysDeptMapper.selectDeptById(task.getDeptId()); if (dept != null && StringUtils.isNotEmpty(dept.getDispatchOrderClass())) { dispatchOrdClass = dept.getDispatchOrderClass(); // log.info("获取任务所属部门的调度单编码成功,部门ID: {}, 调度单编码: {}", task.getDeptId(), dispatchOrdClass); } } catch (Exception e) { log.error("查询任务所属部门信息异常,部门ID: {}", task.getDeptId(), e); } } params.put("AdminID", adminID); // 基本信息 params.put("DispatchOrdClass", dispatchOrdClass); params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString()); params.put("DispatchOrdState", "1"); // 调度单状态 // 时间信息 if (task.getPlannedStartTime() != null) { params.put("DispatchOrdTraSDTime", sdf.format(task.getPlannedStartTime())); // 拟出发时间 } else { params.put("DispatchOrdTraSDTime", ""); } params.put("DispatchOrd_NS_Time", task.getCreateTime() != null ? sdf.format(task.getCreateTime()) : sdf.format(new Date())); // 开单时间 // 车辆信息 - 从任务关联的车辆获取CarID Long carId = getTaskVehicleCarId(task.getTaskId()); params.put("DispatchOrdCarID", carId.toString()); // 联系人信息 params.put("DispatchOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("DispatchOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("ServiceOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdPtName", StringUtils.nvl(emergency.getPatientName(), "")); params.put("ServiceOrdTraStreet",StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); // 地址信息 params.put("DispatchOrdTraStreet", StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); params.put("DispatchOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); params.put("DispatchOrdTraVia", ""); // 实际途经地 // 操作命令 params.put("DispatchOrd_Check", "0"); // 3=直接强制完成 // 绩效和费用:确保数值字段不为null String transferPrice = "0"; if (emergency.getTransferPrice() != null) { try { transferPrice = emergency.getTransferPrice().toString(); if (transferPrice.contains(".")) { transferPrice = new java.math.BigDecimal(transferPrice).stripTrailingZeros().toPlainString(); } } catch (Exception e) { log.warn("转换转运价格失败,任务ID: {}, 使用默认值0", task.getTaskId(), e); transferPrice = "0"; } } params.put("DispatchOrdPerfomance", transferPrice); params.put("StretcherMoney", "0"); // 抬担架费 params.put("AddMoneyType", ""); // 附加项目 params.put("AddMoney", "0"); // 附加项目费用 params.put("AddMoneyExplain", ""); // 附加项目说明 // 人员信息 params.put("EntourageName_aid1", ""); // 外援人员1 params.put("EntourageName_aid2", ""); // 外援人员2 params.put("DispatchOrd_NS_ID", adminID); // 调度人员ID params.put("RecommendedCar", ""); // 指定车型 params.put("ServiceOrdTaskRemarks", StringUtils.nvl(task.getTaskDescription(), "")); // 医护司备注 // 电话信息 params.put("Phone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("TEL_Time", sdf.format(new Date())); params.put("TEL_Remarks", "新系统同步创建调度单"); // 时长信息 params.put("TimeLength_Program", "0"); // 大型活动保障时长 params.put("TimeLength_ICU", "0"); // 居家ICU时长 params.put("TimeLength_Wait", "0"); // 等待时长 // 里程数 params.put("DispatchOrdTraStreetMileage", ""); // 开始里程数 params.put("DispatchOrdTraEndMileage", ""); // 结束里程数 // 服务单相关信息(从admin_save_24.gds 221-255行补充) params.put("ServiceOrdPtCondition", StringUtils.nvl(emergency.getPatientCondition(), "")); // 病情描述 params.put("ServiceOrdPtDoctor", ""); // 患者医生 params.put("ServiceOrdPtDoctorPhone", ""); // 患者医生电话 params.put("TransferModeID", ""); // 转运方式 params.put("ServiceOrdVIP", "0"); // VIP客户 // 价格字段复用,确保一致性 params.put("ServiceOrdTraTxnPrice", transferPrice); // 成交价 params.put("ServiceOrdTraPrePayment", "0"); // 需预付款 params.put("SettlementPrice", "0"); // 结算价 params.put("ServiceOrdTraPriceReason", ""); // 差价原因 params.put("ServiceOrd_CC_ID", ""); // 客服人员ID params.put("ServiceOrd_Sale_ID", ""); // 销售人员ID params.put("ServiceOrdIntroducer", ""); // 介绍人 params.put("ServiceOrd_work_ID", ""); // 主要企微客服ID params.put("ServiceOrd_work_IDs", ""); // 其他企微客服ID params.put("ServiceOrd_work_is", "0"); // 是否企微成交 params.put("CommissionScenarioID", "0"); // 企微绩效方案 params.put("ServiceOrdApptDate", task.getPlannedStartTime() != null ? sdf.format(task.getPlannedStartTime()) : ""); // 预约时间 params.put("ServiceOrdPtDiagnosis", ""); // 诊断 params.put("ServiceOrdOperationRemarks", "新系统同步创建"); // 操作备注 params.put("ServiceOrdEstimatedOrderDate", ""); // 预计派单时间 params.put("ServiceOrdEstimatedOrderDateOld", ""); // 原预计派单时间 params.put("ServiceOrdViaDistance", "0"); // 中途距离 // 距离字段:确保不为空,避免旧系统接口报错 String transferDistance = "0"; if (emergency.getTransferDistance() != null) { try { transferDistance = emergency.getTransferDistance().toString(); // 去除可能的小数点后多余的0 if (transferDistance.contains(".")) { transferDistance = new java.math.BigDecimal(transferDistance).stripTrailingZeros().toPlainString(); } } catch (Exception e) { log.warn("转换转运距离失败,任务ID: {}, 使用默认值0", task.getTaskId(), e); transferDistance = "0"; } } params.put("ServiceOrdTraDistance", transferDistance); params.put("OrderLevel", "0"); // 查看等级 params.put("ServiceOrdDepartureType", "1"); // 预约类型 params.put("ConditionLevel", "0"); // 病重级别 params.put("DirectionType", "0"); // 转运去向 params.put("ServiceOrdPtOutHospID", emergency.getHospitalOutId() != null ? emergency.getHospitalOutId().toString() : "0"); // 转出医院ID params.put("ServiceOrdPtInHospID", emergency.getHospitalInId() != null ? emergency.getHospitalInId().toString() : "0"); // 转入医院ID params.put("ServiceOrdPtOutHosp", StringUtils.nvl(emergency.getHospitalOutName(), "")); // 转出医院 params.put("ServiceOrdTraVia", StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); // 转出地址 params.put("ServiceOrdPtInHosp", StringUtils.nvl(emergency.getHospitalInName(), "")); // 转入医院 params.put("ServiceOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); // 转入地址 params.put("FromHQ2_is", "0"); // 广州总部推送任务标记 // 病情ID列表(ICD-10疾病ID,用于诊断ICD) // 格式:逗号分隔的ID列表,如 ",1,2,3," String ordIcdId = ""; if (StringUtils.isNotEmpty(emergency.getDiseaseIds())) { // 将存储的 "1,2,3" 格式转换为旧系统要求的 ",1,2,3," 格式 ordIcdId = "," + emergency.getDiseaseIds() + ","; log.info("病情ID列表已设置,任务ID: {}, OrdICD_ID: {}", task.getTaskId(), ordIcdId); } params.put("OrdICD_ID", ordIcdId); params.put("OrdICD_ID_old", ""); // 旧病情ID列表(用于对比是否需要更新) // 执行人员信息(随行人员) syncTaskAssignees(task, params); return params; } /** * 同步任务执行人员信息到调度单随行人员参数 * * @param task 任务信息 * @param params 调度单参数Map */ private void syncTaskAssignees(SysTask task, Map<String, String> params) { try { // 获取任务的执行人员信息列表(包含角色类型) //TODO 如果有两个司机就要 设置 Entourage_1和Entourage_2 //两个护士就要设置 Entourage_4和Entourage_6 //两个医生要设置 Entourage_3和Entourage_5 List<TaskCreateVO.AssigneeInfo> assignees = getTaskAssignees(task.getTaskId()); if (assignees == null || assignees.isEmpty()) { log.warn("任务无执行人员,任务ID: {}", task.getTaskId()); // 设置默认空值 params.put("EntourageLeadID", ""); params.put("Entourage_1", ""); // 司机 params.put("Entourage_2", ""); //司机 params.put("Entourage_3", ""); // 医生 params.put("Entourage_5", ""); //医生 params.put("Entourage_4", ""); // 护士 params.put("Entourage_6", ""); // 护士 return; } String leadEntourageId = ""; // 领队的EntourageID String driverOaId = ""; // 司机的OA_UserID String doctorOaId = ""; // 医生的OA_UserID String nurseOaId = ""; // 护士的OA_UserID // 遍历执行人员,根据角色类型分配到对应的Entourage参数 for (int i = 0; i < assignees.size(); i++) { TaskCreateVO.AssigneeInfo assignee = assignees.get(i); Long userId = assignee.getUserId(); String userType = assignee.getUserType(); // 直接使用前端传递的角色类型 if (userId == null) { continue; } // 查询用户的OA_UserID SysUser user = sysUserMapper.selectUserById(userId); if (user == null || user.getOaUserId() == null) { log.warn("执行人员信息不存在或未配置OA_UserID,用户ID: {}", userId); continue; } String oaUserId = user.getOaUserId().toString(); // 根据用户类型分配到对应的Entourage参数 if ("driver".equals(userType)) { if (driverOaId.isEmpty()) { driverOaId = oaUserId; if(params.get("Entourage_1")==null) { params.put("Entourage_1", oaUserId); }else{ params.put("Entourage_2", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "1"; // 司机对应Entourage_1 } } } else if ("doctor".equals(userType)) { if (doctorOaId.isEmpty()) { doctorOaId = oaUserId; if(params.get("Entourage_3")==null) { params.put("Entourage_3", oaUserId); }else{ params.put("Entourage_5", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "3"; // 医生对应Entourage_3 } } } else if ("nurse".equals(userType)) { if (nurseOaId.isEmpty()) { nurseOaId = oaUserId; if(params.get("Entourage_4")==null) { params.put("Entourage_4", oaUserId); }else{ params.put("Entourage_6", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "4"; // 护士对应Entourage_4 } } } } // 设置参数 params.put("EntourageLeadID", leadEntourageId); // params.put("Entourage_1", driverOaId); // 司机 // params.put("Entourage_3", doctorOaId); // 医生 // params.put("Entourage_4", nurseOaId); // 护士 // log.info("任务执行人员同步成功,任务ID: {}, 领队ID: {}, 司机: {}, 医生: {}, 护士: {}", // task.getTaskId(), leadEntourageId, driverOaId, doctorOaId, nurseOaId); } catch (Exception e) { log.error("同步任务执行人员异常,任务ID: {}", task.getTaskId(), e); // 设置默认空值 params.put("EntourageLeadID", ""); params.put("Entourage_1", ""); params.put("Entourage_3", ""); params.put("Entourage_4", ""); } } /** * 获取任务的执行人员信息列表(包含角色类型) * * @param taskId 任务ID * @return 执行人员信息列表 */ private List<TaskCreateVO.AssigneeInfo> getTaskAssignees(Long taskId) { List<TaskCreateVO.AssigneeInfo> assignees = new java.util.ArrayList<>(); try { // 从数据库查询执行人员信息(按排序顺序) List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees != null && !taskAssignees.isEmpty()) { // 将数据库中的执行人员转换为AssigneeInfo对象 for (SysTaskAssignee taskAssignee : taskAssignees) { TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo(); assignee.setUserId(taskAssignee.getUserId()); assignee.setUserName(taskAssignee.getUserName()); assignee.setUserType(taskAssignee.getUserType()); assignees.add(assignee); } log.info("从数据库获取执行人员信息成功,任务ID: {}, 人员数量: {}", taskId, assignees.size()); return assignees; } // 如果数据库中没有执行人员信息,尝试从任务的主要执行人获取 // log.warn("数据库中未找到执行人员信息,尝试从任务主要执行人获取,任务ID: {}", taskId); SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task != null && task.getAssigneeId() != null) { SysUser user = sysUserMapper.selectUserById(task.getAssigneeId()); if (user != null) { TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo(); assignee.setUserId(user.getUserId()); assignee.setUserName(user.getNickName()); assignee.setUserType(getUserType(user)); // 通过角色判断类型 assignees.add(assignee); } } } catch (Exception e) { log.error("获取任务执行人员信息异常,任务ID: {}", taskId, e); } return assignees; } /** * 判断用户类型(司机/医生/护士/其他) * 根据用户的角色名称来判断 * * @param user 用户信息 * @return 用户类型:driver/doctor/nurse/other */ private String getUserType(SysUser user) { String roleName = ""; // 从用户的角色列表中获取角色名称 if (user.getRoles() != null && !user.getRoles().isEmpty()) { roleName = user.getRoles().get(0).getRoleName(); } // 判断是否为司机 if (roleName != null && roleName.contains("司机")) { return "driver"; } // 判断是否为医生 if (roleName != null && roleName.contains("医生")) { return "doctor"; } // 判断是否为护士 if (roleName != null && roleName.contains("护士")) { return "nurse"; } // 其他类型,默认为司机(保证至少有一个人员) log.warn("用户角色无法判断类型,默认为司机,用户ID: {}, 角色: {}", user.getUserId(), roleName); return "driver"; } /** * 获取任务关联车辆的旧系统CarID * * @param taskId 任务ID * @return CarID,如果未找到则返回0L */ private Long getTaskVehicleCarId(Long taskId) { try { // 从 sys_task_vehicle 表查询车辆ID List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles != null && !taskVehicles.isEmpty()) { // 取第一个关联的车辆 Long vehicleId = taskVehicles.get(0).getVehicleId(); if (vehicleId != null) { // 从 tb_vehicle_info 表获取 car_id VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoById(vehicleId); if (vehicleInfo != null && vehicleInfo.getCarId() != null) { Long carId = vehicleInfo.getCarId().longValue(); log.info("获取任务关联车辆的CarID成功,任务ID: {}, 车辆ID: {}, CarID: {}", taskId, vehicleId, carId); return carId; } else { log.warn("车辆信息中未配置CarID,任务ID: {}, 车辆ID: {}", taskId, vehicleId); } } else { log.warn("任务车辆关联记录中车辆ID为空,任务ID: {}", taskId); } } else { log.warn("任务未关联车辆,任务ID: {}", taskId); } } catch (Exception e) { log.error("查询任务关联车辆的CarID异常,任务ID: {}", taskId, e); } return 0L; } private String getAdminID(SysTask task) { String adminID=""; if (task.getCreatorId() != null) { try { SysUser creator = sysUserMapper.selectUserById(task.getCreatorId()); if (creator != null && creator.getOaUserId() != null) { adminID = creator.getOaUserId().toString(); log.info("获取创建人OA_UserID成功,用户ID: {}, OA_UserID: {}", task.getCreatorId(), adminID); } else { log.warn("创建人未配置OA_UserID,用户ID: {}", task.getCreatorId()); } } catch (Exception e) { log.error("查询创建人OA_UserID异常,用户ID: {}", task.getCreatorId(), e); } } return adminID; } /** * 构建同步参数 */ private Map<String, String> buildSyncParams(SysTask task, SysTaskEmergency emergency) { Map<String, String> params = new HashMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd"); Long taskId=task.getTaskId(); // 管理员ID(创建人ID对应的OA_UserID) String adminID = this.getAdminID(task); params.put("adminID", adminID); // 服务单分类(从任务所属部门的服务单编码获取) String serviceOrdClass = "BF"; // ServiceOrdClass默认值 if (task.getDeptId() != null) { try { SysDept dept = sysDeptMapper.selectDeptById(task.getDeptId()); if (dept != null && StringUtils.isNotEmpty(dept.getServiceOrderClass())) { // 使用部门的服务单编码作为ServiceOrdClass serviceOrdClass = dept.getServiceOrderClass(); // log.info("获取任务所属部门的服务单编码成功,部门ID: {}, 部门名称: {}, 服务单编码: {}", // task.getDeptId(), dept.getDeptName(), serviceOrdClass); } else { log.warn("任务所属部门未配置服务单编码,部门ID: {}、部门名称: {},使用默认值", task.getDeptId(), dept != null ? dept.getDeptName() : "null"); } } catch (Exception e) { log.error("查询任务所属部门信息异常,部门ID: {}", task.getDeptId(), e); } } else { log.warn("任务未关联部门,使用默认服务单编码"); } // 服务单执行区域(从任务的document_type_id获取) String serviceOrdAreaType = "1"; // 默认值 if (StringUtils.isNotEmpty(emergency.getDocumentTypeId())) { serviceOrdAreaType = emergency.getDocumentTypeId(); // log.info("获取单据类型ID成功,任务ID: {}, 单据类型ID: {}", task.getTaskId(), serviceOrdAreaType); } else { log.warn("任务未配置单据类型ID,任务ID: {},使用默认值", task.getTaskId()); } // 基础信息 params.put("ServiceOrdClass", serviceOrdClass); // 从部门的服务单编码获取 params.put("ServiceOrdAreaType", serviceOrdAreaType); // 从任务的document_type_id获取 // 服务单执行类型(从任务的task_type_id获取) String serviceOrdType = "1"; // 默认值 if (StringUtils.isNotEmpty(emergency.getTaskTypeId())) { serviceOrdType = emergency.getTaskTypeId(); // log.info("获取任务类型ID成功,任务ID: {}, 任务类型ID: {}", taskId, serviceOrdType); } else { log.warn("任务未配置任务类型ID,任务ID: {},使用默认值", taskId); } params.put("ServiceOrdType", serviceOrdType); // 服务单执行类型(从任务的task_type_id获取) params.put("ServiceOrdState", "2"); // 服务单状态(2=正式单) params.put("ServiceOrdStartDate", task.getCreateTime() != null ? sdfDate.format(task.getCreateTime()) : sdfDate.format(new Date())); // 预约时间 if (task.getPlannedStartTime() != null) { params.put("ServiceOrdApptDate", sdf.format(task.getPlannedStartTime())); } // 联系人信息 params.put("ServiceOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("ServiceOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdCoTies", ""); // 联系人与患者关系 // 患者信息 params.put("ServiceOrdPtName", StringUtils.nvl(emergency.getPatientName(), "")); params.put("ServiceOrdPtAge", ""); // 年龄 params.put("ServiceOrdPtKG", ""); // 体重 params.put("ServiceOrdPtSex", "0".equals(emergency.getPatientGender()) ? "男" : "1".equals(emergency.getPatientGender()) ? "女" : ""); params.put("ServiceOrdPtNat", ""); // 国籍 params.put("ServiceOrdPtIDCard", StringUtils.nvl(emergency.getPatientIdCard(), "")); // 医院信息 params.put("ServiceOrdPtOutHosp", StringUtils.nvl(emergency.getHospitalOutName(), "")); params.put("ServiceOrdPtOutHospID", emergency.getHospitalOutId() != null ? emergency.getHospitalOutId().toString() : "0"); // 转出医院ID params.put("ServiceOrdPtInHosp", StringUtils.nvl(emergency.getHospitalInName(), "")); params.put("ServiceOrdPtInHospID", emergency.getHospitalInId() != null ? emergency.getHospitalInId().toString() : "0"); // 转入医院ID // 科室信息 params.put("ServiceOrdPtServices", StringUtils.nvl(emergency.getHospitalOutDepartment(), "")); params.put("ServiceOrdPtServicesID", StringUtils.nvl(emergency.getHospitalOutDepartmentId(), "0")); // 转出科室ID params.put("ServiceOrdPtInServices", StringUtils.nvl(emergency.getHospitalInDepartment(), "")); params.put("ServiceOrdPtInServicesID", StringUtils.nvl(emergency.getHospitalInDepartmentId(), "0")); // 转入科室ID // 病情信息 params.put("ServiceOrdPtDiagnosis", ""); // 诊断 params.put("ServiceOrdPtCondition", StringUtils.nvl(emergency.getPatientCondition(), "")); params.put("ServiceOrdTaskRemarks", StringUtils.nvl(task.getTaskDescription(), "")); params.put("ServiceOrdPtDoctor", ""); // 患者医生 params.put("ServiceOrdPtDoctorPhone", ""); // 患者医生电话 // 地址信息 params.put("province", ""); // 出发地省份 params.put("city", ""); // 出发地城市 params.put("ServiceOrdTraStreet",task.getDepartureAddress()); //派车地址 params.put("ServiceOrdTraStreetCoo", ""); // 出发地坐标 params.put("ServiceOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); params.put("ServiceOrdTraEndCoo", ""); // 目的地坐标 params.put("ServiceOrdTraVia", ""); // 途经地 // 距离和价格信息 params.put("ServiceOrdViaDistance", "0"); // 中途距离 params.put("ServiceOrdTraDistance", emergency.getTransferDistance() != null ? emergency.getTransferDistance().toString() : "0"); params.put("ServiceOrdTraDuration", ""); // 预计行程时间 params.put("ServiceOrdTraUnitPrice", "0"); // 单价/公里 params.put("ServiceOrdTraOfferPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0"); params.put("ServiceOrdTraTxnPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0"); params.put("ServiceOrdTraPrePayment", "0"); // 需预付款 params.put("SettlementPrice", "0"); // 结算价 params.put("ServiceOrdTraPriceReason", ""); // 差价原因 // 其他信息 params.put("Phone", StringUtils.nvl(emergency.getPatientPhone(), "")); // 来电电话 params.put("TEL_Time", sdf.format(new Date())); // 来电时间 params.put("TEL_Remarks", "新系统同步"); // 来电备注 params.put("TransferModeID", ""); // 转运方式 params.put("ServiceOrdVIP", "0"); // VIP客户 params.put("ServiceOrd_CC_ID", ""); // 客服人员ID params.put("ServiceOrd_Sale_ID", ""); // 销售人员ID params.put("ServiceOrdIntroducer", ""); // 介绍人 params.put("ServiceOrd_work_ID", ""); // 主要企微客服ID params.put("ServiceOrd_work_IDs", ""); // 其他企微客服ID params.put("ServiceOrd_work_is", "0"); // 是否企微成交 params.put("CommissionScenarioID", "0"); // 企微绩效方案 params.put("ServiceOrdOperationRemarks", "新系统同步创建"); // 操作备注 params.put("ServiceOrdEstimatedOrderDate", ""); // 预计派单时间 params.put("ServiceOrdSource", "10"); // 订单来源(10=新系统) params.put("OrderLevel", "0"); // 查看等级 params.put("ServiceOrdDepartureType", "1"); // 预约类型 params.put("ConditionLevel", "0"); // 病重级别 params.put("DirectionType", "0"); // 转运去向 params.put("ServiceOrd_m", "1"); // 来源入口 params.put("FromHQ2_is", "0"); // 广州总部推送任务标记 params.put("OrderPrice_Auto", "0"); // 订单自动报价参考值 return params; } /** * 发送HTTP/HTTPS POST请求 * 支持HTTPS自签名证书 */ private String sendHttpPost(String urlString, Map<String, String> params) throws Exception { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 如果是HTTPS请求,配置SSL信任所有证书 if (conn instanceof HttpsURLConnection) { HttpsURLConnection httpsConn = (HttpsURLConnection) conn; httpsConn.setSSLSocketFactory(createTrustAllSSLContext().getSocketFactory()); httpsConn.setHostnameVerifier((hostname, session) -> true); // 信任所有主机名 // log.debug("配置HTTPS连接,信任所有SSL证书,URL: {}", urlString); } try { // 设置连接属性 conn.setRequestMethod("POST"); conn.setConnectTimeout(legacyConfig.getConnectTimeout()); conn.setReadTimeout(legacyConfig.getReadTimeout()); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + legacyConfig.getCharset()); conn.setRequestProperty("Accept-Charset", legacyConfig.getCharset()); // 构建POST数据 StringBuilder postData = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { if (postData.length() > 0) { postData.append("&"); } postData.append(URLEncoder.encode(entry.getKey(), legacyConfig.getCharset())); postData.append("="); postData.append(URLEncoder.encode(entry.getValue(), legacyConfig.getCharset())); } // 发送POST数据 try (OutputStream os = conn.getOutputStream()) { os.write(postData.toString().getBytes(legacyConfig.getCharset())); os.flush(); } // 读取响应 int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { try (BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream(), legacyConfig.getCharset()))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } return response.toString().trim(); } } else { log.error("请求失败,请求URL {},参数 {}",urlString,postData); throw new Exception("HTTP/HTTPS请求失败,响应码: " + responseCode); } } finally { conn.disconnect(); } } /** * 创建信任所有SSL证书的SSLContext * 用于支持自签名证书的HTTPS请求 * * 注意:此方法会信任所有SSL证书,包括自签名证书 * 仅用于与旧系统的内部通信,生产环境建议使用正规CA证书 */ private SSLContext createTrustAllSSLContext() throws Exception { // 创建信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { // 信任所有客户端证书 } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { // 信任所有服务器证书 } } }; // 安装信任所有证书的TrustManager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); return sslContext; } /** * 解析旧系统响应 * 预期格式: "OK:ServiceOrdID" 或错误信息 */ private Long parseResponse(String response) { if (StringUtils.isEmpty(response)) { return null; } // 去除可能的HTML标签和空白字符 response = response.replaceAll("<[^>]*>", "").trim(); // 检查是否成功响应 if (response.startsWith("OK:")) { try { String serviceOrdIdStr = response.substring(3).trim(); return Long.parseLong(serviceOrdIdStr); } catch (NumberFormatException e) { log.error("解析ServiceOrdID失败: {}", response, e); return null; } } else { log.error("旧系统返回错误: {}", response); return null; } } // 删除下面的重复方法,因为我们将使用MapValueUtils工具类中的方法 /* private String getStringValue(Map<String, Object> map, String key) { Object value = map.get(key); return value != null ? value.toString() : null; } private BigDecimal getBigDecimalValue(Map<String, Object> map, String key) { Object value = map.get(key); if (value == null) { return null; } if (value instanceof BigDecimal) { return (BigDecimal) value; } try { return new BigDecimal(value.toString()); } catch (NumberFormatException e) { return null; } } private Long getLongValue(Map<String, Object> map, String key) { Object value = map.get(key); if (value == null) { return null; } if (value instanceof Long) { return (Long) value; } try { return Long.valueOf(value.toString()); } catch (NumberFormatException e) { return null; } } private Integer getIntegerValue(Map<String, Object> map, String key) { Object value = map.get(key); if (value == null) { return null; } if (value instanceof Integer) { return (Integer) value; } try { return Integer.valueOf(value.toString()); } catch (NumberFormatException e) { return null; } } private Date getDateValue(Map<String, Object> map, String key) { Object value = map.get(key); if (value == null) { return null; } if (value instanceof Date) { return (Date) value; } // 如果是字符串,尝试解析 if (value instanceof String) { try { return DateUtils.parseDate(value.toString()); } catch (Exception e) { return null; } } return null; } private boolean isValidDateFormat(String dateStr, String format) { if (StringUtils.isEmpty(dateStr)) { return false; } try { SimpleDateFormat sdf = new SimpleDateFormat(format); sdf.setLenient(false); sdf.parse(dateStr); return true; } catch (Exception e) { return false; } } */ /** * 重新同步车辆和人员变更的任务到旧系统 * 当任务的车辆信息或人员信息发生变更时,需要调用旧系统接口重新同步 * 使用 admin_save_25.asp 接口,而不是 admin_save_24.gds */ @Override @Transactional public boolean resyncDispatchOrderToLegacy(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; } Long serviceOrdId = emergency.getLegacyServiceOrdId(); if (serviceOrdId == null || serviceOrdId <= 0) { log.warn("服务单未同步,无法重新同步调度单,任务ID: {}", taskId); return false; } // ====== 前置校验:确保任务数据完整 ====== // 1. 检查是否已分配车辆 List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles == null || taskVehicles.isEmpty()) { log.warn("任务未分配车辆,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 2. 检查是否已分配执行人员 List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees == null || taskAssignees.isEmpty()) { log.warn("任务未分配执行人员,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 3. 检查预约时间是否有效 if (task.getPlannedStartTime() == null || task.getPlannedStartTime().getTime() <= 0L) { log.warn("任务预约时间无效,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 4. 检查转出医院信息 if (StringUtils.isEmpty(emergency.getHospitalOutName()) || StringUtils.isEmpty(emergency.getHospitalOutAddress())) { log.warn("任务转出医院信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 5. 检查转入医院信息 if (StringUtils.isEmpty(emergency.getHospitalInName()) || StringUtils.isEmpty(emergency.getHospitalInAddress())) { log.warn("任务转入医院信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 6. 检查患者基本信息 if (StringUtils.isEmpty(emergency.getPatientName()) || StringUtils.isEmpty(emergency.getPatientPhone())) { log.warn("任务患者信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } log.info("任务数据校验通过,开始重新同步调度单,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); // 构建请求参数(使用相同的参数构建方法) Map<String, String> params = buildDispatchOrderParams(task, emergency); params.put("DispatchOrdID", emergency.getLegacyDispatchOrdId().toString()); params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString()); params.put("DispatchOrdState", "3"); log.info("重新同步调度单到旧系统请求参数: {}", params); // 发送HTTP请求到旧系统(使用admin_save_25.asp接口) String response = sendHttpPost(legacyConfig.getDispatchUpdateUrl(), params); // log.info("重新同步调度单到旧系统响应: ServiceOrdID:{},DispatchOrdId:{},Result: {}",emergency.getLegacyServiceOrdId(),emergency.getLegacyDispatchOrdId(), response); // 解析响应 // Long dispatchOrdId = parseResponse(response); if (response != null && response.equals("OK")) { // 重新同步成功,清除重新同步标记 SysTaskEmergency emergency=sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); Long dispatchOrderId = emergency.getLegacyDispatchOrdId(); if(LongUtil.isEmpty(dispatchOrderId)){ Long serviceOrderId= taskEmergencySyncService.syncEmergency(taskId); if(LongUtil.isNotEmpty(serviceOrderId)) { emergency.setNeedResync(0); emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg(null); // emergency.setSyncStatus(2); emergency.setSyncTime(new Date()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); // log.info("调度单重新同步成功,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); return true; } else { // 重新同步失败 emergency.setDispatchSyncErrorMsg("重新同步失败:" + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("调度单重新同步失败,任务ID: {}, 响应: {}", taskId, response); return false; } } catch (Exception e) { log.error("重新同步调度单到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setDispatchSyncErrorMsg("重新同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新调度单同步状态失败", ex); } return false; }else { return taskDispatchSyncService.resyncDispatchOrderToLegacy(taskId); } } /** * 批量重新同步需要更新的调度单 */ @@ -1526,47 +322,60 @@ while (true) { // 分页查询需要重新同步的任务 List<SysTaskEmergency> needResyncTasks = sysTaskEmergencyMapper.selectNeedResyncTasks(offset, pageSize); // log.info("查询到需要重新同步的任务数量: {}", needResyncTasks.size()); if (needResyncTasks == null || needResyncTasks.isEmpty()) { log.info("没有更多需要重新同步的任务,offset: {}", offset); break; // 没有更多数据,退出循环 } // log.info("开始重新同步调度单第 {} 页,任务数量: {}", (offset / pageSize) + 1, needResyncTasks.size()); int pageSuccessCount = 0; for (SysTaskEmergency emergency : needResyncTasks) { Long dispatchOrdId = emergency.getLegacyDispatchOrdId(); Long taskId = emergency.getTaskId(); if (LongUtil.isEmpty(dispatchOrdId)) { //没有调度单,我们就调用创建调度单 Long serviceOrderId = syncDispatchOrderToLegacy(taskId); if (LongUtil.isNotEmpty(serviceOrderId)) { emergency.setNeedResync(0); emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg(null); sysTaskEmergencyService.updateSysTaskEmergency(emergency); continue; } // log.info("开始重新同步调度单,任务ID: {}", emergency.getTaskId()); boolean success = resyncDispatchOrderToLegacy(emergency.getTaskId()); if (success) { pageSuccessCount++; boolean success = resyncDispatchOrderToLegacy(emergency.getTaskId()); if (success) { pageSuccessCount++; } // 避免过于频繁的请求 try { Thread.sleep(1000); // 每个请求间隔1秒 } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("重新同步调度单被中断"); return totalSuccessCount + pageSuccessCount; } } // 避免过于频繁的请求 try { Thread.sleep(1000); // 每个请求间隔1秒 } catch (InterruptedException e) { Thread.currentThread().interrupt(); log.warn("重新同步调度单被中断"); return totalSuccessCount + pageSuccessCount; } } totalSuccessCount += pageSuccessCount; totalSuccessCount += pageSuccessCount; // log.info("调度单重新同步第 {} 页完成,总数: {}, 成功: {}", // (offset / pageSize) + 1, needResyncTasks.size(), pageSuccessCount); // 如果本页数据少于每页大小,说明已经是最后一页 if (needResyncTasks.size() < pageSize) { // 如果本页数据少于每页大小,说明已经是最后一页 if (needResyncTasks.size() < pageSize) { // log.info("已到达最后一页,调度单重新同步结束"); break; break; } offset += pageSize; // 下一页 } offset += pageSize; // 下一页 } // log.info("批量重新同步调度单完成,总成功数: {}", totalSuccessCount); return totalSuccessCount; ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java
@@ -461,9 +461,9 @@ createTaskVo.setTaskType("EMERGENCY_TRANSFER"); // 急救转运任务 // 设置单据类型和任务类型ID(从旧系统字段映射) if (StringUtils.isNotEmpty(serviceOrdClass)) { createTaskVo.setDocumentTypeId(serviceOrdClass); String ServiceOrdAreaType = MapValueUtils.getStringValue(order, "ServiceOrdAreaType"); if (StringUtils.isNotEmpty(ServiceOrdAreaType)) { createTaskVo.setDocumentTypeId(ServiceOrdAreaType); } String serviceOrdType = MapValueUtils.getStringValue(order, "ServiceOrdType"); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java
@@ -110,7 +110,7 @@ } } emergencyInfo.setTransferDistance(createVO.getTransferDistance()); emergencyInfo.setTransferDistance(createVO.getDistance()); emergencyInfo.setTransferPrice(createVO.getPrice()); emergencyInfo.setDocumentTypeId(createVO.getDocumentTypeId()); emergencyInfo.setTaskTypeId(createVO.getTaskTypeId()); @@ -266,8 +266,8 @@ } } if (updateVO.getTransferDistance() != null) { oldEmergency.setTransferDistance(updateVO.getTransferDistance()); if (updateVO.getDistance() != null) { oldEmergency.setTransferDistance(updateVO.getDistance()); } if (updateVO.getPrice() != null) { oldEmergency.setTransferPrice(updateVO.getPrice()); @@ -428,8 +428,8 @@ } // 更新费用信息 if (createVO.getTransferDistance() != null) { existingInfo.setTransferDistance(createVO.getTransferDistance()); if (createVO.getDistance() != null) { existingInfo.setTransferDistance(createVO.getDistance()); } if (createVO.getPrice() != null) { existingInfo.setTransferPrice(createVO.getPrice()); @@ -484,6 +484,7 @@ } try { sysTaskEmergencyService.markNeedResync(taskId); } catch (Exception e) { // 标记失败不影响主流程 } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskEmergencyServiceImpl.java
@@ -134,13 +134,16 @@ if (emergency == null) { return; } emergency.setNeedResync(1); emergency.setUpdateTime(new java.util.Date()); sysTaskEmergencyMapper.updateSysTaskEmergency(emergency); // 只有已经同步过调度单的任务才需要标记重新同步 if (emergency.getDispatchSyncStatus() != null && emergency.getDispatchSyncStatus() == 2 && emergency.getLegacyDispatchOrdId() != null && emergency.getLegacyDispatchOrdId() > 0) { emergency.setNeedResync(1); sysTaskEmergencyMapper.updateSysTaskEmergency(emergency); } // // // 只有已经同步过调度单的任务才需要标记重新同步 // if (emergency.getDispatchSyncStatus() != null && emergency.getDispatchSyncStatus() == 2 // && emergency.getLegacyDispatchOrdId() != null && emergency.getLegacyDispatchOrdId() > 0) { // // } } catch (Exception e) { // 标记失败不影响主流程,只记录日志 Logger log = LoggerFactory.getLogger(SysTaskEmergencyServiceImpl.class); ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -386,8 +386,8 @@ if (createVO.getTransferTime() != null) { task.setPlannedStartTime(createVO.getTransferTime()); } if (createVO.getTransferDistance() != null) { task.setEstimatedDistance(createVO.getTransferDistance()); if (createVO.getDistance() != null) { task.setEstimatedDistance(createVO.getDistance()); } if (createVO.getPlannedStartTime() != null) { task.setPlannedStartTime(createVO.getPlannedStartTime()); @@ -481,14 +481,13 @@ @Override @Transactional public int updateSysTask(TaskUpdateVO updateVO, Boolean updateFromLegacy) { SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(updateVO.getTaskId()); if (oldTask == null) { SysTask task = sysTaskMapper.selectSysTaskByTaskId(updateVO.getTaskId()); if (task == null) { throw new RuntimeException("任务不存在"); } Long userId = SecurityUtils.getUserId(); String userName = SecurityUtils.getUsername(); SysTask task = new SysTask(); task.setTaskId(updateVO.getTaskId()); task.setTaskDescription(updateVO.getTaskDescription()); task.setPlannedStartTime(updateVO.getPlannedStartTime()); @@ -500,43 +499,32 @@ // 设置通用地址和坐标信息 task.setDepartureAddress(updateVO.getDepartureAddress()); task.setDestinationAddress(updateVO.getDestinationAddress()); task.setDepartureLongitude(updateVO.getDepartureLongitude()); task.setDepartureLatitude(updateVO.getDepartureLatitude()); task.setDestinationLongitude(updateVO.getDestinationLongitude()); task.setDestinationLatitude(updateVO.getDestinationLatitude()); // 设置预计距离 if (updateVO.getEstimatedDistance() != null) { task.setEstimatedDistance(updateVO.getEstimatedDistance()); } else if (updateVO.getTransferDistance() != null) { // 兼容急救转运字段 task.setEstimatedDistance(updateVO.getTransferDistance()); } else if (updateVO.getDistance() != null) { // 兼容福祉车字段 // 兼容急救转运字段 task.setEstimatedDistance(updateVO.getDistance()); } // 如果更新了部门ID if (updateVO.getDeptId() != null) { task.setDeptId(updateVO.getDeptId()); }else{ task.setDeptId(oldTask.getDeptId()); } // 如果更新了任务编号 if (updateVO.getTaskCode() != null) { task.setTaskCode(updateVO.getTaskCode()); } Boolean hasSetDepartureFlag=false; //设置总部推送 task.setIsHeadPush(this.isTaskHeaderPush(oldTask.getCreatorId(), task.getDeptId())?"1":"0"); task.setIsHeadPush(this.isTaskHeaderPush(task.getCreatorId(), task.getDeptId())?"1":"0"); // 自动获取出发地GPS坐标(如果更新了地址但缺失坐标) if (updateVO.getDepartureAddress() != null && (updateVO.getDepartureLongitude() == null || updateVO.getDepartureLatitude() == null) && mapService != null) { if (!updateVO.getDepartureAddress().equals(oldTask.getDepartureAddress())) { if (!updateVO.getDepartureAddress().equals(task.getDepartureAddress())) { try { Map<String, Double> coords = mapService.geocoding( updateVO.getDepartureAddress(), @@ -545,6 +533,7 @@ if (coords != null) { task.setDepartureLongitude(BigDecimal.valueOf(coords.get("lng"))); task.setDepartureLatitude(BigDecimal.valueOf(coords.get("lat"))); hasSetDepartureFlag = true; // log.info("出发地GPS坐标自动获取成功: {}, {}", coords.get("lng"), coords.get("lat")); } } catch (Exception e) { @@ -552,12 +541,20 @@ } } } // 设置通用地址和坐标信息 task.setDepartureAddress(updateVO.getDepartureAddress()); if(!hasSetDepartureFlag) { task.setDepartureLongitude(updateVO.getDepartureLongitude()); task.setDepartureLatitude(updateVO.getDepartureLatitude()); } Boolean hasSetDestinationFlag=false; // 自动获取目的地GPS坐标(如果更新了地址但缺失坐标) if (updateVO.getDestinationAddress() != null && (updateVO.getDestinationLongitude() == null || updateVO.getDestinationLatitude() == null) && mapService != null) { if (!updateVO.getDestinationAddress().equals(oldTask.getDestinationAddress())) { if (!updateVO.getDestinationAddress().equals(task.getDestinationAddress())) { try { Map<String, Double> coords = mapService.geocoding( updateVO.getDestinationAddress(), @@ -566,6 +563,7 @@ if (coords != null) { task.setDestinationLongitude(BigDecimal.valueOf(coords.get("lng"))); task.setDestinationLatitude(BigDecimal.valueOf(coords.get("lat"))); hasSetDestinationFlag = true; // log.info("目的地GPS坐标自动获取成功: {}, {}", coords.get("lng"), coords.get("lat")); } } catch (Exception e) { @@ -573,6 +571,12 @@ } } } task.setDestinationAddress(updateVO.getDestinationAddress()); if(!hasSetDestinationFlag) { task.setDestinationLongitude(updateVO.getDestinationLongitude()); task.setDestinationLatitude(updateVO.getDestinationLatitude()); } if(updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()){ TaskCreateVO.AssigneeInfo assigneeInfo= updateVO.getAssignees().get(0); task.setAssigneeId(assigneeInfo.getUserId()); @@ -593,7 +597,8 @@ needResync = true; } } // 更新执行人员(检测人员变更) if (result > 0 && updateVO.getAssignees() != null) { boolean assigneesChanged = sysTaskAssigneeService.updateTaskAssignees( @@ -605,43 +610,52 @@ } Long dispatchOrderId=0L; // 更新急救转运扩展信息(检测地址和成交价变更) if (result > 0 && "EMERGENCY_TRANSFER".equals(oldTask.getTaskType())) { if (result > 0 && "EMERGENCY_TRANSFER".equals(task.getTaskType())) { SysTaskEmergency oldEmergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(updateVO.getTaskId()); sysEmergencyTaskService.updateEmergencyInfoFromUpdateVO(oldEmergency, updateVO, userName); dispatchOrderId= oldEmergency.getLegacyDispatchOrdId(); sysEmergencyTaskService.markNeedResyncIfNecessary(updateVO.getTaskId(), oldTask, updateVO, updateFromLegacy); markNeedSync(task,updateVO); } // 更新福祉车扩展信息 if (result > 0 && "WELFARE".equals(oldTask.getTaskType())) { if (result > 0 && "WELFARE".equals(task.getTaskType())) { if (updateVO.getPassenger() != null || updateVO.getStartAddress() != null || updateVO.getEndAddress() != null) { sysWelfareTaskService.updateWelfareInfo(updateVO.getTaskId(), updateVO, userName); } } // 如果是急救转运任务且有变更,标记需要重新同步 if (result > 0 && "EMERGENCY_TRANSFER".equals(oldTask.getTaskType()) && needResync && !updateFromLegacy) { sysEmergencyTaskService.markNeedResyncIfNecessary(updateVO.getTaskId(), oldTask, updateVO, updateFromLegacy); } // 记录操作日志 if (result > 0) { recordTaskLog(updateVO.getTaskId(), "UPDATE", "更新任务", buildTaskDescription(oldTask), buildTaskDescription(task), buildTaskDescription(task), buildTaskDescription(task), userId, userName); } if(result > 0 && oldTask.getTaskStatus().equals(TaskStatus.PENDING.getCode()) if(result > 0 && task.getTaskStatus().equals(TaskStatus.PENDING.getCode()) && updateVO.getAssignees() != null && !updateVO.getAssignees().isEmpty() && LongUtil.isNotEmpty(dispatchOrderId)){ this.sendTaskAssigneeEvent(updateVO,oldTask,userId,userName); this.sendTaskAssigneeEvent(updateVO,task,userId,userName); } return result; } private void markNeedSync(SysTask sysTask,TaskUpdateVO updateVO){ // 如果是急救转运任务且有变更,标记需要重新同步 if ( "EMERGENCY_TRANSFER".equals(sysTask.getTaskType()) ) { sysEmergencyTaskService.markNeedResyncIfNecessary(updateVO.getTaskId(), sysTask, updateVO, true); eventPublisher.publishEvent(new TaskUpdateEvent(this,sysTask.getTaskId(), sysTask.getTaskCode(),sysTask.getTaskType())); } } /** * 更新任务(用于旧系统同步) * @@ -803,7 +817,8 @@ } taskEmergency.setUpdateTime(DateUtils.getNowDate()); Boolean hasEmergencyInfo = updateVO.getHospitalOut() != null || updateVO.getHospitalIn() != null || updateVO.getPatient() != null; Boolean hasEmergencyInfo = updateVO.getHospitalOut() != null || updateVO.getHospitalIn() != null || updateVO.getPatient() != null || updateVO.getPrice() != null || updateVO.getDistance() != null; // 使用TaskCreateVO的字段来更新急救转运信息 @@ -1426,8 +1441,8 @@ if (createVO.getTransferTime() != null) { task.setPlannedStartTime(createVO.getTransferTime()); } if (createVO.getTransferDistance() != null) { task.setEstimatedDistance(createVO.getTransferDistance()); if (createVO.getDistance() != null) { task.setEstimatedDistance(createVO.getDistance()); } // 设置福祉车特定信息 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncServiceImpl.java
New file @@ -0,0 +1,395 @@ package com.ruoyi.system.service.impl; import com.ruoyi.common.config.LegacySystemConfig; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.LongUtil; import com.ruoyi.common.utils.MapValueUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.SysTask; import com.ruoyi.system.domain.SysTaskAssignee; import com.ruoyi.system.domain.SysTaskEmergency; import com.ruoyi.system.domain.SysTaskVehicle; import com.ruoyi.system.domain.vo.TaskCreateVO; import com.ruoyi.system.event.TaskDispatchSyncEvent; import com.ruoyi.system.mapper.*; import com.ruoyi.system.service.ISysTaskEmergencyService; import com.ruoyi.system.service.ITaskDispatchSyncService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.util.Date; import java.util.List; import java.util.Map; /** * 同步新系统中的调度到旧系统中 */ @Slf4j @Service public class TaskDispatchSyncServiceImpl implements ITaskDispatchSyncService { @Autowired private ApplicationEventPublisher eventPublisher; @Override public Long syncDispatch(Long taskId) { return this.syncDispatchOrderToLegacy(taskId); } @Autowired private LegacySystemConfig legacyConfig; @Autowired private ISysTaskEmergencyService sysTaskEmergencyService; @Autowired private SysTaskMapper sysTaskMapper; @Autowired private SysTaskVehicleMapper sysTaskVehicleMapper; @Autowired private SysTaskAssigneeMapper sysTaskAssigneeMapper; @Autowired private SysUserMapper sysUserMapper; @Autowired private LegacyTransferSyncMapper legacyTransferSyncMapper; @Autowired private TaskSyncUtilService taskSyncUtilService; @Autowired private TaskDispatchSyncUtilService taskDispatchSyncUtilService; /** * 重新同步车辆和人员变更的任务到旧系统 * 当任务的车辆信息或人员信息发生变更时,需要调用旧系统接口重新同步 * 使用 admin_save_25.asp 接口,而不是 admin_save_24.gds */ @Override public boolean resyncDispatchOrderToLegacy(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; } Long serviceOrdId = emergency.getLegacyServiceOrdId(); if (serviceOrdId == null || serviceOrdId <= 0) { log.warn("服务单未同步,无法重新同步调度单,任务ID: {}", taskId); return false; } // ====== 前置校验:确保任务数据完整 ====== // 1. 检查是否已分配车辆 List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles == null || taskVehicles.isEmpty()) { log.warn("任务未分配车辆,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 2. 检查是否已分配执行人员 List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees == null || taskAssignees.isEmpty()) { log.warn("任务未分配执行人员,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 3. 检查预约时间是否有效 if (task.getPlannedStartTime() == null || task.getPlannedStartTime().getTime() <= 0L) { log.warn("任务预约时间无效,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 4. 检查转出医院信息 if (StringUtils.isEmpty(emergency.getHospitalOutName()) || StringUtils.isEmpty(emergency.getHospitalOutAddress())) { log.warn("任务转出医院信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 5. 检查转入医院信息 if (StringUtils.isEmpty(emergency.getHospitalInName()) || StringUtils.isEmpty(emergency.getHospitalInAddress())) { log.warn("任务转入医院信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } // 6. 检查患者基本信息 if (StringUtils.isEmpty(emergency.getPatientName()) || StringUtils.isEmpty(emergency.getPatientPhone())) { log.warn("任务患者信息不完整,跳过调度单重新同步,任务ID: {}", taskId); return false; } log.info("任务数据校验通过,开始重新同步调度单,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); // 构建请求参数(使用相同的参数构建方法) Map<String, Object> params = taskDispatchSyncUtilService.buildDispatchOrderParams(task, emergency); params.put("DispatchOrdID", emergency.getLegacyDispatchOrdId().toString()); params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString()); params.put("DispatchOrdState", "3"); log.info("重新同步调度单到旧系统请求参数: {}", params); // 发送HTTP请求到旧系统(使用admin_save_25.asp接口) String response =taskSyncUtilService.sendHttpPost(legacyConfig.getDispatchUpdateUrl(), params); log.info("重新同步调度单到旧系统响应: ServiceOrdID:{},DispatchOrdId:{},Result: {}",emergency.getLegacyServiceOrdId(),emergency.getLegacyDispatchOrdId(), response); // 解析响应 // Long dispatchOrdId = parseResponse(response); if (response != null && response.equals("OK")) { // 重新同步成功,清除重新同步标记 emergency.setNeedResync(0); emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg(null); sysTaskEmergencyService.updateSysTaskEmergency(emergency); // log.info("调度单重新同步成功,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); return true; } else { // 重新同步失败 emergency.setDispatchSyncErrorMsg("重新同步失败:" + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("调度单重新同步失败,任务ID: {}, 响应: {}", taskId, response); return false; } } catch (Exception e) { log.error("重新同步调度单到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setDispatchSyncErrorMsg("重新同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新调度单同步状态失败", ex); } return false; } } public Map<String,Object> getLegacyDispatchByDispatchId(Long dispatchId) { List<Map<String, Object>> result = legacyTransferSyncMapper.selectByDispatchId(dispatchId); if(!CollectionUtils.isEmpty(result)){ return result.get(0); }else{ return null; } } /** * 同步调度单到旧系统(admin_save_24.asp) */ private Long syncDispatchOrderToLegacy(Long taskId) { if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用,跳过调度单同步,任务ID: {}", taskId); return null; } try { // 查询任务信息 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { log.error("任务不存在,任务ID: {}", taskId); return null; } // 只同步急救转运任务 if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) { log.info("非急救转运任务,跳过调度单同步,任务ID: {}", taskId); return null; } // 查询急救转运扩展信息 SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency == null) { log.error("急救转运扩展信息不存在,任务ID: {}", taskId); return null; } // 如果已经同步过,不再重复同步 if (emergency.getLegacyDispatchOrdId() != null && emergency.getLegacyDispatchOrdId() > 0) { // log.info("调度单已同步过,任务ID: {}, DispatchOrdID: {}", taskId, emergency.getLegacyDispatchOrdId()); return emergency.getLegacyDispatchOrdId(); } Long serviceOrdId=emergency.getLegacyServiceOrdId(); // 必须先同步服务单 if (LongUtil.isEmpty(serviceOrdId)) { log.warn("服务单未同步,无法同步调度单,任务ID: {}", taskId); return null; } // ====== 前置校验:确保任务数据完整 ====== // 1. 检查是否已分配车辆 List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles == null || taskVehicles.isEmpty()) { log.warn("任务未分配车辆,跳过调度单同步,任务ID: {}", taskId); return null; } // 2. 检查是否已分配执行人员 List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees == null || taskAssignees.isEmpty()) { log.warn("任务未分配执行人员,跳过调度单同步,任务ID: {}", taskId); return null; } // 3. 检查预约时间是否有效(必须大于1970年) if (task.getPlannedStartTime() == null) { log.warn("任务未设置预约时间,跳过调度单同步,任务ID: {}", taskId); return null; } // 检查预约时间是否大于1970-01-01(时间戳0对应1970-01-01 00:00:00) long timestamp1970 = 0L; if (task.getPlannedStartTime().getTime() <= timestamp1970) { log.warn("任务预约时间无效(小于等于1970年),跳过调度单同步,任务ID: {}, 预约时间: {}", taskId, task.getPlannedStartTime()); return null; } // 4. 检查转出医院信息 if (StringUtils.isEmpty(emergency.getHospitalOutName())) { log.warn("任务未设置转出医院,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getHospitalOutAddress())) { log.warn("任务未设置转出医院地址,跳过调度单同步,任务ID: {}", taskId); return null; } // 5. 检查转入医院信息 if (StringUtils.isEmpty(emergency.getHospitalInName())) { log.warn("任务未设置转入医院,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getHospitalInAddress())) { log.warn("任务未设置转入医院地址,跳过调度单同步,任务ID: {}", taskId); return null; } // 6. 检查患者基本信息 if (StringUtils.isEmpty(emergency.getPatientName())) { log.warn("任务未设置患者姓名,跳过调度单同步,任务ID: {}", taskId); return null; } if (StringUtils.isEmpty(emergency.getPatientPhone())) { log.warn("任务未设置患者电话,跳过调度单同步,任务ID: {}", taskId); return null; } log.info("任务数据校验通过,开始同步调度单,任务ID: {}", taskId); // 更新同步状态为同步中 emergency.setDispatchSyncStatus(1); sysTaskEmergencyService.updateSysTaskEmergency(emergency); SysUser u=sysUserMapper.selectUserById(task.getCreatorId()); Integer oaUserID= u.getOaUserId(); // 构建请求参数 Map<String, Object> params = taskDispatchSyncUtilService.buildDispatchOrderParams(task, emergency); // 发送HTTP请求 String response =taskSyncUtilService.sendHttpPost(legacyConfig.getDispatchCreateUrl(), params); // 解析响应 Long dispatchOrdId = taskSyncUtilService.parseResponse(response); if (dispatchOrdId != null && dispatchOrdId > 0) { // 同步成功,更新记录 emergency.setLegacyDispatchOrdId(dispatchOrdId); emergency.setDispatchSyncStatus(2); // 同步成功 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg(null); //更新调度单信息开到新系统 Map<String,Object> dispatchInfo = this.getLegacyDispatchByDispatchId(dispatchOrdId); if (dispatchInfo != null) { emergency.setLegacyDispatchNsTime(MapValueUtils.getDateValue(dispatchInfo, "DispatchOrd_NS_Time")); // 同步成功 emergency.setLegacyDispatchOrdClass(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdClass")); // 同步成功 emergency.setLegacyDispatchOrdNo(MapValueUtils.getStringValue(dispatchInfo, "DispatchOrdNo")); // 同步成功 emergency.setLegacyServiceNsTime(MapValueUtils.getDateValue(dispatchInfo, "ServiceOrd_CC_Time")); // 同步成功 emergency.setLegacyServiceOrdClass(MapValueUtils.getStringValue(dispatchInfo, "ServiceOrdClass")); // 同步成功 } sysTaskEmergencyService.updateSysTaskEmergency(emergency); eventPublisher.publishEvent(new TaskDispatchSyncEvent(this, taskId, task.getTaskCode(),serviceOrdId, dispatchOrdId, oaUserID)); // log.info("调度单同步成功,任务ID: {}, DispatchOrdID: {}", taskId, dispatchOrdId); return dispatchOrdId; } else { // 同步失败 emergency.setDispatchSyncStatus(3); // 同步失败 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg("旧系统返回无效的DispatchOrdID: " + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("调度单同步失败,任务ID: {}, 响应: {}", taskId, response); return null; } } catch (Exception e) { log.error("同步调度单到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setDispatchSyncStatus(3); // 同步失败 emergency.setDispatchSyncTime(new Date()); emergency.setDispatchSyncErrorMsg("同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新调度单同步状态失败", ex); } return null; } } } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java
New file @@ -0,0 +1,408 @@ package com.ruoyi.system.service.impl; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.*; import com.ruoyi.system.domain.vo.TaskCreateVO; import com.ruoyi.system.mapper.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Service @Slf4j public class TaskDispatchSyncUtilService { @Autowired private SysUserMapper sysUserMapper; @Autowired private SysTaskMapper sysTaskMapper; @Autowired private SysTaskAssigneeMapper sysTaskAssigneeMapper; @Autowired private TaskSyncUtilService taskSyncUtilService; @Autowired private SysDeptMapper sysDeptMapper; /** * 构建调度单同步参数 */ public Map<String, Object> buildDispatchOrderParams(SysTask task, SysTaskEmergency emergency) { Map<String, Object> params = new HashMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 获取管理员ID(创建人ID对应的OA_UserID) String adminID = taskSyncUtilService.getAdminID(task); // 获取调度单类型(从任务所属部门的调度单编码获取) String dispatchOrdClass = "SA"; // 默认值 if (task.getDeptId() != null) { try { SysDept dept = sysDeptMapper.selectDeptById(task.getDeptId()); if (dept != null && StringUtils.isNotEmpty(dept.getDispatchOrderClass())) { dispatchOrdClass = dept.getDispatchOrderClass(); // log.info("获取任务所属部门的调度单编码成功,部门ID: {}, 调度单编码: {}", task.getDeptId(), dispatchOrdClass); } } catch (Exception e) { log.error("查询任务所属部门信息异常,部门ID: {}", task.getDeptId(), e); } } params.put("AdminID", adminID); // 基本信息 params.put("DispatchOrdClass", dispatchOrdClass); params.put("ServiceOrdID", emergency.getLegacyServiceOrdId().toString()); params.put("DispatchOrdState", "1"); // 调度单状态 // 时间信息 if (task.getPlannedStartTime() != null) { params.put("DispatchOrdTraSDTime", sdf.format(task.getPlannedStartTime())); // 拟出发时间 } else { params.put("DispatchOrdTraSDTime", ""); } params.put("DispatchOrd_NS_Time", task.getCreateTime() != null ? sdf.format(task.getCreateTime()) : sdf.format(new Date())); // 开单时间 // 车辆信息 - 从任务关联的车辆获取CarID Long carId = getTaskVehicleCarId(task.getTaskId()); params.put("DispatchOrdCarID", carId.toString()); // 联系人信息 params.put("DispatchOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("DispatchOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("ServiceOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdPtName", StringUtils.nvl(emergency.getPatientName(), "")); params.put("ServiceOrdTraStreet",StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); // 地址信息 params.put("DispatchOrdTraStreet", StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); params.put("DispatchOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); params.put("DispatchOrdTraVia", ""); // 实际途经地 // 操作命令 params.put("DispatchOrd_Check", "0"); // 3=直接强制完成 // 绩效和费用:确保数值字段不为null String transferPrice = "0"; if (emergency.getTransferPrice() != null) { try { transferPrice = emergency.getTransferPrice().toString(); if (transferPrice.contains(".")) { transferPrice = new java.math.BigDecimal(transferPrice).stripTrailingZeros().toPlainString(); } } catch (Exception e) { log.warn("转换转运价格失败,任务ID: {}, 使用默认值0", task.getTaskId(), e); transferPrice = "0"; } } params.put("DispatchOrdPerfomance", transferPrice); params.put("StretcherMoney", "0"); // 抬担架费 params.put("AddMoneyType", ""); // 附加项目 params.put("AddMoney", "0"); // 附加项目费用 params.put("AddMoneyExplain", ""); // 附加项目说明 // 人员信息 params.put("EntourageName_aid1", ""); // 外援人员1 params.put("EntourageName_aid2", ""); // 外援人员2 params.put("DispatchOrd_NS_ID", adminID); // 调度人员ID params.put("RecommendedCar", ""); // 指定车型 params.put("ServiceOrdTaskRemarks", StringUtils.nvl(task.getTaskDescription(), "")); // 医护司备注 // 电话信息 params.put("Phone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("TEL_Time", sdf.format(new Date())); params.put("TEL_Remarks", "新系统同步创建调度单"); // 时长信息 params.put("TimeLength_Program", "0"); // 大型活动保障时长 params.put("TimeLength_ICU", "0"); // 居家ICU时长 params.put("TimeLength_Wait", "0"); // 等待时长 // 里程数 params.put("DispatchOrdTraStreetMileage", ""); // 开始里程数 params.put("DispatchOrdTraEndMileage", ""); // 结束里程数 // 服务单相关信息(从admin_save_24.gds 221-255行补充) params.put("ServiceOrdPtCondition", StringUtils.nvl(emergency.getPatientCondition(), "")); // 病情描述 params.put("ServiceOrdPtDoctor", ""); // 患者医生 params.put("ServiceOrdPtDoctorPhone", ""); // 患者医生电话 params.put("TransferModeID", ""); // 转运方式 params.put("ServiceOrdVIP", "0"); // VIP客户 // 价格字段复用,确保一致性 params.put("ServiceOrdTraTxnPrice", transferPrice); // 成交价 params.put("ServiceOrdTraPrePayment", "0"); // 需预付款 params.put("SettlementPrice", "0"); // 结算价 params.put("ServiceOrdTraPriceReason", ""); // 差价原因 params.put("ServiceOrd_CC_ID", ""); // 客服人员ID params.put("ServiceOrd_Sale_ID", ""); // 销售人员ID params.put("ServiceOrdIntroducer", ""); // 介绍人 params.put("ServiceOrd_work_ID", ""); // 主要企微客服ID params.put("ServiceOrd_work_IDs", ""); // 其他企微客服ID params.put("ServiceOrd_work_is", "0"); // 是否企微成交 params.put("CommissionScenarioID", "0"); // 企微绩效方案 params.put("ServiceOrdApptDate", task.getPlannedStartTime() != null ? sdf.format(task.getPlannedStartTime()) : ""); // 预约时间 params.put("ServiceOrdPtDiagnosis", ""); // 诊断 params.put("ServiceOrdOperationRemarks", "新系统同步创建"); // 操作备注 params.put("ServiceOrdEstimatedOrderDate", ""); // 预计派单时间 params.put("ServiceOrdEstimatedOrderDateOld", ""); // 原预计派单时间 params.put("ServiceOrdViaDistance", "0"); // 中途距离 // 距离字段:确保不为空,避免旧系统接口报错 String transferDistance = "0"; if (emergency.getTransferDistance() != null) { try { transferDistance = emergency.getTransferDistance().toString(); // 去除可能的小数点后多余的0 if (transferDistance.contains(".")) { transferDistance = new java.math.BigDecimal(transferDistance).stripTrailingZeros().toPlainString(); } } catch (Exception e) { log.warn("转换转运距离失败,任务ID: {}, 使用默认值0", task.getTaskId(), e); transferDistance = "0"; } } // log.info("转运距离:{}",transferDistance); params.put("ServiceOrdTraDistance", transferDistance); params.put("OrderLevel", "0"); // 查看等级 params.put("ServiceOrdDepartureType", "1"); // 预约类型 params.put("ConditionLevel", "0"); // 病重级别 params.put("DirectionType", "0"); // 转运去向 params.put("ServiceOrdPtOutHospID", emergency.getHospitalOutId() != null ? emergency.getHospitalOutId().toString() : "0"); // 转出医院ID params.put("ServiceOrdPtServices", emergency.getHospitalOutBedNumber()==null?"":emergency.getHospitalOutBedNumber().toString()); // 转出床位 params.put("ServiceOrdPtServicesID",emergency.getHospitalOutDepartmentId()==null?"":emergency.getHospitalOutDepartmentId().toString()); // 转出科室ID params.put("ServiceOrdPtInServicesID",emergency.getHospitalInDepartmentId()==null?"":emergency.getHospitalInDepartmentId().toString()); // 转入科室ID params.put("ServiceOrdPtInServices", emergency.getHospitalInBedNumber()==null?"":emergency.getHospitalInBedNumber().toString());// 转入床位 params.put("ServiceOrdPtInHospID", emergency.getHospitalInId() != null ? emergency.getHospitalInId().toString() : "0"); // 转入医院ID params.put("ServiceOrdPtOutHosp", StringUtils.nvl(emergency.getHospitalOutName(), "")); // 转出医院 params.put("ServiceOrdTraVia", StringUtils.nvl(task.getDepartureAddress(), StringUtils.nvl(emergency.getHospitalOutAddress(), ""))); // 转出地址 params.put("ServiceOrdPtInHosp", StringUtils.nvl(emergency.getHospitalInName(), "")); // 转入医院 params.put("ServiceOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); // 转入地址 params.put("FromHQ2_is", "0"); // 广州总部推送任务标记 // 病情ID列表(ICD-10疾病ID,用于诊断ICD) // 格式:逗号分隔的ID列表,如 ",1,2,3," String ordIcdId = ""; if (StringUtils.isNotEmpty(emergency.getDiseaseIds())) { // 将存储的 "1,2,3" 格式转换为旧系统要求的 ",1,2,3," 格式 ordIcdId = "," + emergency.getDiseaseIds() + ","; log.info("病情ID列表已设置,任务ID: {}, OrdICD_ID: {}", task.getTaskId(), ordIcdId); } params.put("OrdICD_ID", ordIcdId); params.put("OrdICD_ID_old", ""); // 旧病情ID列表(用于对比是否需要更新) // 执行人员信息(随行人员) syncTaskAssignees(task, params); return params; } @Autowired private SysTaskVehicleMapper sysTaskVehicleMapper; @Autowired private VehicleInfoMapper vehicleInfoMapper; /** * 获取任务关联车辆的旧系统CarID * * @param taskId 任务ID * @return CarID,如果未找到则返回0L */ private Long getTaskVehicleCarId(Long taskId) { try { // 从 sys_task_vehicle 表查询车辆ID List<SysTaskVehicle> taskVehicles = sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId); if (taskVehicles != null && !taskVehicles.isEmpty()) { // 取第一个关联的车辆 Long vehicleId = taskVehicles.get(0).getVehicleId(); if (vehicleId != null) { // 从 tb_vehicle_info 表获取 car_id VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoById(vehicleId); if (vehicleInfo != null && vehicleInfo.getCarId() != null) { Long carId = vehicleInfo.getCarId().longValue(); log.info("获取任务关联车辆的CarID成功,任务ID: {}, 车辆ID: {}, CarID: {}", taskId, vehicleId, carId); return carId; } else { log.warn("车辆信息中未配置CarID,任务ID: {}, 车辆ID: {}", taskId, vehicleId); } } else { log.warn("任务车辆关联记录中车辆ID为空,任务ID: {}", taskId); } } else { log.warn("任务未关联车辆,任务ID: {}", taskId); } } catch (Exception e) { log.error("查询任务关联车辆的CarID异常,任务ID: {}", taskId, e); } return 0L; } /** * 获取任务的执行人员信息列表(包含角色类型) * * @param taskId 任务ID * @return 执行人员信息列表 */ private List<TaskCreateVO.AssigneeInfo> getTaskAssignees(Long taskId) { List<TaskCreateVO.AssigneeInfo> assignees = new java.util.ArrayList<>(); try { // 从数据库查询执行人员信息(按排序顺序) List<SysTaskAssignee> taskAssignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId); if (taskAssignees != null && !taskAssignees.isEmpty()) { // 将数据库中的执行人员转换为AssigneeInfo对象 for (SysTaskAssignee taskAssignee : taskAssignees) { TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo(); assignee.setUserId(taskAssignee.getUserId()); assignee.setUserName(taskAssignee.getUserName()); assignee.setUserType(taskAssignee.getUserType()); assignees.add(assignee); } log.info("从数据库获取执行人员信息成功,任务ID: {}, 人员数量: {}", taskId, assignees.size()); return assignees; } // 如果数据库中没有执行人员信息,尝试从任务的主要执行人获取 // log.warn("数据库中未找到执行人员信息,尝试从任务主要执行人获取,任务ID: {}", taskId); SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task != null && task.getAssigneeId() != null) { SysUser user = sysUserMapper.selectUserById(task.getAssigneeId()); if (user != null) { TaskCreateVO.AssigneeInfo assignee = new TaskCreateVO.AssigneeInfo(); assignee.setUserId(user.getUserId()); assignee.setUserName(user.getNickName()); assignee.setUserType(taskSyncUtilService.getUserType(user)); // 通过角色判断类型 assignees.add(assignee); } } } catch (Exception e) { log.error("获取任务执行人员信息异常,任务ID: {}", taskId, e); } return assignees; } /** * 同步任务执行人员信息到调度单随行人员参数 * * @param task 任务信息 * @param params 调度单参数Map */ private void syncTaskAssignees(SysTask task, Map<String, Object> params) { try { // 获取任务的执行人员信息列表(包含角色类型) //TODO 如果有两个司机就要 设置 Entourage_1和Entourage_2 //两个护士就要设置 Entourage_4和Entourage_6 //两个医生要设置 Entourage_3和Entourage_5 List<TaskCreateVO.AssigneeInfo> assignees = getTaskAssignees(task.getTaskId()); if (assignees == null || assignees.isEmpty()) { log.warn("任务无执行人员,任务ID: {}", task.getTaskId()); // 设置默认空值 params.put("EntourageLeadID", ""); params.put("Entourage_1", ""); // 司机 params.put("Entourage_2", ""); //司机 params.put("Entourage_3", ""); // 医生 params.put("Entourage_5", ""); //医生 params.put("Entourage_4", ""); // 护士 params.put("Entourage_6", ""); // 护士 return; } String leadEntourageId = ""; // 领队的EntourageID String driverOaId = ""; // 司机的OA_UserID String doctorOaId = ""; // 医生的OA_UserID String nurseOaId = ""; // 护士的OA_UserID // 遍历执行人员,根据角色类型分配到对应的Entourage参数 for (int i = 0; i < assignees.size(); i++) { TaskCreateVO.AssigneeInfo assignee = assignees.get(i); Long userId = assignee.getUserId(); String userType = assignee.getUserType(); // 直接使用前端传递的角色类型 if (userId == null) { continue; } // 查询用户的OA_UserID SysUser user = sysUserMapper.selectUserById(userId); if (user == null || user.getOaUserId() == null) { log.warn("执行人员信息不存在或未配置OA_UserID,用户ID: {}", userId); continue; } String oaUserId = user.getOaUserId().toString(); // 根据用户类型分配到对应的Entourage参数 if ("driver".equals(userType)) { if (driverOaId.isEmpty()) { driverOaId = oaUserId; if(params.get("Entourage_1")==null) { params.put("Entourage_1", oaUserId); }else{ params.put("Entourage_2", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "1"; // 司机对应Entourage_1 } } } else if ("doctor".equals(userType)) { if (doctorOaId.isEmpty()) { doctorOaId = oaUserId; if(params.get("Entourage_3")==null) { params.put("Entourage_3", oaUserId); }else{ params.put("Entourage_5", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "3"; // 医生对应Entourage_3 } } } else if ("nurse".equals(userType)) { if (nurseOaId.isEmpty()) { nurseOaId = oaUserId; if(params.get("Entourage_4")==null) { params.put("Entourage_4", oaUserId); }else{ params.put("Entourage_6", oaUserId); } // 如果是第一个执行人员,设置为领队 if (i == 0 && leadEntourageId.isEmpty()) { leadEntourageId = "4"; // 护士对应Entourage_4 } } } } // 设置参数 params.put("EntourageLeadID", leadEntourageId); // params.put("Entourage_1", driverOaId); // 司机 // params.put("Entourage_3", doctorOaId); // 医生 // params.put("Entourage_4", nurseOaId); // 护士 // log.info("任务执行人员同步成功,任务ID: {}, 领队ID: {}, 司机: {}, 医生: {}, 护士: {}", // task.getTaskId(), leadEntourageId, driverOaId, doctorOaId, nurseOaId); } catch (Exception e) { log.error("同步任务执行人员异常,任务ID: {}", task.getTaskId(), e); // 设置默认空值 params.put("EntourageLeadID", ""); params.put("Entourage_1", ""); params.put("Entourage_3", ""); params.put("Entourage_4", ""); } } } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java
New file @@ -0,0 +1,174 @@ package com.ruoyi.system.service.impl; import com.ruoyi.common.config.LegacySystemConfig; import com.ruoyi.common.utils.LongUtil; import com.ruoyi.common.utils.MapValueUtils; import com.ruoyi.system.domain.SysTask; import com.ruoyi.system.domain.SysTaskEmergency; import com.ruoyi.system.event.TaskServiceOrderSyncEvent; import com.ruoyi.system.mapper.LegacyTransferSyncMapper; import com.ruoyi.system.mapper.SysTaskMapper; import com.ruoyi.system.service.ISysTaskEmergencyService; import com.ruoyi.system.service.ISysTaskService; import com.ruoyi.system.service.TaskEmergencySyncService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.Date; import java.util.List; import java.util.Map; @Slf4j @Service public class TaskEmergencySyncServiceImpl implements TaskEmergencySyncService { @Autowired private ApplicationEventPublisher eventPublisher; @Autowired private ISysTaskService sysTaskService; @Autowired private SysTaskMapper sysTaskMapper; @Autowired private ISysTaskEmergencyService sysTaskEmergencyService; @Autowired private LegacySystemConfig legacyConfig; @Autowired private LegacyTransferSyncMapper legacyTransferSyncMapper; @Autowired private TaskSyncUtilService taskSyncUtilService; private Map<String,Object> getLegacyByServiceOrdId(Long serviceOrdId) { List<Map<String, Object>> result = legacyTransferSyncMapper.selectByServiceOrdId(serviceOrdId); if(!CollectionUtils.isEmpty(result)){ return result.get(0); }else{ return null; } } /** * 同步急救转运任务到旧系统 */ public Long syncEmergencyTaskToLegacy(SysTask task,SysTaskEmergency emergency,Boolean isNew) { Long taskId=task.getTaskId(); Long serviceOrderId = emergency.getLegacyServiceOrdId(); if (!legacyConfig.isEnabled()) { log.info("旧系统同步已禁用,跳过任务ID: {}", taskId); return null; } try { // 更新同步状态为同步中 emergency.setSyncStatus(1); sysTaskEmergencyService.updateSysTaskEmergency(emergency); // 构建请求参数 Map<String, Object> params = taskSyncUtilService.buildSyncParams(task, emergency); String updateUrl=legacyConfig.getEmergencyCreateUrl(); if(!isNew){ updateUrl=legacyConfig.getEmergencyUpdateUrl(); params.put("ServiceOrdID",serviceOrderId); } // 发送HTTP请求 String response = taskSyncUtilService.sendHttpPost(updateUrl, params); // 解析响应 Long serviceOrdId = taskSyncUtilService.parseResponse(response); if (LongUtil.isNotEmpty(serviceOrderId)) { // 同步成功,更新记录 emergency.setLegacyServiceOrdId(serviceOrdId); emergency.setSyncStatus(2); // 同步成功 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg(null); Map<String, Object> legacy = getLegacyByServiceOrdId(serviceOrdId); String serviceOrdNo = MapValueUtils.getStringValue(legacy, "ServiceOrdNo"); if(serviceOrdNo!=null) { emergency.setLegacyServiceOrdNo(serviceOrdNo); } String serviceOrdClass = MapValueUtils.getStringValue(legacy, "ServiceOrdClass"); if(serviceOrdClass!=null) { emergency.setLegacyServiceOrdClass(serviceOrdClass); } Date serviceCCTime = MapValueUtils.getDateValue(legacy, "ServiceOrd_CC_Time"); if(serviceCCTime!=null) { emergency.setLegacyServiceNsTime(serviceCCTime); } sysTaskEmergencyService.updateSysTaskEmergency(emergency); // 更新任务主表同步标记 task.setLegacySynced(1); sysTaskMapper.updateSysTask(task); eventPublisher.publishEvent(new TaskServiceOrderSyncEvent(this, taskId, task.getTaskCode(), serviceOrdId,!isNew)); // log.info("任务同步成功,任务ID: {}, ServiceOrdID: {}", taskId, serviceOrdId); return serviceOrdId; } else { // 同步失败 emergency.setSyncStatus(3); // 同步失败 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg("旧系统返回无效的ServiceOrdID: " + response); sysTaskEmergencyService.updateSysTaskEmergency(emergency); log.error("任务同步失败,任务ID: {}, 响应: {}", taskId, response); return null; } } catch (Exception e) { log.error("同步任务到旧系统异常,任务ID: {}", taskId, e); // 更新同步状态为失败 try { emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if (emergency != null) { emergency.setSyncStatus(3); // 同步失败 emergency.setSyncTime(new Date()); emergency.setSyncErrorMsg("同步异常: " + e.getMessage()); sysTaskEmergencyService.updateSysTaskEmergency(emergency); } } catch (Exception ex) { log.error("更新同步状态失败", ex); } return null; } } @Override public Long syncEmergency(Long taskId) { SysTask task=sysTaskService.selectSysTaskByTaskId(taskId); SysTaskEmergency emergency = sysTaskEmergencyService.selectSysTaskEmergencyByTaskId(taskId); if(emergency!=null){ Long dispatchOrderId=emergency.getLegacyDispatchOrdId(); Long serviceOrderId = emergency.getLegacyServiceOrdId(); if(LongUtil.isEmpty(dispatchOrderId) && LongUtil.isEmpty(serviceOrderId)){ //dispatch为空且 return syncNewEmergency(task,emergency); }else if(LongUtil.isNotEmpty(serviceOrderId) && LongUtil.isEmpty(dispatchOrderId)){ //serviceId不为空,dispatchOrdId为空 return syncUpdateEmergency(task,emergency); } } return 0L; } private Long syncNewEmergency(SysTask task,SysTaskEmergency emergency) { return this.syncEmergencyTaskToLegacy(task,emergency,true); } private Long syncUpdateEmergency(SysTask task,SysTaskEmergency emergency) { return this.syncEmergencyTaskToLegacy(task,emergency,false); } } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskSyncUtilService.java
New file @@ -0,0 +1,370 @@ package com.ruoyi.system.service.impl; import com.ruoyi.common.config.LegacySystemConfig; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.SysTask; import com.ruoyi.system.domain.SysTaskEmergency; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysUserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; @Slf4j @Service public class TaskSyncUtilService { @Autowired private ISysUserService sysUserService; @Autowired private ISysDeptService sysDeptService; @Autowired private LegacySystemConfig legacySystemConfig; /** * 判断用户类型(司机/医生/护士/其他) * 根据用户的角色名称来判断 * * @param user 用户信息 * @return 用户类型:driver/doctor/nurse/other */ public String getUserType(SysUser user) { String roleName = ""; // 从用户的角色列表中获取角色名称 if (user.getRoles() != null && !user.getRoles().isEmpty()) { roleName = user.getRoles().get(0).getRoleName(); } // 判断是否为司机 if (roleName != null && roleName.contains("司机")) { return "driver"; } // 判断是否为医生 if (roleName != null && roleName.contains("医生")) { return "doctor"; } // 判断是否为护士 if (roleName != null && roleName.contains("护士")) { return "nurse"; } // 其他类型,默认为司机(保证至少有一个人员) log.warn("用户角色无法判断类型,默认为司机,用户ID: {}, 角色: {}", user.getUserId(), roleName); return "driver"; } public String getAdminID(SysTask task) { String adminID=""; if (task.getCreatorId() != null) { try { SysUser creator = sysUserService.selectUserById(task.getCreatorId()); if (creator != null && creator.getOaUserId() != null) { adminID = creator.getOaUserId().toString(); log.info("获取创建人OA_UserID成功,用户ID: {}, OA_UserID: {}", task.getCreatorId(), adminID); } else { log.warn("创建人未配置OA_UserID,用户ID: {}", task.getCreatorId()); } } catch (Exception e) { log.error("查询创建人OA_UserID异常,用户ID: {}", task.getCreatorId(), e); } } return adminID; } /** * 构建同步参数 */ public Map<String, Object> buildSyncParams(SysTask task, SysTaskEmergency emergency) { Map<String, Object> params = new HashMap<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd"); Long taskId=task.getTaskId(); // 管理员ID(创建人ID对应的OA_UserID) String adminID = this.getAdminID(task); params.put("adminID", adminID); // 服务单分类(从任务所属部门的服务单编码获取) String serviceOrdClass = "BF"; // ServiceOrdClass默认值 if (task.getDeptId() != null) { try { SysDept dept = sysDeptService.selectDeptById(task.getDeptId()); if (dept != null && StringUtils.isNotEmpty(dept.getServiceOrderClass())) { // 使用部门的服务单编码作为ServiceOrdClass serviceOrdClass = dept.getServiceOrderClass(); // log.info("获取任务所属部门的服务单编码成功,部门ID: {}, 部门名称: {}, 服务单编码: {}", // task.getDeptId(), dept.getDeptName(), serviceOrdClass); } else { log.warn("任务所属部门未配置服务单编码,部门ID: {}、部门名称: {},使用默认值", task.getDeptId(), dept != null ? dept.getDeptName() : "null"); } } catch (Exception e) { log.error("查询任务所属部门信息异常,部门ID: {}", task.getDeptId(), e); } } else { log.warn("任务未关联部门,使用默认服务单编码"); } // 服务单执行区域(从任务的document_type_id获取) String serviceOrdAreaType = "1"; // 默认值 if (StringUtils.isNotEmpty(emergency.getDocumentTypeId())) { serviceOrdAreaType = emergency.getDocumentTypeId(); // log.info("获取单据类型ID成功,任务ID: {}, 单据类型ID: {}", task.getTaskId(), serviceOrdAreaType); } else { log.warn("任务未配置单据类型ID,任务ID: {},使用默认值", task.getTaskId()); } // 基础信息 params.put("ServiceOrdClass", serviceOrdClass); // 从部门的服务单编码获取 params.put("ServiceOrdAreaType", serviceOrdAreaType); // 从任务的document_type_id获取 // 服务单执行类型(从任务的task_type_id获取) String serviceOrdType = "1"; // 默认值 if (StringUtils.isNotEmpty(emergency.getTaskTypeId())) { serviceOrdType = emergency.getTaskTypeId(); // log.info("获取任务类型ID成功,任务ID: {}, 任务类型ID: {}", taskId, serviceOrdType); } else { log.warn("任务未配置任务类型ID,任务ID: {},使用默认值", taskId); } params.put("ServiceOrdType", serviceOrdType); // 服务单执行类型(从任务的task_type_id获取) params.put("ServiceOrdState", "2"); // 服务单状态(2=正式单) params.put("ServiceOrdStartDate", task.getCreateTime() != null ? sdfDate.format(task.getCreateTime()) : sdfDate.format(new Date())); // 预约时间 if (task.getPlannedStartTime() != null) { params.put("ServiceOrdApptDate", sdf.format(task.getPlannedStartTime())); } // 联系人信息 params.put("ServiceOrdCoName", StringUtils.nvl(emergency.getPatientContact(), "")); params.put("ServiceOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), "")); params.put("ServiceOrdCoTies", ""); // 联系人与患者关系 // 患者信息 params.put("ServiceOrdPtName", StringUtils.nvl(emergency.getPatientName(), "")); params.put("ServiceOrdPtAge", ""); // 年龄 params.put("ServiceOrdPtKG", ""); // 体重 params.put("ServiceOrdPtSex", "0".equals(emergency.getPatientGender()) ? "男" : "1".equals(emergency.getPatientGender()) ? "女" : ""); params.put("ServiceOrdPtNat", ""); // 国籍 params.put("ServiceOrdPtIDCard", StringUtils.nvl(emergency.getPatientIdCard(), "")); // 医院信息 params.put("ServiceOrdPtOutHosp", StringUtils.nvl(emergency.getHospitalOutName(), "")); params.put("ServiceOrdPtOutHospID", emergency.getHospitalOutId() != null ? emergency.getHospitalOutId().toString() : "0"); // 转出医院ID params.put("ServiceOrdPtInHosp", StringUtils.nvl(emergency.getHospitalInName(), "")); params.put("ServiceOrdPtInHospID", emergency.getHospitalInId() != null ? emergency.getHospitalInId().toString() : "0"); // 转入医院ID // 科室信息 params.put("ServiceOrdPtServices", StringUtils.nvl(emergency.getHospitalOutBedNumber(), "")); //转出床位 params.put("ServiceOrdPtServicesID", StringUtils.nvl(emergency.getHospitalOutDepartmentId(), "0")); // 转出科室ID params.put("ServiceOrdPtInServices", StringUtils.nvl(emergency.getHospitalInBedNumber(), "")); //转入床位 params.put("ServiceOrdPtInServicesID", StringUtils.nvl(emergency.getHospitalInDepartmentId(), "0")); // 转入科室ID // 病情信息 params.put("ServiceOrdPtDiagnosis", ""); // 诊断 //病情描述 params.put("ServiceOrdPtCondition", StringUtils.nvl(emergency.getPatientCondition(), "")); params.put("ServiceOrdTaskRemarks", StringUtils.nvl(task.getTaskDescription(), "")); params.put("ServiceOrdPtDoctor", ""); // 患者医生 params.put("ServiceOrdPtDoctorPhone", ""); // 患者医生电话 // 地址信息 params.put("province", ""); // 出发地省份 params.put("city", ""); // 出发地城市 params.put("ServiceOrdTraStreet",task.getDepartureAddress()); //派车地址 params.put("ServiceOrdTraStreetCoo", ""); // 出发地坐标 params.put("ServiceOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), ""))); params.put("ServiceOrdTraEndCoo", ""); // 目的地坐标 params.put("ServiceOrdTraVia", ""); // 途经地 // 距离和价格信息 params.put("ServiceOrdViaDistance", "0"); // 中途距离 params.put("ServiceOrdTraDistance", emergency.getTransferDistance() != null ? emergency.getTransferDistance().toString() : "0"); params.put("ServiceOrdTraDuration", ""); // 预计行程时间 params.put("ServiceOrdTraUnitPrice", "0"); // 单价/公里 params.put("ServiceOrdTraOfferPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0"); params.put("ServiceOrdTraTxnPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0"); params.put("ServiceOrdTraPrePayment", "0"); // 需预付款 params.put("SettlementPrice", "0"); // 结算价 params.put("ServiceOrdTraPriceReason", ""); // 差价原因 // 其他信息 params.put("Phone", StringUtils.nvl(emergency.getPatientPhone(), "")); // 来电电话 params.put("TEL_Time", sdf.format(new Date())); // 来电时间 params.put("TEL_Remarks", "新系统同步"); // 来电备注 params.put("TransferModeID", ""); // 转运方式 params.put("ServiceOrdVIP", "0"); // VIP客户 params.put("ServiceOrd_CC_ID", ""); // 客服人员ID params.put("ServiceOrd_Sale_ID", ""); // 销售人员ID params.put("ServiceOrdIntroducer", ""); // 介绍人 params.put("ServiceOrd_work_ID", ""); // 主要企微客服ID params.put("ServiceOrd_work_IDs", ""); // 其他企微客服ID params.put("ServiceOrd_work_is", "0"); // 是否企微成交 params.put("CommissionScenarioID", "0"); // 企微绩效方案 params.put("ServiceOrdOperationRemarks", "新系统同步创建"); // 操作备注 params.put("ServiceOrdEstimatedOrderDate", ""); // 预计派单时间 params.put("ServiceOrdSource", "10"); // 订单来源(10=新系统) params.put("OrderLevel", "0"); // 查看等级 params.put("ServiceOrdDepartureType", "1"); // 预约类型 params.put("ConditionLevel", "0"); // 病重级别 params.put("DirectionType", "0"); // 转运去向 params.put("ServiceOrd_m", "1"); // 来源入口 params.put("FromHQ2_is", "0"); // 广州总部推送任务标记 params.put("OrderPrice_Auto", "0"); // 订单自动报价参考值 return params; } /** * 发送HTTP/HTTPS POST请求 * 支持HTTPS自签名证书 */ public String sendHttpPost(String urlString, Map<String, Object> params) throws Exception { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 如果是HTTPS请求,配置SSL信任所有证书 if (conn instanceof HttpsURLConnection) { HttpsURLConnection httpsConn = (HttpsURLConnection) conn; httpsConn.setSSLSocketFactory(createTrustAllSSLContext().getSocketFactory()); httpsConn.setHostnameVerifier((hostname, session) -> true); // 信任所有主机名 // log.debug("配置HTTPS连接,信任所有SSL证书,URL: {}", urlString); } try { // 设置连接属性 conn.setRequestMethod("POST"); conn.setConnectTimeout(legacySystemConfig.getConnectTimeout()); conn.setReadTimeout(legacySystemConfig.getReadTimeout()); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + legacySystemConfig.getCharset()); conn.setRequestProperty("Accept-Charset", legacySystemConfig.getCharset()); // 构建POST数据 StringBuilder postData = new StringBuilder(); for (Map.Entry<String, Object> entry : params.entrySet()) { if (postData.length() > 0) { postData.append("&"); } postData.append(URLEncoder.encode(entry.getKey(), legacySystemConfig.getCharset())); postData.append("="); postData.append(URLEncoder.encode(entry.getValue().toString(), legacySystemConfig.getCharset())); } // log.info("发送POST请求到旧系统,URL: {}, 参数: {}", urlString, postData.toString()); // 发送POST数据 try (OutputStream os = conn.getOutputStream()) { os.write(postData.toString().getBytes(legacySystemConfig.getCharset())); os.flush(); } // 读取响应 int responseCode = conn.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { try (BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream(), legacySystemConfig.getCharset()))) { StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } return response.toString().trim(); } } else { log.error("请求失败,请求URL {},参数 {}",urlString,postData); throw new Exception("HTTP/HTTPS请求失败,响应码: " + responseCode); } } finally { conn.disconnect(); } } /** * 解析旧系统响应 * 预期格式: "OK:ServiceOrdID" 或错误信息 */ public Long parseResponse(String response) { if (StringUtils.isEmpty(response)) { return null; } // 去除可能的HTML标签和空白字符 response = response.replaceAll("<[^>]*>", "").trim(); // 检查是否成功响应 if (response.startsWith("OK:")) { try { String serviceOrdIdStr = response.substring(3).trim(); return Long.parseLong(serviceOrdIdStr); } catch (NumberFormatException e) { log.error("解析ServiceOrdID失败: {}", response, e); return null; } } else { log.error("旧系统返回错误: {}", response); return null; } } /** * 创建信任所有SSL证书的SSLContext * 用于支持自签名证书的HTTPS请求 * * 注意:此方法会信任所有SSL证书,包括自签名证书 * 仅用于与旧系统的内部通信,生产环境建议使用正规CA证书 */ private SSLContext createTrustAllSSLContext() throws Exception { // 创建信任所有证书的TrustManager TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { // 信任所有客户端证书 } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { // 信任所有服务器证书 } } }; // 安装信任所有证书的TrustManager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); return sslContext; } } ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml
@@ -152,7 +152,7 @@ b.DispatchOrdState, b.DispatchOrdNo, b.DispatchOrdClass, a.ServiceOrdClass a.ServiceOrdClass FROM ServiceOrder as a left JOIN DispatchOrd b on a.ServiceOrdID = b.ServiceOrdIDDt