wlzboy
2025-11-22 d4fe921568bc29d72644a55fd194adf7f9277cb5
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -1,10 +1,19 @@
package com.ruoyi.system.service.impl;
import java.io.*;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.IOException;
import java.util.stream.Collectors;
import java.net.HttpURLConnection;
import java.net.URL;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.mapper.*;
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;
@@ -12,22 +21,32 @@
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.GpsDistanceUtils;
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.SysTaskEmergency;
import com.ruoyi.system.domain.SysTaskWelfare;
import com.ruoyi.system.domain.SysTaskAssignee;
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.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.domain.VehicleInfo;
import com.ruoyi.system.service.ISysTaskService;
import com.ruoyi.system.service.ILegacySystemSyncService;
import com.ruoyi.system.service.ITaskAttachmentSyncService;
import com.ruoyi.system.event.TaskCreatedEvent;
import com.ruoyi.system.event.TaskAssignedEvent;
import com.ruoyi.system.event.TaskStatusChangedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
/**
 * 任务管理Service业务层处理
@@ -37,6 +56,8 @@
 */
@Service
public class SysTaskServiceImpl implements ISysTaskService {
    private static final Logger log = LoggerFactory.getLogger(SysTaskServiceImpl.class);
    
    @Autowired
    private SysTaskMapper sysTaskMapper;
@@ -49,6 +70,33 @@
    
