wlzboy
2025-12-25 ae478a3d5dab28dd598d39f27429e4a544b15ad2
feat:已完成时,检查附件是否上传
17个文件已修改
266 ■■■■ 已修改文件
app/api/task.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/index.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pages/task/index.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/create-emergency.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/create-normal.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/create-welfare.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/detail.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/edit-welfare.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/pagesTask/edit.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskAttachmentSyncController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskSyncUtilService.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusPushConverter.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/api/task.js
@@ -165,3 +165,15 @@
    method: 'post'
  })
}
// 检查任务是否重复(根据联系人电话和创建日期)
export function checkTaskDuplicate(phone, createDate) {
  return request({
    url: '/task/checkDuplicate',
    method: 'get',
    params: {
      phone: phone,
      createDate: createDate
    }
  })
}
app/pages/index.vue
@@ -851,12 +851,19 @@
          title: '检查附件...'
        });
        
        const response = await checkTaskConsentAttachment(taskId);
        // 注意:这里会被请求拦截器处理,code !== 200 时会 reject
        const response = await checkTaskConsentAttachment(taskId).catch(err => {
          // 拦截器 reject 的情况,返回一个默认对象
          console.log('请求被拦截器 reject,err:', err);
          return { code: -1, msg: '未上传知情同意书' };
        });
        
        uni.hideLoading();
        console.log('检查附件结果:', response);
        
        if (response.code === 200) {
        if (response && response.code === 200) {
          // 已上传知情同意书,继续更新状态
          console.log('已上传知情同意书,继续完成任务');
          this.$modal
            .confirm("确认任务已完成?")
            .then(() => {
@@ -864,20 +871,21 @@
            })
            .catch(() => {});
        } else {
          // 未上传知情同意书,显示提示
          this.$modal.confirm('任务未上传知情同意书,无法完成任务。是否现在去上传?').then(() => {
          // 未上传知情同意书或其他错误,阻止完成
          const message = (response && response.msg) || '任务未上传知情同意书,无法完成任务';
          console.log('未上传知情同意书,阻止完成');
          this.$modal.confirm(message + '。是否现在去上传?').then(() => {
            // 跳转到任务详情页上传附件
            this.$tab.navigateTo(`/pagesTask/detail?id=${taskId}`);
          }).catch(() => {});
        }
      } catch (error) {
        uni.hideLoading();
        console.error('检查附件失败:', error);
        console.error('检查附件异常:', error);
        
        // 如果检查失败,询问用户是否继续
        this.$modal.confirm('检查附件状态失败,是否继续完成任务?').then(() => {
          this.updateTaskStatus(taskId, status, remark);
        }).catch(() => {});
        // 如果检查失败(网络异常等),不允许完成任务
        this.$modal.showToast('检查附件状态失败,无法完成任务');
      }
    },
app/pages/task/index.vue
@@ -940,12 +940,19 @@
          title: '检查附件...'
        });
        
        const response = await checkTaskConsentAttachment(taskId);
        // 注意:这里会被请求拦截器处理,code !== 200 时会 reject
        const response = await checkTaskConsentAttachment(taskId).catch(err => {
          // 拦截器 reject 的情况,返回一个默认对象
          console.log('请求被拦截器 reject,err:', err);
          return { code: -1, msg: '未上传知情同意书' };
        });
        
        uni.hideLoading();
        console.log('检查附件结果:', response);
        
        if (response.code === 200) {
        if (response && response.code === 200) {
          // 已上传知情同意书,继续更新状态
          console.log('已上传知情同意书,继续完成任务');
          this.$modal
            .confirm("确认任务已完成?")
            .then(() => {
@@ -953,8 +960,11 @@
            })
            .catch(() => {});
        } else {
          // 未上传知情同意书,显示提示
          this.$modal.confirm('任务未上传知情同意书,无法完成任务。是否现在去上传?').then(() => {
          // 未上传知情同意书或其他错误,阻止完成
          const message = (response && response.msg) || '任务未上传知情同意书,无法完成任务';
          console.log('未上传知情同意书,阻止完成');
          this.$modal.confirm(message + '。是否现在去上传?').then(() => {
            // 跳转到任务详情页上传附件
            uni.navigateTo({
              url: `/pagesTask/detail?id=${taskId}`
@@ -963,12 +973,10 @@
        }
      } catch (error) {
        uni.hideLoading();
        console.error('检查附件失败:', error);
        console.error('检查附件异常:', error);
        
        // 如果检查失败,询问用户是否继续
        this.$modal.confirm('检查附件状态失败,是否继续完成任务?').then(() => {
          this.updateTaskStatus(taskId, status, remark);
        }).catch(() => {});
        // 如果检查失败(网络异常等),不允许完成任务
        this.$modal.showToast('检查附件状态失败,无法完成任务');
      }
    },
app/pagesTask/create-emergency.vue
@@ -266,7 +266,7 @@
import { mapState } from 'vuex'
import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue'
import { addTask } from "@/api/task"
import { addTask, checkTaskDuplicate } from "@/api/task"
import { listAvailableVehicles, getUserBoundVehicle } from "@/api/vehicle"
import { searchHospitals, searchHospitalsByDeptRegion } from "@/api/hospital"
import DepartureSelector from './components/DepartureSelector.vue'
@@ -909,6 +909,38 @@
        return
      }
      
      // 获取当前日期(格式YYYY-MM-DD)
      const today = new Date()
      const createDate = today.getFullYear() + '-' +
                        String(today.getMonth() + 1).padStart(2, '0') + '-' +
                        String(today.getDate()).padStart(2, '0')
      const phone = this.taskForm.patient.phone
      // 先检查是否重复
      uni.showLoading({
        title: '检查中...'
      })
      checkTaskDuplicate(phone, createDate).then(response => {
        uni.hideLoading()
        // 如果接口返回错误,说明存在重复
        if (response.code !== 200) {
          this.$modal.showToast(response.msg || '该联系电话在当天已有任务,不能重复提交')
          return
        }
        // 检查通过,继续提交
        this.doSubmitTask()
      }).catch(error => {
        uni.hideLoading()
        console.error('重复性检查失败:', error)
        this.$modal.showToast('检查失败,请重试')
      })
    },
    // 执行实际的提交操作
    doSubmitTask() {
      this.$modal.confirm('确定要保存任务吗?').then(() => {
        this.loading = true
        const submitData = this.buildSubmitData()
app/pagesTask/create-normal.vue
@@ -91,7 +91,7 @@
          class="form-input" 
          type="digit" 
          placeholder="请输入行驶公里数" 
          v-model="taskForm.distance"
          v-model="taskForm.transferDistance"
        />
      </view>
      
@@ -186,7 +186,7 @@
        plannedEndTime: '',
        startLocation: '',
        endLocation: '',
        distance: '',
        transferDistance: '',
        remark: ''
      },
      vehicles: [],
@@ -497,7 +497,7 @@
          // 百度地图返回的距离单位是米,需要转换为公里
          const distanceInMeters = response.data.distance
          const distanceInKm = distanceInMeters / 1000
          this.taskForm.distance = distanceInKm.toFixed(2)
          this.taskForm.transferDistance = distanceInKm.toFixed(2)
          
          console.log('距离计算成功:', distanceInMeters, '米 =', distanceInKm, '公里')
          
@@ -576,7 +576,7 @@
        plannedEndTime: this.taskForm.plannedEndTime,
        departureAddress: this.taskForm.startLocation,
        destinationAddress: this.taskForm.endLocation,
        estimatedDistance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
        transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
        remark: this.taskForm.remark
      }
      
app/pagesTask/create-welfare.vue
@@ -103,7 +103,7 @@
          class="form-input" 
          type="digit" 
          placeholder="请输入公里数" 
          v-model="taskForm.distance"
          v-model="taskForm.transferDistance"
        />
      </view>
      
@@ -171,7 +171,7 @@
        },
        startAddress: '',
        endAddress: '',
        distance: '',
        transferDistance: '',
        price: ''
      },
      vehicles: [],
@@ -267,7 +267,7 @@
          this.addressCoordinates.endAddress.lat,
          this.addressCoordinates.endAddress.lng
        ).then(distance => {
          this.taskForm.distance = distance.toFixed(2)
          this.taskForm.transferDistance = distance.toFixed(2)
        }).catch(error => {
          console.error('距离计算失败:', error)
        })
@@ -344,7 +344,7 @@
        passenger: this.taskForm.passenger,
        startAddress: this.taskForm.startAddress,
        endAddress: this.taskForm.endAddress,
        distance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
        transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
        price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
      }
      
