wlzboy
2026-04-01 c459808efab29dc1b8439fbb90556bdb16f4c88b
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -1,33 +1,42 @@
package com.ruoyi.system.service.impl;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.net.HttpURLConnection;
import java.net.URL;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.*;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.event.*;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.*;
import com.ruoyi.system.utils.TaskCodeGenerator;
import com.ruoyi.common.config.ImageUrlConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.system.domain.SysTask;
import com.ruoyi.system.domain.SysTaskVehicle;
import com.ruoyi.system.domain.SysTaskAttachment;
import com.ruoyi.system.domain.SysTaskLog;
import com.ruoyi.system.domain.vo.TaskQueryVO;
import com.ruoyi.system.domain.vo.TaskCreateVO;
import com.ruoyi.system.domain.vo.TaskUpdateVO;
import com.ruoyi.system.domain.vo.TaskStatisticsVO;
import com.ruoyi.system.domain.SysTaskStatusHistory;
import com.ruoyi.system.domain.SysTaskEmergency;
import com.ruoyi.system.domain.SysTaskWelfare;
import com.ruoyi.system.domain.SysTaskAssignee;
import com.ruoyi.system.domain.enums.TaskStatus;
import com.ruoyi.system.mapper.SysTaskMapper;
import com.ruoyi.system.mapper.SysTaskVehicleMapper;
import com.ruoyi.system.mapper.SysTaskAttachmentMapper;
import com.ruoyi.system.mapper.SysTaskLogMapper;
import com.ruoyi.system.service.ISysTaskService;
import com.ruoyi.system.domain.VehicleInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
/**
 * 任务管理Service业务层处理
@@ -38,11 +47,10 @@
@Service
public class SysTaskServiceImpl implements ISysTaskService {
    
    @Autowired
    private SysTaskMapper sysTaskMapper;
    private static final Logger log = LoggerFactory.getLogger(SysTaskServiceImpl.class);
    
    @Autowired
    private SysTaskVehicleMapper sysTaskVehicleMapper;
    private SysTaskMapper sysTaskMapper;
    
    @Autowired
    private SysTaskAttachmentMapper sysTaskAttachmentMapper;
@@ -50,6 +58,70 @@
    @Autowired
    private SysTaskLogMapper sysTaskLogMapper;
    @Autowired
    private SysTaskStatusHistoryMapper sysTaskStatusHistoryMapper;
    @Autowired
    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
    @Autowired
    private SysTaskAssigneeMapper sysTaskAssigneeMapper;
    @Autowired(required = false)
    private ILegacySystemSyncService legacySystemSyncService;
    @Autowired
    private ISysEmergencyTaskService sysEmergencyTaskService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private ImageUrlConfig imageUrlConfig;
    @Autowired
    private ISysTaskAttachmentService sysTaskAttachmentService;
    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private ISysUserService userService;
    @Autowired(required = false)
    private IMapService mapService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private ISysTaskAssigneeService sysTaskAssigneeService;
    @Autowired
    private ISysWelfareTaskService sysWelfareTaskService;
    @Autowired
    private ISysTaskVehicleService sysTaskVehicleService;
    @Autowired
    private ISysTaskAssigneeService assigneeService;
    @Override
    public Boolean dispatchSyncEvent(Long taskId) {
        SysTask task= sysTaskMapper.selectSysTaskByTaskId(taskId);
        SysUser user= userService.selectUserById(task.getCreatorId());
        Integer oaUser=user.getOaUserId();
        SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
        eventPublisher.publishEvent(new TaskDispatchSyncEvent(this, taskId, task.getTaskCode(),emergency.getLegacyServiceOrdId(), emergency.getLegacyDispatchOrdId(),oaUser));
        return true;
    }
    private Long getBranchCompanyId(Long userId) {
       return userService.getBranchCompanyIdByUserId(userId);
    }
    /**
     * 查询任务管理
     * 
@@ -58,9 +130,30 @@
     */
    @Override
    public SysTask selectSysTaskByTaskId(Long taskId) {
        return sysTaskMapper.selectSysTaskByTaskId(taskId);
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null) {
            bindTaskAssign(task);
            // 加载急救转运扩展信息
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                task.setEmergencyInfo(emergencyInfo);
            }
            // 加载福祉车扩展信息
            else if ("WELFARE".equals(task.getTaskType())) {
                SysTaskWelfare welfareInfo = sysWelfareTaskService.getWelfareInfoByTaskId(taskId);
                task.setWelfareInfo(welfareInfo);
            }
        }
        return task;
    }
    private void bindTaskAssign(SysTask task){
       List<SysTaskAssignee> assignees= assigneeService.getAssigneesByTaskId(task.getTaskId());
       if(assignees!=null && !assignees.isEmpty()) {
           task.setAssignees(assignees);
       }
    }
    /**
     * 查询任务管理列表
     * 
@@ -69,7 +162,73 @@
     */
    @Override
    public List<SysTask> selectSysTaskList(TaskQueryVO queryVO) {
        return sysTaskMapper.selectSysTaskList(queryVO);
        List<SysTask> tasks= sysTaskMapper.selectSysTaskList(queryVO);
        tasks.forEach(task -> {
            bindTaskAssign( task);
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId());
                task.setEmergencyInfo(emergencyInfo);
            }
        });
        return tasks;
    }
    /**
     * 设置任务是总部推送的标记
     * @param taskCreatorId 任务创建人的用户ID
     * @param taskDeptId 任务中的归属机构ID
     */
    @Override
    public Boolean isTaskHeaderPush(Long taskCreatorId,Long taskDeptId){
        if(LongUtil.isEmpty(taskCreatorId))return false;
        if(LongUtil.isEmpty(taskDeptId))return false ;
        Long createrDeptId = getBranchCompanyId(taskCreatorId);
        if(createrDeptId !=null && !taskDeptId.equals(createrDeptId) && createrDeptId.equals(DeptUtil.GUANGZHOU_DEPT_ID)){
            //广州总部推送的任务
           return true;
        }else{
            return false;
        }
    }
    /**
     *根据任务编号、调度单编号或服务单编号查询任务列表(SQL算法下推优化版本)
     *
     * @param queryVO 任务查询对象
     * @param taskCode 任务编号
     * @return 任务管理集合
     */
    @Override
    public List<SysTask> selectSysTaskListByMultiCode(TaskQueryVO queryVO, String taskCode) {
        // 设置任务码用于SQL查询
        queryVO.setTaskCode(taskCode);
        // 使用优化的查询方法,直接在SQL中关联sys_task_emergency表并计算匹配的dispatchCode和serviceCode
        List<SysTask> tasks = sysTaskMapper.selectSysTaskListByMultiCodeOptimized(queryVO);
        // 处理任务分配信息和急救转运扩展信息
        tasks.forEach(task -> {
            bindTaskAssign(task);
            // 对于急救转运任务,使用SQL查询中已计算并匹配好的dispatchCode和serviceCode
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                // 创建一个临时的emergencyInfo对象,包含从SQL查询结果中获取的计算后的代码
//                SysTaskEmergency emergencyInfo = new SysTaskEmergency();
//                emergencyInfo.setDispatchCode(task.getDispatchCode());
//                emergencyInfo.setServiceCode(task.getServiceCode());
                // 加载完整的扩展信息
                SysTaskEmergency fullEmergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId());
                if (fullEmergencyInfo != null) {
                    // 保留完整信息,但确保dispatchCode和serviceCode是计算后的值
                    task.setEmergencyInfo(fullEmergencyInfo);
                }
            }
        });
        return tasks;
    }
    /**
@@ -79,26 +238,67 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int insertSysTask(TaskCreateVO createVO) {
    public Long insertSysTask(TaskCreateVO createVO) {
    // 获取当前用户名和用户ID
        String username = SecurityUtils.getUsername();
        Long userId = SecurityUtils.getUserId();
    // 校验用户ID是否为空或为0
        if(userId==null || userId==0){
            log.error("insertSysTask 用户ID为空 userName:{}",username);
            return 0L;
        }
        SysTask task = new SysTask();
    // 创建新的任务对象
        task.setTaskCode(generateTaskCode());
        task.setTaskType(createVO.getTaskType());
        task.setTaskStatus(TaskStatus.PENDING.getCode());
        task.setTaskDescription(createVO.getTaskDescription());
        task.setDepartureAddress(createVO.getDepartureAddress());
        task.setDestinationAddress(createVO.getDestinationAddress());
        task.setPlannedStartTime(createVO.getPlannedStartTime());
        task.setPlannedEndTime(createVO.getPlannedEndTime());
        task.setAssigneeId(createVO.getAssigneeId());
        task.setCreatorId(SecurityUtils.getUserId());
        task.setDeptId(SecurityUtils.getDeptId());
        task.setCreateBy(SecurityUtils.getUsername());
    // 设置任务基本信息
        task.setTaskType(createVO.getTaskType()); // 生成任务编码
        task.setTaskStatus(TaskStatus.PENDING.getCode()); // 设置任务类型
        task.setTaskDescription(createVO.getTaskDescription()); // 设置任务状态为待处理
        task.setPlannedStartTime(createVO.getPlannedStartTime()); // 设置任务描述
        task.setPlannedEndTime(createVO.getPlannedEndTime()); // 设置计划开始时间
        task.setAssigneeId(createVO.getAssigneeId()); // 设置计划结束时间
 // 设置指派人ID
        task.setCreatorId(userId);
    // 设置创建人信息
        // 优先使用前端传入的部门ID,如果没有则使用当前用户的部门ID
        task.setDeptId(createVO.getDeptId() != null ? createVO.getDeptId() : SecurityUtils.getDeptId());
        task.setCreateBy(username);
        task.setCreateTime(DateUtils.getNowDate());
        task.setUpdateBy(username);
        task.setUpdateTime(DateUtils.getNowDate());
        task.setRemark(createVO.getRemark());
        task.setDelFlag("0");
        // 设置地址和坐标信息
        setAddressAndCoordinatesFromVO(task, createVO);
        // 设置任务类型特定信息
        setTaskTypeSpecificInfo(task, createVO);
        // 自动填充缺失的GPS坐标
        autoFillMissingGpsCoordinates(task);
        
        int result = sysTaskMapper.insertSysTask(task);
        // 保存车辆关联信息
        if (result > 0 && createVO.getVehicleIds() != null && !createVO.getVehicleIds().isEmpty()) {
            sysTaskVehicleService.saveTaskVehicles(task.getTaskId(), createVO.getVehicleIds(), username);
        }
        // 保存执行人员信息(包含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            sysTaskAssigneeService.saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),username);
        }
        // 保存急救转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            sysEmergencyTaskService.saveEmergencyInfo(task.getTaskId(), username, createVO, null, null, null);
        }
        // 保存福祉车扩展信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            sysWelfareTaskService.saveWelfareInfo(task.getTaskId(), SecurityUtils.getUsername(), createVO);
        }
        
        // 记录操作日志
        if (result > 0) {
@@ -106,7 +306,162 @@
                         "任务类型:" + createVO.getTaskType(), SecurityUtils.getUserId(), SecurityUtils.getUsername());
        }
        
        return result;
        // 发布任务创建事件
        if (result > 0) {
            eventPublisher.publishEvent(new TaskCreatedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                task.getTaskType(),
                task.getCreatorId(),
                SecurityUtils.getUsername()
            ));
        }
        // 异步同步急救转运任务到旧系统
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType()) && legacySystemSyncService != null) {
            final Long finalTaskId = task.getTaskId();
            new Thread(() -> {
                try {
                    Thread.sleep(200); // 等待2秒,确保事务已提交
                    legacySystemSyncService.syncEmergencyTaskToLegacy(finalTaskId);
                } catch (Exception e) {
                    // 同步失败不影响主流程,仅记录日志
                    log.error("同步急救转运任务到旧系统失败", e);
                }
            }).start();
        }
        return result > 0 ? task.getTaskId() : 0L;
    }
    /**
     * 新增任务管理(允许从外部传入用户信息、部门信息和时间信息)
     *
     * @param createVO 任务创建对象
     * @param userId 用户ID
     * @param deptId 部门ID
     * @param createTime 创建时间
     * @param updateTime 更新时间
     * @return 结果
     */
    @Override
    public Long insertTask(TaskCreateVO createVO,Long serviceOrderId,Long dispatchOrderId, String serviceOrdNo, Long userId,String userName, Long deptId, Date createTime, Date updateTime) {
        SysTask task = new SysTask();
        if(createVO.getTaskCode()!=null){
            task.setTaskCode(createVO.getTaskCode());
        }else{
            task.setTaskCode(generateTaskCode());
        }
        task.setTaskType(createVO.getTaskType());
        task.setTaskStatus(TaskStatus.PENDING.getCode());
        task.setTaskDescription(createVO.getTaskDescription());
        task.setPlannedStartTime(createVO.getPlannedStartTime());
        task.setPlannedEndTime(createVO.getPlannedEndTime());
        task.setActualStartTime(createVO.getActualStartTime());
        task.setActualEndTime(createVO.getActualEndTime());
        task.setAssigneeId(createVO.getAssigneeId());
        // 使用外部传入的用户ID和部门ID
        task.setCreatorId(userId);
        task.setDeptId(deptId);
        task.setCreateBy(userName);
        // 使用外部传入的创建时间和更新时间
        task.setCreateTime(createTime);
        task.setUpdateTime(updateTime);
        task.setUpdateBy(userName);
        task.setRemark(createVO.getRemark());
        task.setDelFlag("0");
        // 设置地址和坐标信息
        setAddressAndCoordinatesFromVO(task, createVO);
        // 设置任务类型特定信息(注:insertTask使用plannedStartTime而非serviceTime)
        if (createVO.getTransferTime() != null) {
            task.setPlannedStartTime(createVO.getTransferTime());
        }
        if (createVO.getTransferDistance() != null) {
            task.setEstimatedDistance(createVO.getTransferDistance());
        }
        if (createVO.getPlannedStartTime() != null) {
            task.setPlannedStartTime(createVO.getPlannedStartTime());
        }
        if (createVO.getStartAddress() != null) {
            task.setDepartureAddress(createVO.getStartAddress());
        }
        if (createVO.getEndAddress() != null) {
            task.setDestinationAddress(createVO.getEndAddress());
        }
        // 自动填充缺失的GPS坐标
        autoFillMissingGpsCoordinates(task);
        int result = sysTaskMapper.insertSysTask(task);
        // 保存车辆关联信息
        if (result > 0 && createVO.getVehicleIds() != null && !createVO.getVehicleIds().isEmpty()) {
            sysTaskVehicleService.saveTaskVehicles(task.getTaskId(), createVO.getVehicleIds(), userName,
                updateTime, createTime, updateTime);
        }
        // 保存执行人员信息(包含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            sysTaskAssigneeService.saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),userName);
        }
        // 保存急救转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            sysEmergencyTaskService.saveEmergencyInfo(task.getTaskId(), userName, createVO, serviceOrderId, dispatchOrderId, serviceOrdNo);
        }
        // 保存福祉车扩展信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            sysWelfareTaskService.saveWelfareInfo(task.getTaskId(), userName, createVO);
        }
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(task.getTaskId(), "CREATE", "创建任务", null,
                         "任务类型:" + createVO.getTaskType(), userId, userName);
        }
        // 发布任务创建事件
        if (result > 0) {
            eventPublisher.publishEvent(new TaskCreatedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                task.getTaskType(),
                userId,
                userName
            ));
        }
        if(result>0) {
            this.sendEmeryTaskProcess(task, dispatchOrderId);
        }
        return result > 0 ? task.getTaskId() : 0L;
    }
    private void sendTaskAssigneeEvent(TaskCreateVO createVO,SysTask task,Long userId,String userName){
        List<Long> assigneeIds = createVO.getAssignees().stream()
                .map(TaskCreateVO.AssigneeInfo::getUserId)
                .collect(Collectors.toList());
        List<String> assigneeNames = createVO.getAssignees().stream()
                .map(TaskCreateVO.AssigneeInfo::getUserName)
                .collect(Collectors.toList());
        eventPublisher.publishEvent(new TaskAssignedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                assigneeIds,
                assigneeNames,
                userId,
                userName
        ));
    }
    /**
@@ -116,37 +471,371 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int updateSysTask(TaskUpdateVO updateVO) {
        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(updateVO.getTaskId());
        if (oldTask == null) {
    public int updateSysTask(TaskUpdateVO updateVO, Boolean updateFromLegacy) {
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(updateVO.getTaskId());
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        SysTask task = new SysTask();
        Long userId = SecurityUtils.getUserId();
        String userName = SecurityUtils.getUsername();
        task.setTaskId(updateVO.getTaskId());
        task.setTaskDescription(updateVO.getTaskDescription());
        task.setDepartureAddress(updateVO.getDepartureAddress());
        task.setDestinationAddress(updateVO.getDestinationAddress());
        task.setPlannedStartTime(updateVO.getPlannedStartTime());
        task.setPlannedEndTime(updateVO.getPlannedEndTime());
        task.setAssigneeId(updateVO.getAssigneeId());
        task.setUpdateBy(SecurityUtils.getUsername());
        task.setUpdateTime(DateUtils.getNowDate());
        task.setUpdateBy(userName);
        task.setUpdateTime(updateVO.getUpdateTime() != null ? updateVO.getUpdateTime() : DateUtils.getNowDate());
        task.setRemark(updateVO.getRemark());
        
        // 设置预计距离
        if (updateVO.getTransferDistance() != null) {
            task.setEstimatedDistance(updateVO.getTransferDistance());
        }
        // 如果更新了部门ID
        if (updateVO.getDeptId() != null) {
            task.setDeptId(updateVO.getDeptId());
        }
        // 如果更新了任务编号
        if (updateVO.getTaskCode() != null) {
            task.setTaskCode(updateVO.getTaskCode());
        }
        Boolean hasSetDepartureFlag=false;
        //设置总部推送
        // 自动获取出发地GPS坐标(如果更新了地址但缺失坐标)
        if (updateVO.getDepartureAddress() != null &&
            (updateVO.getDepartureLongitude() == null || updateVO.getDepartureLatitude() == null) &&
            mapService != null) {
            if (!updateVO.getDepartureAddress().equals(task.getDepartureAddress())) {
                try {
                    Map<String, Double> coords = mapService.geocoding(
                        updateVO.getDepartureAddress(),
                        extractCityFromAddress(updateVO.getDepartureAddress())
                    );
                    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) {
                    log.error("自动获取出发地GPS坐标失败", e);
                }
            }
        }
        // 设置通用地址和坐标信息
        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(task.getDestinationAddress())) {
                try {
                    Map<String, Double> coords = mapService.geocoding(
                        updateVO.getDestinationAddress(),
                        extractCityFromAddress(updateVO.getDestinationAddress())
                    );
                    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) {
                    log.error("自动获取目的地GPS坐标失败", e);
                }
            }
        }
        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());
            task.setAssigneeName(assigneeInfo.getUserName());
        }
        // 用于跟踪是否需要重新同步(车辆、人员、地址、成交价变更)
        boolean needResync = true;
        int result = sysTaskMapper.updateSysTask(task);
        // 更新车辆关联
        if (result > 0 && updateVO.getVehicleIds() != null && !updateVO.getVehicleIds().isEmpty()) {
            boolean vehiclesChanged = sysTaskVehicleService.updateTaskVehicles(
                updateVO.getTaskId(), updateVO.getVehicleIds(), userName);
            if (vehiclesChanged) {
                // 标记需要重新同步(车辆变更)
                needResync = true;
            }
        }
        // 更新执行人员(检测人员变更)
        if (result > 0 && updateVO.getAssignees() != null) {
            boolean assigneesChanged = sysTaskAssigneeService.updateTaskAssignees(
                updateVO.getTaskId(), updateVO.getAssignees(), userName);
            if (assigneesChanged) {
                // 标记需要重新同步(人员变更)
                needResync = true;
            }
        }
        Long dispatchOrderId=0L;
        // 更新急救转运扩展信息(检测地址和成交价变更)
        if (result > 0 && "EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            SysTaskEmergency oldEmergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(updateVO.getTaskId());
            sysEmergencyTaskService.updateEmergencyInfoFromUpdateVO(oldEmergency, updateVO, userName);
          dispatchOrderId=  oldEmergency.getLegacyDispatchOrdId();
            markNeedSync(task,updateVO);
        }
        // 更新福祉车扩展信息
        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) {
            recordTaskLog(updateVO.getTaskId(), "UPDATE", "更新任务",
                         buildTaskDescription(oldTask), buildTaskDescription(task),
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
            recordTaskLog(updateVO.getTaskId(), "UPDATE", "更新任务",
                buildTaskDescription(task), buildTaskDescription(task),
                userId, userName);
        }
        if(result > 0 && task.getTaskStatus().equals(TaskStatus.PENDING.getCode())
                && updateVO.getAssignees() != null
                && !updateVO.getAssignees().isEmpty()
                && LongUtil.isNotEmpty(dispatchOrderId)){
            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()));
        }
    }
    /**
     * 更新任务(用于旧系统同步)
     *
     * @param updateVO 任务更新对象
     * @param serviceOrderId 旧系统服务单ID
     * @param dispatchOrderId 旧系统调度单ID
     * @param serviceOrdNo 旧系统服务单编号
     * @param userId 用户ID
     * @param userName 用户名
     * @param deptId 部门ID
     * @param createTime 创建时间
     * @param updateTime 更新时间
     * @return 结果
     */
    @Override
    public int updateTask(TaskUpdateVO updateVO, Long serviceOrderId, Long dispatchOrderId, String serviceOrdNo,
                         Long userId, String userName, Long deptId, Date createTime, Date updateTime) {
//        log.info("开始更新任务 ServiceOrdID: {} , dispatchOrdId:{}", serviceOrderId,dispatchOrderId);
        // 通过旧系统服务单ID查找任务
        // 获取旧任务信息,用于判断地址是否变更
        SysTaskEmergency taskEmergency = sysTaskEmergencyMapper.selectByLegacyServiceOrdId(serviceOrderId);
        Long taskId = taskEmergency.getTaskId();
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        updateVO.setTaskId(taskId);
        if(updateVO.getTaskStatus()!=null){
            task.setTaskStatus(updateVO.getTaskStatus());
        }
        task.setTaskDescription(updateVO.getTaskDescription());
        task.setPlannedStartTime(updateVO.getPlannedStartTime());
        task.setPlannedEndTime(updateVO.getPlannedEndTime());
        if(updateVO.getActualStartTime() != null) {
            task.setActualStartTime(updateVO.getActualStartTime());
        }
        if(updateVO.getActualEndTime() != null) {
            task.setActualEndTime(updateVO.getActualEndTime());
        }
        if(deptId!=null){
            task.setDeptId(deptId);
        }
//        task.setAssigneeId(updateVO.getAssigneeId());
        task.setUpdateBy(userName);
        task.setUpdateTime(DateUtils.getNowDate());
        task.setRemark(updateVO.getRemark());
        // 设置地址和坐标信息
        if(updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()){
            TaskCreateVO.AssigneeInfo assigneeInfo= updateVO.getAssignees().get(0);
            task.setAssigneeId(assigneeInfo.getUserId());
            task.setAssigneeName(assigneeInfo.getUserName());
        }
        // 如果更新了部门ID
        if (updateVO.getDeptId() != null) {
            task.setDeptId(updateVO.getDeptId());
        }
        // 如果更新了任务编号
        if (updateVO.getTaskCode() != null) {
            task.setTaskCode(updateVO.getTaskCode());
        }
        Boolean modifyOutLongLat = false;
        // 自动获取出发地GPS坐标(如果地址变更且缺失坐标)
        if (task != null && updateVO.getDepartureAddress() != null
            && !updateVO.getDepartureAddress().equals(task.getDepartureAddress())
            && (updateVO.getDepartureLongitude() == null || updateVO.getDepartureLatitude() == null)
            && mapService != null) {
            try {
                Map<String, Double> coords = mapService.geocoding(
                    updateVO.getDepartureAddress(),
                    extractCityFromAddress(updateVO.getDepartureAddress())
                );
                if (coords != null) {
                    task.setDepartureLongitude(BigDecimal.valueOf(coords.get("lng")));
                    task.setDepartureLatitude(BigDecimal.valueOf(coords.get("lat")));
                    modifyOutLongLat = true;
//                    log.info("出发地GPS坐标自动获取成功: {}, {}", coords.get("lng"), coords.get("lat"));
                }
            } catch (Exception e) {
                log.error("自动获取出发地GPS坐标失败", e);
            }
        }
        task.setDepartureAddress(updateVO.getDepartureAddress());
        if(!modifyOutLongLat){
            task.setDepartureLongitude(updateVO.getDepartureLongitude());
            task.setDepartureLatitude(updateVO.getDepartureLatitude());
        }
        Boolean modifyInLongLat = false;
        // 自动获取目的地GPS坐标(如果地址变更且缺失坐标)
        if (task != null && updateVO.getDestinationAddress() != null
            && !updateVO.getDestinationAddress().equals(task.getDestinationAddress())
            && (updateVO.getDestinationLongitude() == null || updateVO.getDestinationLatitude() == null)
            && mapService != null) {
            try {
                Map<String, Double> coords = mapService.geocoding(
                    updateVO.getDestinationAddress(),
                    extractCityFromAddress(updateVO.getDestinationAddress())
                );
                if (coords != null) {
                    task.setDestinationLongitude(BigDecimal.valueOf(coords.get("lng")));
                    task.setDestinationLatitude(BigDecimal.valueOf(coords.get("lat")));
                    modifyInLongLat = true;
//                    log.info("目的地GPS坐标自动获取成功: {}, {}", coords.get("lng"), coords.get("lat"));
                }
            } catch (Exception e) {
                log.error("自动获取目的地GPS坐标失败", e);
            }
        }
        task.setDestinationAddress(updateVO.getDestinationAddress());
        if(!modifyInLongLat){
            task.setDestinationLongitude(updateVO.getDestinationLongitude());
            task.setDestinationLatitude(updateVO.getDestinationLatitude());
        }
        int result = sysTaskMapper.updateSysTask(task);
//        log.info("更新转运任务,ServiceOrdID:{},dispatchOrderId:{},result:{}",serviceOrderId,dispatchOrderId,result);
//        log.info("更新任务车辆 ServiceOrdID: {} , dispatchOrdId:{},VehicleIds:{}", serviceOrderId,dispatchOrderId,updateVO.getVehicleIds());
        // 更新车辆关联
        if (result > 0 && updateVO.getVehicleIds() != null && !updateVO.getVehicleIds().isEmpty()) {
//            log.info("更新车辆关联 ServiceOrdID:{},dispatchOrderId:{}",serviceOrderId,dispatchOrderId);
            sysTaskVehicleService.updateTaskVehicles(taskId, updateVO.getVehicleIds(), userName);
        }
        Boolean hasAssignee = updateVO.getAssigneeId() != null && !updateVO.getAssignees().isEmpty() ;
//        log.info("更新转运任务,ServiceOrdID:{},dispatchOrderId:{},result:{}, hasAssignee:{}",serviceOrderId,dispatchOrderId,result,hasAssignee);
        // 更新执行人员(检测人员变更)
        if (result > 0 && hasAssignee) {
//            log.info("更新执行人员 ServiceOrdID:{},dispatchOrderId:{}",serviceOrderId,dispatchOrderId);
            sysTaskAssigneeService.updateTaskAssignees(taskId, updateVO.getAssignees(), userName);
        }
        // 更新急救转运扩展信息
        if (result > 0) {
            // 更新旧系统ID
            taskEmergency.setLegacyServiceOrdId(serviceOrderId);
            if (LongUtil.isNotEmpty(dispatchOrderId)) {
                taskEmergency.setLegacyDispatchOrdId(dispatchOrderId);
                taskEmergency.setDispatchSyncStatus(2);
                taskEmergency.setDispatchSyncTime(new Date());
                taskEmergency.setDispatchSyncErrorMsg("旧系统同步过来");
            }
            if (serviceOrdNo != null) {
                taskEmergency.setLegacyServiceOrdNo(serviceOrdNo);
            }
            taskEmergency.setUpdateTime(DateUtils.getNowDate());
            Boolean hasEmergencyInfo = updateVO.getHospitalOut() != null || updateVO.getHospitalIn() != null || updateVO.getPatient() != null
                    || updateVO.getPrice() != null || updateVO.getTransferDistance() != null;
//            Boolean isHeadPush=isTaskHeaderPush(task.getCreatorId(),task.getDeptId());
//            updateVO.setFromHQ2_is(isHeadPush?"1":"0");
            // 使用TaskCreateVO的字段来更新急救转运信息
            if (hasEmergencyInfo) {
                sysEmergencyTaskService.updateEmergencyInfoFromCreateVO(taskEmergency, updateVO, userName);
            }
           SysTaskEmergency emergency= sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
            dispatchOrderId = emergency.getLegacyDispatchOrdId();
        }
        if(updateVO.getTaskStatus()!=null
                && updateVO.getTaskStatus().equals(TaskStatus.PENDING.getCode())
                && updateVO.getAssignees()!=null && !updateVO.getAssignees().isEmpty()
                && LongUtil.isNotEmpty(dispatchOrderId)){
            this.sendTaskAssigneeEvent(updateVO,task,userId,userName);
        }
        return result;
    }
    private void sendEmeryTaskProcess(SysTask task,Long dispatchOrderId){
        Long taskId = task.getTaskId();
        String taskCode = task.getShowTaskCode();
        if(task.getTaskStatus()!=null && task.getTaskStatus().equals(TaskStatus.PENDING.getCode())){
            //如果没有分配人员,且没有调度单,不是广州总公司的就需要发送通知跟进
            if(LongUtil.isEmpty(dispatchOrderId)){
                if(!task.getDeptId().equals(DeptUtil.GUANGZHOU_DEPT_ID) && (task.getAssignees()==null  || task.getAssignees().isEmpty())){
                    //发送通知
                    eventPublisher.publishEvent(new TaskOnlyServerOrderSyncEvent(this, taskId, taskCode));
                }
            }
        }
    }
    /**
     * 批量删除任务管理
     * 
@@ -154,7 +843,7 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteSysTaskByTaskIds(Long[] taskIds) {
        int result = 0;
        for (Long taskId : taskIds) {
@@ -175,20 +864,42 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int assignTask(Long taskId, Long assigneeId, String remark) {
        SysTask task = new SysTask();
        task.setTaskId(taskId);
        task.setAssigneeId(assigneeId);
        task.setUpdateBy(SecurityUtils.getUsername());
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        
        int result = sysTaskMapper.assignTask(task);
        SysTask updateTask = new SysTask();
        updateTask.setTaskId(taskId);
        updateTask.setAssigneeId(assigneeId);
        updateTask.setUpdateBy(SecurityUtils.getUsername());
        updateTask.setUpdateTime(DateUtils.getNowDate());
        int result = sysTaskMapper.assignTask(updateTask);
        
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(taskId, "ASSIGN", "分配任务", null, 
                         "分配给用户ID:" + assigneeId + ",备注:" + remark, 
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
        }
        // 发布任务分配事件
        if (result > 0) {
            List<Long> assigneeIds = new ArrayList<>();
            assigneeIds.add(assigneeId);
            eventPublisher.publishEvent(new TaskAssignedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                assigneeIds,
                null, // 姓名列表在监听器中查询
                SecurityUtils.getUserId(),
                SecurityUtils.getUsername()
            ));
        }
        
        return result;
@@ -203,8 +914,91 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark) {
        return changeTaskStatusWithLocation(taskId, newStatus, remark, null);
    }
    /**
     * 强制完成任务(指定实际开始时间和结束时间)
     *
     * @param task 任务信息
     * @return 结果
     */
    @Override
    public int forceCompleteTask(SysTask task) {
        if (task == null || task.getTaskId() == null) {
            throw new RuntimeException("任务信息不能为空");
        }
        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(task.getTaskId());
        if (oldTask == null) {
            throw new RuntimeException("任务不存在");
        }
        // 校验开始时间和结束时间
        if (task.getActualStartTime() == null || task.getActualEndTime() == null) {
            throw new RuntimeException("实际开始时间和结束时间不能为空");
        }
        if (task.getActualStartTime().after(task.getActualEndTime())) {
            throw new RuntimeException("结束时间必须大于开始时间");
        }
        // 记录旧状态
        String oldStatus = oldTask.getTaskStatus();
        TaskStatus oldTaskStatus = TaskStatus.getByCode(oldStatus);
        // 更新任务
        int result = sysTaskMapper.updateTaskStatus(task);
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(task.getTaskId(), "FORCE_COMPLETE", "强制完成任务",
                         oldStatus, task.getTaskStatus(),
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
            // 写入状态变更历史记录
            recordStatusHistory(oldTask, oldStatus,
                    oldTaskStatus != null ? oldTaskStatus.getInfo() : oldStatus,
                    task.getTaskStatus(),
                    TaskStatus.getByCode(task.getTaskStatus()) != null ? TaskStatus.getByCode(task.getTaskStatus()).getInfo() : task.getTaskStatus(),
                    task.getRemark(),
                    SysTaskStatusHistory.SOURCE_APP,
                    SecurityUtils.getUserId(), SecurityUtils.getUsername(),
                    null);
            // 发布任务状态变更事件
            TaskStatus newTaskStatus = TaskStatus.getByCode(task.getTaskStatus());
            eventPublisher.publishEvent(new TaskStatusChangedEvent(
                this,
                task.getTaskId(),
                oldTask.getTaskCode(),
                oldStatus,
                task.getTaskStatus(),
                oldTaskStatus != null ? oldTaskStatus.getInfo() : "未知",
                newTaskStatus != null ? newTaskStatus.getInfo() : "未知",
                null, // assigneeIds
                SecurityUtils.getUserId(),
                SecurityUtils.getUserId(),
                null, // longitude
                null, // latitude
                null  // address
            ));
        }
        return result;
    }
    /**
     * 变更任务状态(含GPS位置信息)
     *
     * @param taskId 任务ID
     * @param newStatus 新状态
     * @param remark 备注
     * @param locationLog GPS位置信息日志对象
     * @return 结果
     */
    @Override
    public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog) {
        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (oldTask == null) {
            throw new RuntimeException("任务不存在");
@@ -220,25 +1014,134 @@
        task.setTaskId(taskId);
        task.setTaskStatus(newStatus.getCode());
        task.setUpdateBy(SecurityUtils.getUsername());
        task.setUpdateTime(DateUtils.getNowDate());
        
        // 根据状态设置相应的时间
        if (newStatus == TaskStatus.IN_PROGRESS && oldTask.getActualStartTime() == null) {
        if (newStatus == TaskStatus.DEPARTING && oldTask.getActualStartTime() == null) {
            // 出发中:设置实际开始时间
            task.setActualStartTime(DateUtils.getNowDate());
        } else if (newStatus == TaskStatus.IN_PROGRESS && oldTask.getActualStartTime() == null) {
            // 兼容旧数据:任务中状态也设置实际开始时间
            task.setActualStartTime(DateUtils.getNowDate());
        } else if (newStatus == TaskStatus.COMPLETED) {
            // 已完成:设置实际结束时间
            task.setActualEndTime(DateUtils.getNowDate());
        }
        
        int result = sysTaskMapper.updateTaskStatus(task);
        
        // 记录操作日志
        // 记录操作日志(含GPS位置信息)
        if (result > 0) {
            recordTaskLog(taskId, "STATUS_CHANGE", "状态变更", 
                         "状态:" + oldTaskStatus.getInfo(), 
                         "状态:" + newStatus.getInfo() + ",备注:" + remark, 
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
                         SecurityUtils.getUserId(), SecurityUtils.getUsername(),
                         locationLog);
            // 写入状态变更历史记录
            recordStatusHistory(oldTask, oldTaskStatus.getCode(), oldTaskStatus.getInfo(),
                    newStatus.getCode(), newStatus.getInfo(), remark,
                    SysTaskStatusHistory.SOURCE_APP,
                    SecurityUtils.getUserId(), SecurityUtils.getUsername(),
                    locationLog);
        }
        // 发布任务状态变更事件
        if (result > 0) {
            // 查询任务的所有执行人
            List<SysTaskAssignee> assignees = sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId);
            List<Long> assigneeIds = null;
            if (assignees != null && !assignees.isEmpty()) {
                assigneeIds = assignees.stream()
                    .map(SysTaskAssignee::getUserId)
                    .collect(Collectors.toList());
            }
            Long userId=SecurityUtils.getUserId();
            Double lng=locationLog==null?null: locationLog.getLongitude();
            Double lat=locationLog==null?null: locationLog.getLatitude();
            String address=locationLog==null?null: locationLog.getLocationAddress();
            eventPublisher.publishEvent(new TaskStatusChangedEvent(
                this,
                oldTask.getTaskId(),
                oldTask.getTaskCode(),
                oldTaskStatus.getCode(),
                newStatus.getCode(),
                oldTaskStatus.getInfo(),
                newStatus.getInfo(),
                assigneeIds,
                oldTask.getCreatorId(),
                userId,
                    lng, lat,
                    address
            ));
        }
        
        return result;
    }
    /**
     * 保存任务取消信息(仅限转运任务)
     *
     * @param taskId 任务ID
     * @param cancelReason 取消原因(数据字典task_cancel_reason的value)
     * @return 结果
     */
    @Override
    public int saveCancelInfo(Long taskId, String cancelReason) {
        // 获取任务信息
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        // 只有转运任务才保存取消信息
        if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            return 0;
        }
        // 获取转运任务扩展信息
        SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
        if (emergency == null) {
            return 0;
        }
        // 设置取消信息
        emergency.setCancelReason(cancelReason);
        emergency.setCancelBy(SecurityUtils.getNickName());
        emergency.setCancelTime(DateUtils.getNowDate());
        emergency.setUpdateBy(SecurityUtils.getUsername());
        emergency.setUpdateTime(DateUtils.getNowDate());
        // 更新数据库
        return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
    }
    @Override
    public int saveCancel(Long taskId, String cancelReason, String cancelBy,Date cancelTime) {
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task == null) {
            throw new RuntimeException("任务不存在");
        }
        // 只有转运任务才保存取消信息
        if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            return 0;
        }
        // 获取转运任务扩展信息
        SysTaskEmergency emergency = sysEmergencyTaskService.selectSysTaskEmergencyByTaskId(taskId);
        if (emergency == null) {
            return 0;
        }
        // 设置取消信息
        emergency.setCancelReason(cancelReason);
        emergency.setCancelBy(cancelBy);
        emergency.setCancelTime(cancelTime);
        emergency.setUpdateTime(DateUtils.getNowDate());
        // 更新数据库
        return sysTaskEmergencyMapper.updateSysTaskEmergency(emergency);
    }
    /**
@@ -246,39 +1149,30 @@
     * 
     * @param taskId 任务ID
     * @param file 文件
     * @param category 附件分类
     * @return 结果
     */
    @Override
    @Transactional
    public int uploadAttachment(Long taskId, MultipartFile file) {
        try {
            // 上传文件
            String fileName = FileUploadUtils.upload("/task", file);
            String filePath = FileUploadUtils.getDefaultBaseDir() + fileName;
            SysTaskAttachment attachment = new SysTaskAttachment();
            attachment.setTaskId(taskId);
            attachment.setFileName(file.getOriginalFilename());
            attachment.setFilePath(filePath);
            attachment.setFileSize(file.getSize());
            attachment.setFileType(getFileType(file.getOriginalFilename()));
            attachment.setUploadTime(DateUtils.getNowDate());
            attachment.setUploadBy(SecurityUtils.getUsername());
            int result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
            // 记录操作日志
            if (result > 0) {
                recordTaskLog(taskId, "UPDATE", "上传附件", null,
                             "上传文件:" + file.getOriginalFilename(),
                             SecurityUtils.getUserId(), SecurityUtils.getUsername());
            }
            return result;
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败:" + e.getMessage());
        }
    public Long uploadAttachment(Long taskId, MultipartFile file, String category) {
        return sysTaskAttachmentService.uploadAttachment(taskId, file, category);
    }
    /**
     * 从微信mediaId上传任务附件
     *
     * @param taskId 任务ID
     * @param accessToken 微信AccessToken
     * @param mediaId 微信mediaId
     * @param category 附件分类
     * @return 返回附件ID
     */
    @Override
    public Long uploadAttachmentFromWechat(Long taskId, String accessToken, String mediaId, String category) {
        return sysTaskAttachmentService.uploadAttachmentFromWechat(taskId, accessToken, mediaId, category);
    }
    /**
     * 删除任务附件
@@ -287,30 +1181,25 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteAttachment(Long attachmentId) {
        SysTaskAttachment attachment = sysTaskAttachmentMapper.selectSysTaskAttachmentByAttachmentId(attachmentId);
        if (attachment == null) {
            throw new RuntimeException("附件不存在");
        }
        // 删除物理文件
        try {
            FileUtils.deleteFile(attachment.getFilePath());
        } catch (Exception e) {
            // 忽略文件删除失败
        }
        int result = sysTaskAttachmentMapper.deleteSysTaskAttachmentByAttachmentId(attachmentId);
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(attachment.getTaskId(), "UPDATE", "删除附件",
                         "删除文件:" + attachment.getFileName(), null,
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
        }
        return result;
        return sysTaskAttachmentService.deleteAttachment(attachmentId);
    }
    /**
     * 根据ID获取附件详情
     *
     * @param attachmentId 附件ID
     * @return 附件详情
     */
    @Override
    public SysTaskAttachment getAttachmentById(Long attachmentId) {
        return sysTaskAttachmentService.getAttachmentById(attachmentId);
    }
    @Override
    public List<SysTaskAttachment> getAttachmentsByTaskId(Long taskId) {
        return sysTaskAttachmentService.getAttachmentsByTaskId(taskId);
    }
    /**
@@ -322,29 +1211,15 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int assignVehicleToTask(Long taskId, Long vehicleId, String remark) {
        // 检查是否已经分配
        int exists = sysTaskVehicleMapper.checkTaskVehicleExists(taskId, vehicleId);
        if (exists > 0) {
            throw new RuntimeException("车辆已经分配给该任务");
        }
        SysTaskVehicle taskVehicle = new SysTaskVehicle();
        taskVehicle.setTaskId(taskId);
        taskVehicle.setVehicleId(vehicleId);
        taskVehicle.setAssignTime(DateUtils.getNowDate());
        taskVehicle.setAssignBy(SecurityUtils.getUsername());
        taskVehicle.setStatus("ASSIGNED");
        taskVehicle.setRemark(remark);
        int result = sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
    public int assignVehicleToTask(Long taskId, Long vehicleId, String remark,Long userId,String userName) {
        int result = sysTaskVehicleService.assignVehicleToTask(taskId, vehicleId, remark, userId, userName);
        
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(taskId, "ASSIGN", "分配车辆", null, 
                         "分配车辆ID:" + vehicleId + ",备注:" + remark, 
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
                         userId, userName);
        }
        
        return result;
@@ -358,9 +1233,9 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int unassignVehicleFromTask(Long taskId, Long vehicleId) {
        int result = sysTaskVehicleMapper.deleteSysTaskVehicleByTaskIdAndVehicleId(taskId, vehicleId);
        int result = sysTaskVehicleService.unassignVehicleFromTask(taskId, vehicleId);
        
        // 记录操作日志
        if (result > 0) {
@@ -381,37 +1256,15 @@
     * @return 结果
     */
    @Override
    @Transactional
    public int assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark) {
        List<SysTaskVehicle> taskVehicles = new ArrayList<>();
        Date now = DateUtils.getNowDate();
        String assignBy = SecurityUtils.getUsername();
        for (Long vehicleId : vehicleIds) {
            // 检查是否已经分配
            int exists = sysTaskVehicleMapper.checkTaskVehicleExists(taskId, vehicleId);
            if (exists == 0) {
                SysTaskVehicle taskVehicle = new SysTaskVehicle();
                taskVehicle.setTaskId(taskId);
                taskVehicle.setVehicleId(vehicleId);
                taskVehicle.setAssignTime(now);
                taskVehicle.setAssignBy(assignBy);
                taskVehicle.setStatus("ASSIGNED");
                taskVehicle.setRemark(remark);
                taskVehicles.add(taskVehicle);
            }
        }
        int result = 0;
        if (!taskVehicles.isEmpty()) {
            result = sysTaskVehicleMapper.batchInsertSysTaskVehicle(taskVehicles);
        }
    public int assignMultipleVehiclesToTask(Long taskId, List<Long> vehicleIds, String remark,Long userId,String userName) {
        int result = sysTaskVehicleService.assignMultipleVehiclesToTask(taskId, vehicleIds, remark, userId, userName);
        
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(taskId, "ASSIGN", "批量分配车辆", null, 
                         "分配车辆数量:" + result + ",备注:" + remark, 
                         SecurityUtils.getUserId(), SecurityUtils.getUsername());
                         userId, userName);
        }
        
        return result;
