wlzboy
4 小时以前 5f2ee03958a1a16dc27195c76ea7cffb422c95d1
feat: 任务修改接口,删除一些不要的字段同步
7个文件已添加
16个文件已修改
3116 ■■■■■ 已修改文件
app/pages/index.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/task/index.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/components/DepartmentSelector.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/edit-emergency.vue 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application-dev.yml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/config/LegacySystemConfig.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/TaskCreateVO.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/event/TaskServiceOrderSyncEvent.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/event/TaskUpdateEvent.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/listener/TaskMessageListener.java 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ILegacySystemSyncService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ITaskDispatchSyncService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/TaskEmergencySyncService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacySystemSyncServiceImpl.java 1283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysEmergencyTaskServiceImpl.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskEmergencyServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncServiceImpl.java 395 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskDispatchSyncUtilService.java 408 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskEmergencySyncServiceImpl.java 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskSyncUtilService.java 368 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/LegacyTransferSyncMapper.xml 补丁 | 查看 | 原始文档 | blame | 历史
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)
        }
      }
    }
@@ -226,5 +227,3 @@
    }
  }
}
</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()
          
@@ -1334,4 +1390,3 @@
    }
  }
}
</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
@@ -18,6 +18,8 @@
    /** 急救转运创建接口路径 */
    private String emergencyCreatePath = "/admin_save_19.gds";
    
    private String emergencyUpdatePath="/admin_save_20.asp";
    /** 调度单创建接口路径 */
    private String dispatchCreatePath = "/admin_save_24.gds";
    
@@ -130,6 +132,10 @@
        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
@@ -10,6 +10,7 @@
 */
public interface ILegacySystemSyncService {
    
    /**
     * 同步急救转运任务到旧系统
     * 
@@ -41,6 +42,8 @@
     */
    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业务层处理
@@ -98,139 +74,21 @@
    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;
        }
    }
    @Autowired
    private TaskEmergencySyncService taskEmergencySyncService;
    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 ITaskDispatchSyncService taskDispatchSyncService;
    @Override
    public Long syncEmergencyTaskToLegacy(Long taskId) {
        if (!legacyConfig.isEnabled()) {
            log.info("旧系统同步已禁用,跳过任务ID: {}", taskId);
            return null;
        return taskEmergencySyncService.syncEmergency(taskId);
        }
        
        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;
        }
    }
    //在这里监听派发的事件
    @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);
        }
    }
    /**
     * 批量同步未同步的调度单
     * 使用分页查询,确保所有符合条件的任务都能被同步
@@ -600,913 +284,25 @@
        }
    }
    
    /**
     * 构建调度单同步参数
     */
    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")) {
                // 重新同步成功,清除重新同步标记
        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;
            }
            return false;
            } else {
                // 重新同步失败
                emergency.setDispatchSyncErrorMsg("重新同步失败:" + response);
                sysTaskEmergencyService.updateSysTaskEmergency(emergency);
                log.error("调度单重新同步失败,任务ID: {}, 响应: {}", taskId, response);
                return false;
            return taskDispatchSyncService.resyncDispatchOrderToLegacy(taskId);
        }
            }
            
        } 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;
        }
    }
    
    /**
     * 批量重新同步需要更新的调度单
@@ -1537,6 +333,19 @@
                
                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());
                    
@@ -1566,7 +375,7 @@
                
                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;
            }
            // 只有已经同步过调度单的任务才需要标记重新同步
            if (emergency.getDispatchSyncStatus() != null && emergency.getDispatchSyncStatus() == 2
                    && emergency.getLegacyDispatchOrdId() != null && emergency.getLegacyDispatchOrdId() > 0) {
                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) {
//
//            }
        } 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());
@@ -594,6 +598,7 @@
            }
        }
        
        // 更新执行人员(检测人员变更)
        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,368 @@
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()));
            }
            // 发送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