app/pagesTask/detail.vue
@@ -1014,16 +1014,27 @@
            title: '检查附件...'
          });
          
          const response = await checkTaskConsentAttachment(this.taskId);
          // 注意:这里会被请求拦截器处理,code !== 200 时会 reject
          const response = await checkTaskConsentAttachment(this.taskId).catch(err => {
            // 拦截器 reject 的情况,返回一个默认对象
            console.log('请求被拦截器 reject,err:', err);
            return { code: -1, msg: '未上传知情同意书' };
          });
          
          uni.hideLoading();
          console.log('检查附件结果:', response);
          
          if (response.code === 200) {
          // 后台返回 code: 200 表示已上传,code: -1 表示未上传
          if (response && response.code === 200) {
            // 已上传知情同意书,继续更新状态
            console.log('已上传知情同意书,继续完成任务');
            this.getLocationAndUpdateStatus(status, remark);
          } else {
            // 未上传知情同意书,显示提示
            this.$modal.confirm('任务未上传知情同意书,无法完成任务。是否现在去上传?').then(() => {
            // 未上传知情同意书或其他错误,阻止完成
            const message = (response && response.msg) || '任务未上传知情同意书,无法完成任务';
            console.log('未上传知情同意书,阻止完成');
            this.$modal.confirm(message + '。是否现在去上传?').then(() => {
              // 滚动到附件上传区域
              this.$nextTick(() => {
                uni.pageScrollTo({
@@ -1035,12 +1046,10 @@
          }
        } catch (error) {
          uni.hideLoading();
          console.error('检查附件失败:', error);
          console.error('检查附件异常:', error);
          
          // 如果检查失败,询问用户是否继续
          this.$modal.confirm('检查附件状态失败,是否继续完成任务?').then(() => {
            this.getLocationAndUpdateStatus(status, remark);
          }).catch(() => {});
          // 如果检查失败(网络异常等),不允许完成任务
          this.$modal.showToast('检查附件状态失败,无法完成任务');
        }
      },
      
app/pagesTask/edit-welfare.vue
@@ -380,7 +380,7 @@
        destinationLatitude: this.addressCoordinates.endAddress ? this.addressCoordinates.endAddress.lat : null,
        
        // 距离和价格(主任务字段)
        distance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
        transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
        price: this.taskForm.price ? parseFloat(this.taskForm.price) : null,
        
        // 乘客信息(嵌套对象)
app/pagesTask/edit.vue
@@ -53,7 +53,7 @@
          class="form-input" 
          type="digit" 
          placeholder="请输入行驶公里数" 
          v-model="taskForm.distance"
          v-model="taskForm.transferDistance"
        />
      </view>
      
@@ -165,7 +165,7 @@
        plannedEndTime: '',
        startLocation: '',
        endLocation: '',
        distance: '',
        transferDistance: '',
        remark: ''
      },
      loading: false
@@ -209,7 +209,7 @@
        this.taskForm.plannedEndTime = this.taskDetail.plannedEndTime || ''
        this.taskForm.startLocation = this.taskDetail.departureAddress || ''
        this.taskForm.endLocation = this.taskDetail.destinationAddress || ''
        this.taskForm.distance = this.taskDetail.estimatedDistance || ''
        this.taskForm.transferDistance = this.taskDetail.transferDistance || ''
        this.taskForm.remark = this.taskDetail.remark || ''
        
        // 设置车辆信息
@@ -289,7 +289,7 @@
      
      // 监听mixin中的距离计算完成事件
      this.$once('distance-calculated', (distance) => {
        this.taskForm.distance = this.formatDistance(distance)
        this.taskForm.transferDistance = this.formatDistance(distance)
      })
      
      this.closeMapSelector()
@@ -360,7 +360,7 @@
        destinationLatitude: this.addressCoordinates.endLocation ? this.addressCoordinates.endLocation.lat : null,
        
        // 距离(主任务字段)
        distance: this.taskForm.distance ? parseFloat(this.taskForm.distance) : null,
        transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
        
        remark: this.taskForm.remark
      }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/SysTaskController.java
@@ -193,6 +193,30 @@
    public AjaxResult appAdd(@RequestBody TaskCreateVO createVO) {
        return toAjax(sysTaskService.insertSysTask(createVO));
    }
    /**
     * 检查任务是否重复(根据联系人电话和创建日期)
     * @param phone 联系人电话
     * @param createDate 任务创建日期(格式:YYYY-MM-DD)
     * @return 是否存在重复任务
     */
    @GetMapping("/checkDuplicate")
    public AjaxResult checkDuplicate(
            @RequestParam("phone") String phone,
            @RequestParam("createDate") String createDate) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(createDate)) {
            return AjaxResult.error("参数不能为空");
        }
        boolean isDuplicate = sysTaskService.checkTaskDuplicate(phone, createDate);
        if (isDuplicate) {
            return AjaxResult.error("该联系电话在该日期已有任务,不能重复提交");
        }
        return AjaxResult.success("未发现重复任务");
    }
    /**
     * 修改任务(后台管理端)
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskAttachmentSyncController.java
@@ -87,17 +87,28 @@
        }
    }
    /**
     * 检查任务是否上传了知情同意书
     *
     * @param taskId 任务ID
     * @return 检查结果
     */
    @PostMapping("/task/check/{taskId}")
    public AjaxResult checkTaskAttachment(@PathVariable("taskId") Long taskId) {
        try {
            logger.info("检查任务 {} 的知情同意书附件", taskId);
            Boolean ret=taskAttachmentSyncService.checkAttachment(taskId,"1");
            if(ret){
                logger.info("任务 {} 已上传知情同意书", taskId);
                return AjaxResult.success("已上传知情同意书");
            }else{
                logger.warn("任务 {} 未上传知情同意书", taskId);
                return AjaxResult.error(-1,"未上传知情同意书");
            }
        }catch (Exception e){
            logger.error("检查任务 {} 的附件失败", taskId, e);
            return AjaxResult.error("检查失败:" + e.getMessage());
        }
    }
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysTaskMapper.java
@@ -140,4 +140,13 @@
    public List<SysTask> selectTaskByVehicleIdAndDate(@Param("vehicleId") Long vehicleId,
                                                      @Param("startTime") String startTime,
                                                      @Param("endTime") String endTime);
    /**
     * 根据联系人电话和创建日期查询任务数量
     *
     * @param phone 联系人电话
     * @param createDate 任务创建日期(格式:YYYY-MM-DD)
     * @return 任务数量
     */
    public int countTaskByPhoneAndDate(@Param("phone") String phone, @Param("createDate") String createDate);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java
@@ -336,5 +336,14 @@
     * @return 结果
     */
    public com.ruoyi.common.core.domain.AjaxResult cancelAssigneeReady(Long taskId, Long userId);
    /**
     * 检查任务是否重复(根据联系人电话和创建日期)
     *
     * @param phone 联系人电话
     * @param createDate 任务创建日期(格式:YYYY-MM-DD)
     * @return true-存在重复,false-不重复
     */
    public boolean checkTaskDuplicate(String phone, String createDate);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java
@@ -1717,6 +1717,19 @@
    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;
    }
   
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TaskSyncUtilService.java
@@ -19,6 +19,7 @@
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
@@ -91,6 +92,9 @@
        return adminID;
    }
    private String getCoo(BigDecimal lng, BigDecimal lat){
        return lng+","+lat;
    }
    /**
     * 构建同步参数
     */
@@ -160,7 +164,7 @@
        params.put("ServiceOrdCoName", StringUtils.nvl(emergency.getPatientContact(), ""));
        params.put("ServiceOrdCoPhone", StringUtils.nvl(emergency.getPatientPhone(), ""));
        params.put("ServiceOrdCoTies", ""); // 联系人与患者关系
//ServiceOrdTraVia
        // 患者信息
        params.put("ServiceOrdPtName", StringUtils.nvl(emergency.getPatientName(), ""));
        params.put("ServiceOrdPtAge", ""); // 年龄
@@ -196,14 +200,14 @@
        params.put("ServiceOrdTraStreetCoo", ""); // 出发地坐标
        params.put("ServiceOrdTraEnd", StringUtils.nvl(task.getDestinationAddress(), StringUtils.nvl(emergency.getHospitalInAddress(), "")));
        params.put("ServiceOrdTraEndCoo", ""); // 目的地坐标
        params.put("ServiceOrdTraVia", ""); // 途经地
        params.put("ServiceOrdTraVia", emergency.getHospitalOutAddress()!=null ? emergency.getHospitalOutAddress() : ""); // 途经地
        // 距离和价格信息
        params.put("ServiceOrdViaDistance", "0"); // 中途距离
        params.put("ServiceOrdTraDistance", emergency.getTransferDistance() != null ? emergency.getTransferDistance().toString() : "0");
        params.put("ServiceOrdTraDuration", ""); // 预计行程时间
        params.put("ServiceOrdTraUnitPrice", "0"); // 单价/公里
        params.put("ServiceOrdTraOfferPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0");
//        params.put("ServiceOrdTraOfferPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0");
        params.put("ServiceOrdTraTxnPrice", emergency.getTransferPrice() != null ? emergency.getTransferPrice().toString() : "0");
        params.put("ServiceOrdTraPrePayment", "0"); // 需预付款
        params.put("SettlementPrice", "0"); // 结算价
ruoyi-system/src/main/java/com/ruoyi/system/utils/TaskStatusPushConverter.java
@@ -13,7 +13,29 @@
public class TaskStatusPushConverter {
    
    private static final Logger log = LoggerFactory.getLogger(TaskStatusPushConverter.class);
    /** 服务单状态
     * 1    咨询单
     * 2    未调度
     * 3    已调度
     * 4    取消单
     */
    /**
     * 1    1 - 完全未确认
     * 2    2 - 部分已确认
     * 3    未出车
     * 4    3 - 已出车(去接患者途中)
     * 5    已出车(等待患者)
     * 6    4 - 已出车(服务中)
     * 7    5 - 已送达(回程中)
     * 8    已返回
     * 9    跑空单,已返回
     * 10    取消
     * 0    0 - 新调度单(未下发)
     * 11    已提交,等待审核
     * 12    审核完成
     * 13    审核不通过
     * 14    已驻点
     */
    /**
     * 将新系统TaskStatus转换为旧系统状态码
     * 
@@ -37,8 +59,9 @@
                return 8;
            case CANCELLED:      // 已取消
                return 10;
            case ARRIVED:        // 已到达
                return 6;
            case PENDING:        // 待处理 - 不同步
            case ARRIVED:        // 已到达 - 不同步
            default:
//                log.debug("新系统状态不需要同步到旧系统: {}", taskStatus.getInfo());
                return null;
ruoyi-system/src/main/resources/mapper/system/SysTaskMapper.xml
@@ -344,4 +344,14 @@
            #{taskId}
        </foreach>
    </delete>
    <!-- 根据联系人电话和创建日期查询任务数量 -->
    <select id="countTaskByPhoneAndDate" resultType="int">
        select count(1)
        from sys_task t
        inner join sys_task_emergency e on t.task_id = e.task_id
        where t.del_flag = '0'
          and e.patient_phone = #{phone}
          and DATE(t.create_time) = #{createDate}
    </select>
</mapper>