@@ -425,7 +1278,7 @@
     */
    @Override
    public List<SysTaskVehicle> getTaskVehicles(Long taskId) {
        return sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId);
        return sysTaskVehicleService.getTaskVehicles(taskId);
    }
    /**
@@ -437,9 +1290,7 @@
     */
    @Override
    public List<SysTaskVehicle> getAvailableVehicles(Long deptId, String taskType) {
        // 这里需要根据业务逻辑查询可用车辆
        // 暂时返回空列表,实际实现需要查询车辆表
        return new ArrayList<>();
        return sysTaskVehicleService.getAvailableVehicles(deptId, taskType);
    }
    /**
@@ -470,7 +1321,14 @@
     */
    @Override
    public List<SysTask> selectMyTasks(Long userId) {
        return sysTaskMapper.selectMyTasks(userId);
        List<SysTask> list = sysTaskMapper.selectMyTasks(userId);
        list.stream().forEach(task -> {
            bindTaskAssign(task);
            if(task.getTaskType().equals("EMERGENCY_TRANSFER")){
                task.setEmergencyInfo(sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(task.getTaskId()));
            }
        });
        return list;
    }
    /**
@@ -484,23 +1342,117 @@
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null) {
            // 查询关联车辆
            task.setAssignedVehicles(sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId));
            // 查询附件
            task.setAttachments(sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId));
            task.setAssignedVehicles(sysTaskVehicleService.getTaskVehicles(taskId));
            // 查询附件(已自动拼接完整URL)
            task.setAttachments(sysTaskAttachmentService.getAttachmentsByTaskId(taskId));
            // 查询操作日志
            task.setOperationLogs(sysTaskLogMapper.selectSysTaskLogByTaskId(taskId));
            // 查询执行人员列表
            task.setAssignees(sysTaskAssigneeMapper.selectSysTaskAssigneeByTaskId(taskId));
            // 加载急救转运扩展信息
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                task.setEmergencyInfo(emergencyInfo);
            }
            // 加载福祉车扩展信息
            else if ("WELFARE".equals(task.getTaskType())) {
                SysTaskWelfare welfareInfo = sysWelfareTaskService.getWelfareInfoByTaskId(taskId);
                task.setWelfareInfo(welfareInfo);
            }
        }
        return task;
    }
    /**
     * 检查车辆是否有正在进行中的任务
     * 正在进行中的任务是指状态不为:PENDING(待处理)、COMPLETED(已完成)、CANCELLED(已取消)的任务
     *
     * @param vehicleId 车辆ID
     * @return 正在进行中的任务列表
     */
    @Override
    public List<SysTask> checkVehicleActiveTasks(Long vehicleId) {
        return sysTaskMapper.selectActiveTasksByVehicleId(vehicleId);
    }
    /**
     * 检查任务是否已关联旧系统服务单ID
     *
     * @param taskId 任务ID
     * @return true-已关联,false-未关联
     */
    @Override
    public boolean hasLegacyServiceOrdId(Long taskId) {
        return sysEmergencyTaskService.hasLegacyServiceOrdId(taskId);
    }
    /**
     * 检查任务是否已关联旧系统调度单ID
     *
     * @param taskId 任务ID
     * @return true-已关联,false-未关联
     */
    @Override
    public boolean hasLegacyDispatchOrdId(Long taskId) {
        return sysEmergencyTaskService.hasLegacyDispatchOrdId(taskId);
    }
    /**
     * 根据旧系统服务单ID检查是否存在任务
     *
     * @param legacyServiceOrdId 旧系统服务单ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyServiceOrdId(Long legacyServiceOrdId) {
        return sysEmergencyTaskService.existsByLegacyServiceOrdId(legacyServiceOrdId);
    }
    /**
     * 根据旧系统调度单ID检查是否存在任务
     *
     * @param legacyDispatchOrdId 旧系统调度单ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyDispatchOrdId(Long legacyDispatchOrdId) {
        return sysEmergencyTaskService.existsByLegacyDispatchOrdId(legacyDispatchOrdId);
    }
    @Autowired
    private TaskCodeGenerator taskCodeGenerator;
    /**
     * 生成任务编号
     * 
     * @return 任务编号
     */
    private String generateTaskCode() {
        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
        return "TASK" + dateStr + "0001";
        return taskCodeGenerator.generateTaskCode();
    }
    /**
     * 从地址中提取城市名称(用于地图地理编码)
     *
     * @param address 地址
     * @return 城市名称
     */
    private String extractCityFromAddress(String address) {
        if (address == null || address.trim().isEmpty()) {
            return null;
        }
        // 常见城市名列表
        String[] cities = {"广州", "深圳", "东莞", "佛山", "珠海", "惠州", "中山", "江门", "湛江", "肇庆", "清远", "韶关", "梅州", "河源", "潮州", "揭阳", "汕头", "汕尾", "云浮", "阳江","北京","上海","天津"};
        for (String city : cities) {
            if (address.contains(city)) {
                return city;
            }
        }
        return null;
    }
    /**
@@ -516,7 +1468,29 @@
     */
    private void recordTaskLog(Long taskId, String operationType, String operationDesc, 
                              String oldValue, String newValue, Long operatorId, String operatorName) {
        SysTaskLog log = new SysTaskLog();
        recordTaskLog(taskId, operationType, operationDesc, oldValue, newValue,
                     operatorId, operatorName, null);
    }
    /**
     * 记录任务操作日志(含GPS位置信息)
     *
     * @param taskId 任务ID
     * @param operationType 操作类型
     * @param operationDesc 操作描述
     * @param oldValue 操作前值
     * @param newValue 操作后值
     * @param operatorId 操作人ID
     * @param operatorName 操作人姓名
     * @param log GPS位置信息日志对象(可为null)
     */
    private void recordTaskLog(Long taskId, String operationType, String operationDesc,
                              String oldValue, String newValue, Long operatorId, String operatorName,
                              SysTaskLog log) {
        if (log == null) {
            log = new SysTaskLog();
        }
        log.setTaskId(taskId);
        log.setOperationType(operationType);
        log.setOperationDesc(operationDesc);
@@ -529,6 +1503,51 @@
        log.setIpAddress("127.0.0.1");
        
        sysTaskLogMapper.insertSysTaskLog(log);
    }
    /**
     * 记录任务状态变更历史
     *
     * @param task            任务对象(取 task_id / task_code)
     * @param fromStatus      变更前状态码
     * @param fromStatusName  变更前状态名称
     * @param toStatus        变更后状态码
     * @param toStatusName    变更后状态名称
     * @param changeReason    变更原因/备注
     * @param changeSource    触发来源(APP / ADMIN / SYSTEM / LEGACY)
     * @param operatorId      操作人 ID
     * @param operatorName    操作人姓名
     * @param locationLog     GPS 位置信息(可为 null)
     */
    private void recordStatusHistory(SysTask task,
                                     String fromStatus, String fromStatusName,
                                     String toStatus, String toStatusName,
                                     String changeReason, String changeSource,
                                     Long operatorId, String operatorName,
                                     SysTaskLog locationLog) {
        try {
            SysTaskStatusHistory history = new SysTaskStatusHistory();
            history.setTaskId(task.getTaskId());
            history.setTaskCode(task.getTaskCode());
            history.setFromStatus(fromStatus);
            history.setFromStatusName(fromStatusName);
            history.setToStatus(toStatus);
            history.setToStatusName(toStatusName);
            history.setChangeReason(changeReason);
            history.setChangeSource(changeSource != null ? changeSource : SysTaskStatusHistory.SOURCE_APP);
            history.setOperatorId(operatorId);
            history.setOperatorName(operatorName);
            history.setChangeTime(DateUtils.getNowDate());
            history.setIpAddress("127.0.0.1");
            if (locationLog != null) {
                history.setLongitude(locationLog.getLongitude());
                history.setLatitude(locationLog.getLatitude());
                history.setLocationAddress(locationLog.getLocationAddress());
            }
            sysTaskStatusHistoryMapper.insert(history);
        } catch (Exception e) {
            log.error("记录任务状态变更历史失败, taskId={}", task.getTaskId(), e);
        }
    }
    /**
@@ -548,20 +1567,290 @@
        return sb.toString();
    }
    /**
     * 获取文件类型
     * 从TaskCreateVO设置地址和坐标信息到任务对象
     * 
     * @param fileName 文件名
     * @return 文件类型
     * @param task 任务对象
     * @param createVO 创建VO
     */
    private String getFileType(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return "";
    private void setAddressAndCoordinatesFromVO(SysTask task, TaskCreateVO createVO) {
        // 设置通用地址和坐标信息
        if (createVO.getDepartureAddress() != null) {
            task.setDepartureAddress(createVO.getDepartureAddress());
        }
        int lastDotIndex = fileName.lastIndexOf(".");
        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
            return fileName.substring(lastDotIndex + 1).toLowerCase();
        if (createVO.getDestinationAddress() != null) {
            task.setDestinationAddress(createVO.getDestinationAddress());
        }
        return "";
        if (createVO.getDepartureLongitude() != null) {
            task.setDepartureLongitude(createVO.getDepartureLongitude());
        }
        if (createVO.getDepartureLatitude() != null) {
            task.setDepartureLatitude(createVO.getDepartureLatitude());
        }
        if (createVO.getDestinationLongitude() != null) {
            task.setDestinationLongitude(createVO.getDestinationLongitude());
        }
        if (createVO.getDestinationLatitude() != null) {
            task.setDestinationLatitude(createVO.getDestinationLatitude());
        }
        if (createVO.getTransferDistance() != null) {
            task.setEstimatedDistance(createVO.getTransferDistance());
        }
    }
    /**
     * 设置任务类型特定信息(急救转运/福祉车)
     *
     * @param task 任务对象
     * @param createVO 创建VO
     */
    private void setTaskTypeSpecificInfo(SysTask task, TaskCreateVO createVO) {
        // 设置急救转运特定信息
        if (createVO.getTransferTime() != null) {
            task.setPlannedStartTime(createVO.getTransferTime());
        }
        if (createVO.getTransferDistance() != null) {
            task.setEstimatedDistance(createVO.getTransferDistance());
        }
        // 设置福祉车特定信息
        if (createVO.getServiceTime() != null) {
            task.setPlannedStartTime(createVO.getServiceTime());
        }
        if (createVO.getStartAddress() != null) {
            task.setDepartureAddress(createVO.getStartAddress());
        }
        if (createVO.getEndAddress() != null) {
            task.setDestinationAddress(createVO.getEndAddress());
        }
    }
    /**
     * 自动填充缺失的GPS坐标
     *
     * @param task 任务对象
     */
    private void autoFillMissingGpsCoordinates(SysTask task) {
        // 自动获取出发地GPS坐标(如果缺失)
        if (task.getDepartureAddress() != null &&
            (task.getDepartureLongitude() == null || task.getDepartureLatitude() == null) &&
            mapService != null) {
            try {
                Map<String, Double> coords = mapService.geocoding(
                    task.getDepartureAddress(),
                    extractCityFromAddress(task.getDepartureAddress())
                );
                if (coords != null) {
                    task.setDepartureLongitude(BigDecimal.valueOf(coords.get("lng")));
                    task.setDepartureLatitude(BigDecimal.valueOf(coords.get("lat")));
                }
            } catch (Exception e) {
                log.error("自动获取出发地GPS坐标失败", e);
            }
        }
        // 自动获取目的地GPS坐标(如果缺失)
        if (task.getDestinationAddress() != null &&
            (task.getDestinationLongitude() == null || task.getDestinationLatitude() == null) &&
            mapService != null) {
            try {
                Map<String, Double> coords = mapService.geocoding(
                    task.getDestinationAddress(),
                    extractCityFromAddress(task.getDestinationAddress())
                );
                if (coords != null) {
                    task.setDestinationLongitude(BigDecimal.valueOf(coords.get("lng")));
                    task.setDestinationLatitude(BigDecimal.valueOf(coords.get("lat")));
                }
            } catch (Exception e) {
                log.error("自动获取目的地GPS坐标失败", e);
            }
        }
    }
    /**
     * 计算预计公里数
     *
     * @param task 任务对象
     */
    private void calculateEstimatedDistance(SysTask task) {
        if (task.getDepartureLongitude() != null && task.getDepartureLatitude() != null &&
            task.getDestinationLongitude() != null && task.getDestinationLatitude() != null) {
            // 验证GPS坐标是否有效
            if (GpsDistanceUtils.isValidCoordinate(task.getDepartureLatitude(), task.getDepartureLongitude()) &&
                GpsDistanceUtils.isValidCoordinate(task.getDestinationLatitude(), task.getDestinationLongitude())) {
                // 计算距离
                java.math.BigDecimal distance = GpsDistanceUtils.calculateDistance(
                    task.getDepartureLatitude(), task.getDepartureLongitude(),
                    task.getDestinationLatitude(), task.getDestinationLongitude()
                );
                task.setEstimatedDistance(distance);
            } else {
                // 坐标无效,设置为0
                task.setEstimatedDistance(java.math.BigDecimal.ZERO);
            }
        } else {
            // 坐标不完整,设置为0
            task.setEstimatedDistance(java.math.BigDecimal.ZERO);
        }
    }
    private AjaxResult getCheckCanSuccess(){
        List<Map<String, Object>> conflicts = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        result.put("valid", conflicts.isEmpty());
        result.put("conflicts", conflicts);
        return AjaxResult.success(result);
    }
    /**
     * 检查任务是否可以出发
     * 检查:
     * 1. 车辆是否有未完成的任务
     * 2. 执行人员是否有未完成的任务
     *
     * @param taskId 任务ID
     * @return AjaxResult 校验结果
     */
    @Override
    public AjaxResult checkTaskCanDepart(Long taskId) {
        return getCheckCanSuccess();
    }
    public AjaxResult checkTaskCanDepartOld(Long taskId) {
        List<Map<String, Object>> conflicts = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        // 获取任务详情
        SysTask task = this.getTaskDetail(taskId);
        if (task == null) {
            return AjaxResult.error("任务不存在");
        }
        // 1. 检查车辆是否有未完成的任务
        List<SysTaskVehicle> taskVehicles = task.getAssignedVehicles();
        if (taskVehicles != null && !taskVehicles.isEmpty()) {
            for (SysTaskVehicle taskVehicle : taskVehicles) {
                Long vehicleId = taskVehicle.getVehicleId();
                List<SysTask> vehicleActiveTasks = this.checkVehicleActiveTasks(vehicleId);
                // 过滤掉当前任务本身
                vehicleActiveTasks = vehicleActiveTasks.stream()
                    .filter(t -> !t.getTaskId().equals(taskId))
                    .collect(Collectors.toList());
                if (!vehicleActiveTasks.isEmpty()) {
                    for (SysTask activeTask : vehicleActiveTasks) {
                        Map<String, Object> conflict = new HashMap<>();
                        conflict.put("type", "vehicle");
                        conflict.put("vehicleNo", taskVehicle.getVehicleNo());
                        conflict.put("taskId", activeTask.getTaskId());
                        conflict.put("taskCode", activeTask.getTaskCode());
                        conflict.put("taskStatus", activeTask.getTaskStatus());
                        conflict.put("message", String.format("车辆 %s 尚有未完成的任务 %s,请先完成",
                            taskVehicle.getVehicleNo(), activeTask.getTaskCode()));
                        conflicts.add(conflict);
                    }
                }
            }
        }
        // 2. 检查执行人员是否有未完成的任务
        List<SysTaskAssignee> assignees = task.getAssignees();
        if (assignees != null && !assignees.isEmpty()) {
            for (SysTaskAssignee assignee : assignees) {
                Long userId = assignee.getUserId();
                // 查询该执行人的所有正在进行中的任务(排除PENDING、COMPLETED、CANCELLED)
                List<SysTask> userActiveTasks = this.selectMyTasks(userId).stream()
                    .filter(t -> !TaskStatus.PENDING.getCode().equals(t.getTaskStatus())
                              && !TaskStatus.COMPLETED.getCode().equals(t.getTaskStatus())
                              && !TaskStatus.CANCELLED.getCode().equals(t.getTaskStatus())
                              && !t.getTaskId().equals(taskId)) // 过滤掉当前任务
                    .collect(Collectors.toList());
                if (!userActiveTasks.isEmpty()) {
                    for (SysTask activeTask : userActiveTasks) {
                        Map<String, Object> conflict = new HashMap<>();
                        conflict.put("type", "assignee");
                        conflict.put("userName", assignee.getUserName());
                        conflict.put("taskId", activeTask.getTaskId());
                        conflict.put("taskCode", activeTask.getTaskCode());
                        conflict.put("taskStatus", activeTask.getTaskStatus());
                        conflict.put("message", String.format("执行人 %s 尚有正在进行中的任务 %s,请先完成",
                            assignee.getUserName(), activeTask.getTaskCode()));
                        conflicts.add(conflict);
                    }
                }
            }
        }
        // 3. 检查执行人是否全部就绪(受配置开关控制)
        String readyCheckEnabled = configService.selectConfigByKey("task.assignee.ready.check.enabled");
        if ("true".equalsIgnoreCase(readyCheckEnabled)) {
             assignees = task.getAssignees();
            if (assignees != null && !assignees.isEmpty()) {
                boolean allReady = assignees.stream()
                    .allMatch(a -> "1".equals(a.getIsReady()));
                if (!allReady) {
                    Map<String, Object> conflict = new HashMap<>();
                    conflict.put("type", "assigneeReady");
                    conflict.put("message", "存在未就绪的执行人,请等待所有执行人点击就绪后再出车");
                    conflicts.add(conflict);
                }
            }
        }
        result.put("valid", conflicts.isEmpty());
        result.put("conflicts", conflicts);
        return AjaxResult.success(result);
    }
    /**
     * 执行人点击就绪
     *
     * @param taskId 任务ID
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public AjaxResult setAssigneeReady(Long taskId, Long userId) {
        return sysTaskAssigneeService.setAssigneeReady(taskId, userId);
    }
    /**
     * 取消执行人就绪
     *
     * @param taskId 任务ID
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public AjaxResult cancelAssigneeReady(Long taskId, Long userId) {
        return sysTaskAssigneeService.cancelAssigneeReady(taskId, userId);
    }
    /**
     * 检查任务是否重复(根据联系人电话和创建日期)
     *
     * @param phone 联系人电话
     * @param createDate 任务创建日期(格式:YYYY-MM-DD)
     * @return true-存在重复,false-不重复
     */
    @Override
    public boolean checkTaskDuplicate(String phone, String createDate) {
        int count = sysTaskMapper.countTaskByPhoneAndDate(phone, createDate);
        return count > 0;
    }
}