    @Autowired
    private SysTaskLogMapper sysTaskLogMapper;
    @Autowired
    private SysTaskEmergencyMapper sysTaskEmergencyMapper;
    @Autowired
    private SysTaskWelfareMapper sysTaskWelfareMapper;
    @Autowired
    private SysTaskAssigneeMapper sysTaskAssigneeMapper;
    @Autowired
    private VehicleInfoMapper vehicleInfoMapper;
    @Autowired(required = false)
    private ILegacySystemSyncService legacySystemSyncService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private ImageUrlConfig imageUrlConfig;
    @Autowired(required = false)
    private ITaskAttachmentSyncService taskAttachmentSyncService;
    @Autowired
    private SysUserMapper sysUserMapper;
    /**
     * 查询任务管理
@@ -58,7 +106,20 @@
     */
    @Override
    public SysTask selectSysTaskByTaskId(Long taskId) {
        return sysTaskMapper.selectSysTaskByTaskId(taskId);
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null) {
            // 加载急救转运扩展信息
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                task.setEmergencyInfo(emergencyInfo);
            }
            // 加载福祉车扩展信息
            else if ("WELFARE".equals(task.getTaskType())) {
                SysTaskWelfare welfareInfo = sysTaskWelfareMapper.selectSysTaskWelfareByTaskId(taskId);
                task.setWelfareInfo(welfareInfo);
            }
        }
        return task;
    }
    /**
@@ -81,30 +142,320 @@
    @Override
    @Transactional
    public int insertSysTask(TaskCreateVO createVO) {
        String username = SecurityUtils.getUsername();
        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());
        // 优先使用前端传入的部门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");
        
        // 设置通用地址和坐标信息
        if (createVO.getDepartureAddress() != null) {
            task.setDepartureAddress(createVO.getDepartureAddress());
        }
        if (createVO.getDestinationAddress() != null) {
            task.setDestinationAddress(createVO.getDestinationAddress());
        }
        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.getEstimatedDistance() != null) {
            task.setEstimatedDistance(createVO.getEstimatedDistance());
        }
        // 设置急救转运特定信息
        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());
        }
        // 设置福祉车公里数
        if (createVO.getDistance() != null) {
            task.setEstimatedDistance(createVO.getDistance());
        }
        int result = sysTaskMapper.insertSysTask(task);
        // 保存车辆关联信息
        if (result > 0 && createVO.getVehicleIds() != null && !createVO.getVehicleIds().isEmpty()) {
            for (Long vehicleId : createVO.getVehicleIds()) {
                SysTaskVehicle taskVehicle = new SysTaskVehicle();
                taskVehicle.setTaskId(task.getTaskId());
                taskVehicle.setVehicleId(vehicleId);
                taskVehicle.setAssignTime(DateUtils.getNowDate());
                taskVehicle.setAssignBy(SecurityUtils.getUsername());
                taskVehicle.setStatus("ASSIGNED");
                taskVehicle.setCreateBy(SecurityUtils.getUsername());
                taskVehicle.setCreateTime(DateUtils.getNowDate());
                taskVehicle.setUpdateBy(SecurityUtils.getUsername());
                taskVehicle.setUpdateTime(DateUtils.getNowDate());
                sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
            }
        }
        // 保存执行人员信息(包含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),username);
        }
        // 保存急救转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            saveEmergencyInfo(task.getTaskId(),username, createVO,null,null);
        }
        // 保存福祉车扩展信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            saveWelfareInfo(task.getTaskId(),SecurityUtils.getUsername(), createVO);
        }
        
        // 记录操作日志
        if (result > 0) {
            recordTaskLog(task.getTaskId(), "CREATE", "创建任务", null, 
                         "任务类型:" + createVO.getTaskType(), SecurityUtils.getUserId(), SecurityUtils.getUsername());
        }
        // 发布任务创建事件
        if (result > 0) {
            eventPublisher.publishEvent(new TaskCreatedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                task.getTaskType(),
                task.getCreatorId(),
                SecurityUtils.getUsername()
            ));
        }
        // 发布任务分配事件
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            List<Long> assigneeIds = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserId())
                .collect(Collectors.toList());
            List<String> assigneeNames = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserName())
                .collect(Collectors.toList());
            eventPublisher.publishEvent(new TaskAssignedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                assigneeIds,
                assigneeNames,
                SecurityUtils.getUserId(),
                SecurityUtils.getUsername()
            ));
        }
        // 异步同步急救转运任务到旧系统
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType()) && legacySystemSyncService != null) {
            final Long finalTaskId = task.getTaskId();
            new Thread(() -> {
                try {
                    Thread.sleep(2000); // 等待2秒,确保事务已提交
                    legacySystemSyncService.syncEmergencyTaskToLegacy(finalTaskId);
                } catch (Exception e) {
                    // 同步失败不影响主流程,仅记录日志
                }
            }).start();
        }
        return result;
    }
    /**
     * 新增任务管理(允许从外部传入用户信息、部门信息和时间信息)
     *
     * @param createVO 任务创建对象
     * @param userId 用户ID
     * @param deptId 部门ID
     * @param createTime 创建时间
     * @param updateTime 更新时间
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, 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");
        // 设置通用地址和坐标信息
        if (createVO.getDepartureAddress() != null) {
            task.setDepartureAddress(createVO.getDepartureAddress());
        }
        if (createVO.getDestinationAddress() != null) {
            task.setDestinationAddress(createVO.getDestinationAddress());
        }
        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.getEstimatedDistance() != null) {
            task.setEstimatedDistance(createVO.getEstimatedDistance());
        }
        // 设置急救转运特定信息
        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());
        }
        // 设置福祉车公里数
        if (createVO.getDistance() != null) {
            task.setEstimatedDistance(createVO.getDistance());
        }
        int result = sysTaskMapper.insertSysTask(task);
        // 保存车辆关联信息
        if (result > 0 && createVO.getVehicleIds() != null && !createVO.getVehicleIds().isEmpty()) {
            for (Long vehicleId : createVO.getVehicleIds()) {
                SysTaskVehicle taskVehicle = new SysTaskVehicle();
                taskVehicle.setTaskId(task.getTaskId());
                taskVehicle.setVehicleId(vehicleId);
                taskVehicle.setAssignTime(updateTime);
                taskVehicle.setAssignBy(userName);
                taskVehicle.setStatus("ASSIGNED");
                taskVehicle.setCreateBy(userName);
                taskVehicle.setCreateTime(createTime);
                taskVehicle.setUpdateBy(userName);
                taskVehicle.setUpdateTime(updateTime);
                sysTaskVehicleMapper.insertSysTaskVehicle(taskVehicle);
            }
        }
        // 保存执行人员信息(包含角色类型)
        if (result > 0 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            saveTaskAssignees(task.getTaskId(), createVO.getAssignees(),userName);
        }
        // 保存急救转运扩展信息
        if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) {
            saveEmergencyInfo(task.getTaskId(),userName, createVO, serviceOrderId, dispatchOrderId);
        }
        // 保存福祉车扩展信息
        if (result > 0 && "WELFARE".equals(createVO.getTaskType())) {
            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 && createVO.getAssignees() != null && !createVO.getAssignees().isEmpty()) {
            List<Long> assigneeIds = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserId())
                .collect(Collectors.toList());
            List<String> assigneeNames = createVO.getAssignees().stream()
                .map(assignee -> assignee.getUserName())
                .collect(Collectors.toList());
            eventPublisher.publishEvent(new TaskAssignedEvent(
                this,
                task.getTaskId(),
                task.getTaskCode(),
                assigneeIds,
                assigneeNames,
                userId,
                userName
            ));
        }
        
        return result;
    }
@@ -128,12 +479,19 @@
        task.setTaskDescription(updateVO.getTaskDescription());
        task.setDepartureAddress(updateVO.getDepartureAddress());
        task.setDestinationAddress(updateVO.getDestinationAddress());
        task.setDepartureLongitude(updateVO.getDepartureLongitude());
        task.setDepartureLatitude(updateVO.getDepartureLatitude());
        task.setDestinationLongitude(updateVO.getDestinationLongitude());
        task.setDestinationLatitude(updateVO.getDestinationLatitude());
        task.setPlannedStartTime(updateVO.getPlannedStartTime());
        task.setPlannedEndTime(updateVO.getPlannedEndTime());
        task.setAssigneeId(updateVO.getAssigneeId());
        task.setUpdateBy(SecurityUtils.getUsername());
        task.setUpdateTime(DateUtils.getNowDate());
        task.setRemark(updateVO.getRemark());
        // 重新计算预计公里数
        calculateEstimatedDistance(task);
        
        int result = sysTaskMapper.updateSysTask(task);
        
@@ -177,18 +535,40 @@
    @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;
@@ -205,6 +585,21 @@
    @Override
    @Transactional
    public int changeTaskStatus(Long taskId, TaskStatus newStatus, String remark) {
        return changeTaskStatusWithLocation(taskId, newStatus, remark, null);
    }
    /**
     * 变更任务状态(含GPS位置信息)
     *
     * @param taskId 任务ID
     * @param newStatus 新状态
     * @param remark 备注
     * @param locationLog GPS位置信息日志对象
     * @return 结果
     */
    @Override
    @Transactional
    public int changeTaskStatusWithLocation(Long taskId, TaskStatus newStatus, String remark, SysTaskLog locationLog) {
        SysTask oldTask = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (oldTask == null) {
            throw new RuntimeException("任务不存在");
@@ -220,22 +615,53 @@
        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);
        }
        // 发布任务状态变更事件
        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());
            }
            eventPublisher.publishEvent(new TaskStatusChangedEvent(
                this,
                oldTask.getTaskId(),
                oldTask.getTaskCode(),
                oldTaskStatus.getCode(),
                newStatus.getCode(),
                oldTaskStatus.getInfo(),
                newStatus.getInfo(),
                assigneeIds,
                oldTask.getCreatorId()
            ));
        }
        
        return result;
@@ -246,37 +672,183 @@
     * 
     * @param taskId 任务ID
     * @param file 文件
     * @param category 附件分类
     * @return 结果
     */
    @Override
    @Transactional
    public int uploadAttachment(Long taskId, MultipartFile file) {
    public Long uploadAttachment(Long taskId, MultipartFile file, String category) {
        try {
            // 上传文件
            String fileName = FileUploadUtils.upload("/task", file);
            String filePath = FileUploadUtils.getDefaultBaseDir() + fileName;
            // 上传文件,返回相对路径(如:/task/2025/01/15/xxx.jpg)
            String fileName = category+"_"+System.currentTimeMillis()+"_"+file.getOriginalFilename();
            fileName=saveLocalPath(fileName,file.getInputStream());
            
            SysTaskAttachment attachment = new SysTaskAttachment();
            attachment.setTaskId(taskId);
            attachment.setFileName(file.getOriginalFilename());
            attachment.setFilePath(filePath);
            // 保存相对路径,不包含 baseDir
            attachment.setFilePath(fileName);
            attachment.setFileSize(file.getSize());
            attachment.setFileType(getFileType(file.getOriginalFilename()));
            attachment.setAttachmentCategory(category);
            attachment.setUploadTime(DateUtils.getNowDate());
            attachment.setUploadBy(SecurityUtils.getUsername());
            
            int result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
            Long result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
            
            // 记录操作日志
            if (result > 0) {
                String categoryDesc = getCategoryDesc(category);
                recordTaskLog(taskId, "UPDATE", "上传附件", null, 
                             "上传文件:" + file.getOriginalFilename(),
                             "上传文件:" + file.getOriginalFilename() + "(分类:" + categoryDesc + ")",
                             SecurityUtils.getUserId(), SecurityUtils.getUsername());
            }
            
            return result;
            return attachment.getAttachmentId();
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败:" + e.getMessage());
        }
    }
    /**
     * 从微信mediaId上传任务附件
     *
     * @param taskId 任务ID
     * @param accessToken 微信AccessToken
     * @param mediaId 微信mediaId
     * @param category 附件分类
     * @return 返回附件ID
     */
    @Override
    @Transactional
    public Long uploadAttachmentFromWechat(Long taskId, String accessToken, String mediaId, String category) {
        try {
            // 从微信服务器下载文件
            String wechatUrl = String.format(
                "https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s",
                accessToken, mediaId
            );
            byte[] fileBytes = downloadFromUrl(wechatUrl);
            if (fileBytes == null || fileBytes.length == 0) {
                throw new RuntimeException("从微信下载文件失败");
            }
            // 生成文件名(使用mediaId作为文件名的一部分)
            String fileName = "wx_" + mediaId.substring(0, Math.min(20, mediaId.length())) + "_" + System.currentTimeMillis() + ".jpg";
            // 保存到本地
            String relativeFilePath = saveLocalPath(fileName, fileBytes);
            // 保存附件记录
            SysTaskAttachment attachment = new SysTaskAttachment();
            attachment.setTaskId(taskId);
            attachment.setFileName(fileName);
            // 保存相对路径
            attachment.setFilePath(relativeFilePath);
            attachment.setFileSize((long) fileBytes.length);
            attachment.setFileType("jpg");
            attachment.setAttachmentCategory(category);
            attachment.setUploadTime(DateUtils.getNowDate());
            attachment.setUploadBy(SecurityUtils.getUsername());
            Long result = sysTaskAttachmentMapper.insertSysTaskAttachment(attachment);
            // 记录操作日志
            if (result > 0) {
                String categoryDesc = getCategoryDesc(category);
                recordTaskLog(taskId, "UPDATE", "上传附件", null,
                             "通过微信上传文件:" + fileName + "(分类:" + categoryDesc + ")",
                             SecurityUtils.getUserId(), SecurityUtils.getUsername());
            }
            return attachment.getAttachmentId();
        } catch (Exception e) {
            throw new RuntimeException("从微信上传文件失败:" + e.getMessage());
        }
    }
    private static String saveLocalPath(String fileName, byte[] fileBytes) throws IOException {
        String baseDir = FileUploadUtils.getDefaultBaseDir();
        String datePath = DateUtils.datePath();
        String uploadDir = baseDir + "/task/" + datePath;
        // 创建目录
        File uploadPath = new File(uploadDir);
        if (!uploadPath.exists()) {
            uploadPath.mkdirs();
        }
        // 保存文件
        String filePath = uploadDir + "/" + fileName;
        File file = new File(filePath);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(fileBytes);
        }
        // 生成相对路径(不包含baseDir)
        String relativeFilePath = "/task/" + datePath + "/" + fileName;
        return relativeFilePath;
    }
    private String saveLocalPath(String fileName,InputStream stream){
        String baseDir = FileUploadUtils.getDefaultBaseDir();
        String datePath = DateUtils.datePath();
        String uploadDir = baseDir + "/task/" + datePath;
        // 创建目录
        File uploadPath = new File(uploadDir);
        if (!uploadPath.exists()) {
            uploadPath.mkdirs();
        }
        // 保存文件
        String filePath = uploadDir + "/" + fileName;
       //将inputstream写入文件
        try (OutputStream os = new FileOutputStream(filePath)) {
            byte[] buffer = new byte[1024]; // 缓冲区,减少 IO 次数
            int bytesRead;
            // 循环读取输入流中的数据,写入输出流
            while ((bytesRead = stream.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush(); // 强制刷新缓冲区,确保数据写入文件
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 生成相对路径(不包含baseDir)
        String relativeFilePath = "/task/" + datePath + "/" + fileName;
        return relativeFilePath;
    }
    /**
     * 从 URL 下载文件
     */
    private byte[] downloadFromUrl(String fileUrl) throws IOException {
        URL url = new URL(fileUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(30000);
        try (InputStream inputStream = connection.getInputStream()) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream();
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            return outputStream.toByteArray();
        } finally {
            connection.disconnect();
        }
    }
@@ -311,6 +883,27 @@
        }
        
        return result;
    }
    /**
     * 根据ID获取附件详情
     *
     * @param attachmentId 附件ID
     * @return 附件详情
     */
    @Override
    public SysTaskAttachment getAttachmentById(Long attachmentId) {
        SysTaskAttachment attachment = sysTaskAttachmentMapper.selectSysTaskAttachmentByAttachmentId(attachmentId);
        if (attachment != null) {
            // 拼接完整URL
            buildAttachmentUrl(attachment);
        }
        return attachment;
    }
    @Override
    public List<SysTaskAttachment> getAttachmentsByTaskId(Long taskId) {
        return sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId);
    }
    /**
@@ -437,9 +1030,34 @@
     */
    @Override
    public List<SysTaskVehicle> getAvailableVehicles(Long deptId, String taskType) {
        // 这里需要根据业务逻辑查询可用车辆
        // 暂时返回空列表,实际实现需要查询车辆表
        return new ArrayList<>();
        List<SysTaskVehicle> availableVehicles = new ArrayList<>();
        try {
            // 查询所有状态为正常的车辆(不限制部门)
            VehicleInfo queryParam = new VehicleInfo();
            queryParam.setStatus("0"); // 0表示正常状态
            // 不设置deptId,查询所有部门的车辆
            queryParam.setDeptId(deptId);
            List<VehicleInfo> vehicles = vehicleInfoMapper.selectVehicleInfoList(queryParam);
            // 转换为SysTaskVehicle对象
            for (VehicleInfo vehicle : vehicles) {
                SysTaskVehicle taskVehicle = new SysTaskVehicle();
                taskVehicle.setVehicleId(vehicle.getVehicleId());
                taskVehicle.setVehicleNo(vehicle.getVehicleNo());
                taskVehicle.setVehicleType(vehicle.getVehicleType());
                taskVehicle.setVehicleBrand(vehicle.getVehicleBrand());
                taskVehicle.setVehicleModel(vehicle.getVehicleModel());
                taskVehicle.setDeptName(vehicle.getDeptName()); // 添加部门名称
                availableVehicles.add(taskVehicle);
            }
        } catch (Exception e) {
            // 如果查询失败,记录日志并返回空列表
            System.err.println("查询可用车辆失败: " + e.getMessage());
        }
        return availableVehicles;
    }
    /**
@@ -486,21 +1104,114 @@
            // 查询关联车辆
            task.setAssignedVehicles(sysTaskVehicleMapper.selectSysTaskVehicleByTaskId(taskId));
            // 查询附件
            task.setAttachments(sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId));
            List<SysTaskAttachment> attachments = sysTaskAttachmentMapper.selectSysTaskAttachmentByTaskId(taskId);
            // 为每个附件拼接完整URL
            if (attachments != null && !attachments.isEmpty()) {
                attachments.forEach(this::buildAttachmentUrl);
            }
            task.setAttachments(attachments);
            // 查询操作日志
            task.setOperationLogs(sysTaskLogMapper.selectSysTaskLogByTaskId(taskId));
            // 加载急救转运扩展信息
            if ("EMERGENCY_TRANSFER".equals(task.getTaskType())) {
                SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
                task.setEmergencyInfo(emergencyInfo);
            }
            // 加载福祉车扩展信息
            else if ("WELFARE".equals(task.getTaskType())) {
                SysTaskWelfare welfareInfo = sysTaskWelfareMapper.selectSysTaskWelfareByTaskId(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) {
        // 只有急救转运任务才有旧系统ID
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null && "EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            return emergencyInfo != null && emergencyInfo.getLegacyServiceOrdId() != null;
        }
        return false;
    }
    /**
     * 检查任务是否已关联旧系统调度单ID
     *
     * @param taskId 任务ID
     * @return true-已关联,false-未关联
     */
    @Override
    public boolean hasLegacyDispatchOrdId(Long taskId) {
        // 只有急救转运任务才有旧系统ID
        SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId);
        if (task != null && "EMERGENCY_TRANSFER".equals(task.getTaskType())) {
            SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId);
            return emergencyInfo != null && emergencyInfo.getLegacyDispatchOrdId() != null;
        }
        return false;
    }
    /**
     * 根据旧系统服务单ID检查是否存在任务
     *
     * @param legacyServiceOrdId 旧系统服务单ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyServiceOrdId(Long legacyServiceOrdId) {
        if (legacyServiceOrdId == null) {
            return false;
        }
        SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectByLegacyServiceOrdId(legacyServiceOrdId);
        return emergencyInfo != null;
    }
    /**
     * 根据旧系统调度单ID检查是否存在任务
     *
     * @param legacyDispatchOrdId 旧系统调度单ID
     * @return true-存在,false-不存在
     */
    @Override
    public boolean existsByLegacyDispatchOrdId(Long legacyDispatchOrdId) {
        if (legacyDispatchOrdId == null) {
            return false;
        }
        SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectByLegacyDispatchOrdId(legacyDispatchOrdId);
        return emergencyInfo != null;
    }
    @Autowired
    private TaskCodeGenerator taskCodeGenerator;
    /**
     * 生成任务编号
     * 
     * @return 任务编号
     */
    private String generateTaskCode() {
        String dateStr = DateUtils.dateTimeNow("yyyyMMdd");
        return "TASK" + dateStr + "0001";
        return taskCodeGenerator.generateTaskCode();
    }
    /**
@@ -516,7 +1227,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);
@@ -564,4 +1297,241 @@
        }
        return "";
    }
    /**
     * 计算预计公里数
     *
     * @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);
        }
    }
    /**
     * 保存任务执行人员信息(包含角色类型)
     *
     * @param taskId 任务ID
     * @param assignees 执行人员信息列表
     */
    private void saveTaskAssignees(Long taskId, java.util.List<TaskCreateVO.AssigneeInfo> assignees,String userName) {
        if (assignees == null || assignees.isEmpty()) {
            return;
        }
        java.util.List<SysTaskAssignee> taskAssignees = new java.util.ArrayList<>();
        Date now = DateUtils.getNowDate();
        String currentUser = userName;
        for (int i = 0; i < assignees.size(); i++) {
            TaskCreateVO.AssigneeInfo assigneeInfo = assignees.get(i);
            SysTaskAssignee taskAssignee = new SysTaskAssignee();
            taskAssignee.setTaskId(taskId);
            taskAssignee.setUserId(assigneeInfo.getUserId());
            taskAssignee.setUserName(assigneeInfo.getUserName());
            taskAssignee.setUserType(assigneeInfo.getUserType());
            // 第一个执行人员为主要执行人
            taskAssignee.setIsPrimary(i == 0 ? "1" : "0");
            taskAssignee.setSortOrder(i);
            taskAssignee.setCreateTime(now);
            taskAssignee.setCreateBy(currentUser);
            taskAssignee.setUpdateTime(now);
            taskAssignee.setUpdateBy(currentUser);
            taskAssignees.add(taskAssignee);
        }
        // 批量保存
        if (!taskAssignees.isEmpty()) {
            sysTaskAssigneeMapper.batchInsertSysTaskAssignee(taskAssignees);
        }
    }
    /**
     * 保存急救转运任务扩展信息
     *
     * @param taskId 任务ID
     * @param createVO 任务创建对象
     */
    private void saveEmergencyInfo(Long taskId,String createUserName, TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId) {
        SysTaskEmergency emergencyInfo = new SysTaskEmergency();
        emergencyInfo.setTaskId(taskId);
        // 设置患者信息
        if (createVO.getPatient() != null) {
            emergencyInfo.setPatientContact(createVO.getPatient().getContact());
            emergencyInfo.setPatientPhone(createVO.getPatient().getPhone());
            emergencyInfo.setPatientName(createVO.getPatient().getName());
            emergencyInfo.setPatientGender(createVO.getPatient().getGender());
            emergencyInfo.setPatientIdCard(createVO.getPatient().getIdCard());
            emergencyInfo.setPatientCondition(createVO.getPatient().getCondition());
        }
        // 设置转出医院信息
        if (createVO.getHospitalOut() != null) {
            emergencyInfo.setHospitalOutId(createVO.getHospitalOut().getId());
            emergencyInfo.setHospitalOutName(createVO.getHospitalOut().getName());
            emergencyInfo.setHospitalOutDepartment(createVO.getHospitalOut().getDepartment());
            emergencyInfo.setHospitalOutDepartmentId(createVO.getHospitalOut().getDepartmentId());
            emergencyInfo.setHospitalOutBedNumber(createVO.getHospitalOut().getBedNumber());
            emergencyInfo.setHospitalOutAddress(createVO.getHospitalOut().getAddress());
            emergencyInfo.setHospitalOutLongitude(createVO.getHospitalOut().getLongitude());
            emergencyInfo.setHospitalOutLatitude(createVO.getHospitalOut().getLatitude());
        }
        // 设置转入医院信息
        if (createVO.getHospitalIn() != null) {
            emergencyInfo.setHospitalInId(createVO.getHospitalIn().getId());
            emergencyInfo.setHospitalInName(createVO.getHospitalIn().getName());
            emergencyInfo.setHospitalInDepartment(createVO.getHospitalIn().getDepartment());
            emergencyInfo.setHospitalInDepartmentId(createVO.getHospitalIn().getDepartmentId());
            emergencyInfo.setHospitalInBedNumber(createVO.getHospitalIn().getBedNumber());
            emergencyInfo.setHospitalInAddress(createVO.getHospitalIn().getAddress());
            emergencyInfo.setHospitalInLongitude(createVO.getHospitalIn().getLongitude());
            emergencyInfo.setHospitalInLatitude(createVO.getHospitalIn().getLatitude());
        }
        // 设置费用信息
        emergencyInfo.setTransferDistance(createVO.getTransferDistance());
        emergencyInfo.setTransferPrice(createVO.getPrice());
        // 设置单据类型ID
        emergencyInfo.setDocumentTypeId(createVO.getDocumentTypeId());
        // 设置任务类型ID
        emergencyInfo.setTaskTypeId(createVO.getTaskTypeId());
        // 设置病情ID列表(将List<Long>转换为逗号分隔的字符串)
        if (createVO.getDiseaseIds() != null && !createVO.getDiseaseIds().isEmpty()) {
            String diseaseIdsStr = createVO.getDiseaseIds().stream()
                .map(String::valueOf)
                .collect(Collectors.joining(","));
            emergencyInfo.setDiseaseIds(diseaseIdsStr);
        }
        if(serviceOrderId!=null){
            emergencyInfo.setLegacyServiceOrdId(Long.parseLong(serviceOrderId));
            emergencyInfo.setSyncStatus(2);
            emergencyInfo.setSyncTime(new Date());
            emergencyInfo.setSyncErrorMsg("旧系统同步过来");
        }
        if(dispatchOrderId!=null){
            emergencyInfo.setLegacyDispatchOrdId(Long.parseLong(dispatchOrderId));
            emergencyInfo.setDispatchSyncStatus(2);
            emergencyInfo.setDispatchSyncTime(new Date());
            emergencyInfo.setDispatchSyncErrorMsg("旧系统同步过来");
        // 系统字段
        }
        // 系统字段
        emergencyInfo.setCreateTime(DateUtils.getNowDate());
        emergencyInfo.setUpdateTime(DateUtils.getNowDate());
        emergencyInfo.setCreateBy(createUserName);
        emergencyInfo.setUpdateBy(createUserName);
        sysTaskEmergencyMapper.insertSysTaskEmergency(emergencyInfo);
    }
    /**
     * 保存福祉车任务扩展信息
     *
     * @param taskId 任务ID
     * @param createVO 任务创建对象
     */
    private void saveWelfareInfo(Long taskId,String userName, TaskCreateVO createVO) {
        SysTaskWelfare welfareInfo = new SysTaskWelfare();
        welfareInfo.setTaskId(taskId);
        // 设置乘客信息
        if (createVO.getPassenger() != null) {
            welfareInfo.setPassengerContact(createVO.getPassenger().getContact());
            welfareInfo.setPassengerPhone(createVO.getPassenger().getPhone());
        }
        // 设置地址信息
        welfareInfo.setPickupAddress(createVO.getStartAddress());
        welfareInfo.setDestinationAddress(createVO.getEndAddress());
        // 设置GPS坐标
        welfareInfo.setPickupLongitude(createVO.getDepartureLongitude());
        welfareInfo.setPickupLatitude(createVO.getDepartureLatitude());
        welfareInfo.setDestinationLongitude(createVO.getDestinationLongitude());
        welfareInfo.setDestinationLatitude(createVO.getDestinationLatitude());
        // 设置距离和费用
        // 优先使用福祉车专用的distance字段,如果没有则使用通用的estimatedDistance
        BigDecimal serviceDistance = createVO.getDistance() != null ? createVO.getDistance() : createVO.getEstimatedDistance();
        welfareInfo.setServiceDistance(serviceDistance);
        welfareInfo.setServicePrice(createVO.getPrice());
        // 系统字段
        welfareInfo.setCreateTime(DateUtils.getNowDate());
        welfareInfo.setUpdateTime(DateUtils.getNowDate());
        welfareInfo.setCreateBy(userName);
        welfareInfo.setUpdateBy(userName);
        sysTaskWelfareMapper.insertSysTaskWelfare(welfareInfo);
    }
    /**
     * 获取附件分类描述
     *
     * @param category 附件分类代码
     * @return 分类描述
     */
    private String getCategoryDesc(String category) {
        if (category == null || category.isEmpty()) {
            return "未分类";
        }
        switch (category) {
            case "1": return "知情同意书";
            case "2": return "病人资料";
            case "3": return "操作记录";
            case "4": return "出车前";
            case "5": return "出车后";
            case "6": return "系安全带";
            default: return "其他";
        }
    }
    /**
     * 构建附件的完整URL
     *
     * @param attachment 附件对象
     */
    private void buildAttachmentUrl(SysTaskAttachment attachment) {
        if (attachment != null && StringUtils.isNotEmpty(attachment.getFilePath())) {
            String imageUrl = imageUrlConfig.getImageUrl();
            if (StringUtils.isNotEmpty(imageUrl)) {
                // 拼接完整URL:域名 + 相对路径
                attachment.setFileUrl(imageUrl + attachment.getFilePath());
            } else {
                // 如果未配置域名,直接使用相对路径
                attachment.setFileUrl(attachment.getFilePath());
            }
        }
    }
}