| | |
| | | <template> |
| | | <view class="task-detail-container"> |
| | | <view class="task-header"> |
| | | <text class="task-title">{{ task.title }}</text> |
| | | <view class="task-status" :class="'status-' + task.status"> |
| | | {{ getStatusText(task.status) }} |
| | | <view class="detail-header"> |
| | | <view class="back-btn" @click="goBack"> |
| | | <uni-icons type="arrowleft" size="20"></uni-icons> |
| | | </view> |
| | | <view class="title">任务详情</view> |
| | | </view> |
| | | |
| | | <!-- 普通任务详情 --> |
| | | <view class="task-info-section" v-if="isNormalTask"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | <scroll-view class="detail-content" scroll-y="true" v-if="taskDetail"> |
| | | <view class="detail-section"> |
| | | <view class="section-title">基本信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号</view> |
| | | <view class="value">{{ taskDetail.taskCode }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">任务类型</view> |
| | | <view class="value">{{ getTaskTypeText(taskDetail.taskType) }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">任务状态</view> |
| | | <view class="value status" :class="taskDetail.taskStatus === 'PENDING' ? 'pending' : taskDetail.taskStatus === 'DEPARTING' ? 'in_progress' : taskDetail.taskStatus === 'ARRIVED' ? 'in_progress' : taskDetail.taskStatus === 'RETURNING' ? 'in_progress' : taskDetail.taskStatus === 'IN_PROGRESS' ? 'in_progress' : taskDetail.taskStatus === 'COMPLETED' ? 'completed' : taskDetail.taskStatus === 'CANCELLED' ? 'cancelled' : ''"> |
| | | {{ getStatusText(taskDetail.taskStatus) }} |
| | | </view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">执行车辆</view> |
| | | <view class="value">{{ getVehicleInfo(taskDetail) }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">执行人员</view> |
| | | <view class="value">{{ taskDetail.assigneeName || '未分配' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | <view class="detail-section"> |
| | | <view class="section-title">时间信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">计划开始时间</view> |
| | | <view class="value">{{ formatDateTime(taskDetail.plannedStartTime) }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">计划结束时间</view> |
| | | <view class="value">{{ formatDateTime(taskDetail.plannedEndTime) }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.actualStartTime"> |
| | | <view class="label">实际开始时间</view> |
| | | <view class="value">{{ formatDateTime(taskDetail.actualStartTime) }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.actualEndTime"> |
| | | <view class="label">实际结束时间</view> |
| | | <view class="value">{{ formatDateTime(taskDetail.actualEndTime) }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | <view class="detail-section"> |
| | | <view class="section-title">位置信息</view> |
| | | <!-- 急救转运任务:显示转出/转入医院地址 --> |
| | | <template v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo"> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutAddress"> |
| | | <view class="label">转出医院</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalOutAddress }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInAddress"> |
| | | <view class="label">转入医院</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalInAddress }}</view> |
| | | </view> |
| | | </template> |
| | | <!-- 福祉车任务:显示接送/目的地址 --> |
| | | <template v-else-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo"> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.pickupAddress"> |
| | | <view class="label">接送地址</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.pickupAddress }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.destinationAddress"> |
| | | <view class="label">目的地址</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.destinationAddress }}</view> |
| | | </view> |
| | | </template> |
| | | <!-- 其他任务类型:显示通用地址 --> |
| | | <template v-else> |
| | | <view class="info-item"> |
| | | <view class="label">出发地</view> |
| | | <view class="value">{{ getDepartureAddress(taskDetail) }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">目的地</view> |
| | | <view class="value">{{ getDestinationAddress(taskDetail) }}</view> |
| | | </view> |
| | | </template> |
| | | <!-- 距离信息:根据任务类型显示不同字段 --> |
| | | <view class="info-item" v-if="getDistanceInfo(taskDetail)"> |
| | | <view class="label">距离</view> |
| | | <view class="value">{{ getDistanceInfo(taskDetail) }}公里</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发地:</view> |
| | | <view class="value">{{ task.startLocation }}</view> |
| | | <view class="detail-section" v-if="taskDetail.taskDescription"> |
| | | <view class="section-title">任务描述</view> |
| | | <view class="description">{{ taskDetail.taskDescription }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">目的地:</view> |
| | | <view class="value">{{ task.endLocation }}</view> |
| | | <view class="detail-section" v-if="taskDetail.remark"> |
| | | <view class="section-title">备注信息</view> |
| | | <view class="description">{{ taskDetail.remark }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发时间:</view> |
| | | <view class="value">{{ task.startTime }}</view> |
| | | <!-- 急救转运任务特有信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo"> |
| | | <view class="section-title">患者信息</view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientName"> |
| | | <view class="label">患者姓名</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientName }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientPhone"> |
| | | <view class="label">联系电话</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientPhone }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientGender"> |
| | | <view class="label">性别</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientGender === 'male' ? '男' : '女' }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientAge"> |
| | | <view class="label">年龄</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientAge }}岁</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientIdCard"> |
| | | <view class="label">身份证号</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientIdCard }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.patientCondition"> |
| | | <view class="label">病情描述</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.patientCondition }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | <!-- 急救转运 - 转出医院信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo"> |
| | | <view class="section-title">转出医院信息</view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutName"> |
| | | <view class="label">医院名称</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalOutName }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutDepartment"> |
| | | <view class="label">科室</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalOutDepartment }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutBedNumber"> |
| | | <view class="label">床号</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalOutBedNumber }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalOutAddress"> |
| | | <view class="label">医院地址</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalOutAddress }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务描述:</view> |
| | | <view class="value">{{ task.description || '无描述信息' }}</view> |
| | | <!-- 急救转运 - 转入医院信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo"> |
| | | <view class="section-title">转入医院信息</view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInName"> |
| | | <view class="label">医院名称</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalInName }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInDepartment"> |
| | | <view class="label">科室</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalInDepartment }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInBedNumber"> |
| | | <view class="label">床号</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalInBedNumber }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.hospitalInAddress"> |
| | | <view class="label">医院地址</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.hospitalInAddress }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">行驶公里数:</view> |
| | | <view class="value">{{ task.distance || '未填写' }}</view> |
| | | <!-- 急救转运 - 费用信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'EMERGENCY_TRANSFER' && taskDetail.emergencyInfo"> |
| | | <view class="section-title">费用信息</view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.transferDistance"> |
| | | <view class="label">转运公里数</view> |
| | | <view class="value">{{ taskDetail.emergencyInfo.transferDistance }}公里</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.emergencyInfo.transferPrice"> |
| | | <view class="label">转运费用</view> |
| | | <view class="value">¥{{ taskDetail.emergencyInfo.transferPrice }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">结束时间:</view> |
| | | <view class="value">{{ task.endTime || '未填写' }}</view> |
| | | <!-- 福祉车任务特有信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo"> |
| | | <view class="section-title">乘客信息</view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerContact"> |
| | | <view class="label">联系人</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerContact }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerPhone"> |
| | | <view class="label">联系电话</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerPhone }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerName"> |
| | | <view class="label">乘客姓名</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerName }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerAge"> |
| | | <view class="label">年龄</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerAge }}岁</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerGender"> |
| | | <view class="label">性别</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerGender === 'male' ? '男' : '女' }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.passengerIdCard"> |
| | | <view class="label">身份证号</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.passengerIdCard }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.specialNeeds"> |
| | | <view class="label">特殊需求</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.specialNeeds }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">备注:</view> |
| | | <view class="value">{{ task.remark || '无备注' }}</view> |
| | | <!-- 福祉车 - 服务信息 --> |
| | | <view class="detail-section" v-if="taskDetail.taskType === 'WELFARE' && taskDetail.welfareInfo"> |
| | | <view class="section-title">服务信息</view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.serviceType"> |
| | | <view class="label">服务类型</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.serviceType }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.pickupAddress"> |
| | | <view class="label">接送地址</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.pickupAddress }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.destinationAddress"> |
| | | <view class="label">目的地址</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.destinationAddress }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.serviceDistance"> |
| | | <view class="label">服务公里数</view> |
| | | <view class="value">{{ taskDetail.welfareInfo.serviceDistance }}公里</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.welfareInfo.servicePrice"> |
| | | <view class="label">服务费用</view> |
| | | <view class="value">¥{{ taskDetail.welfareInfo.servicePrice }}</view> |
| | | </view> |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <view class="loading" v-else> |
| | | <uni-icons type="spinner-cycle" size="40" color="#007AFF"></uni-icons> |
| | | <text>加载中...</text> |
| | | </view> |
| | | |
| | | <!-- 急救转运任务详情 --> |
| | | <view class="task-info-section" v-else-if="task.type === 'emergency'"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | <!-- 操作按钮区域 --> |
| | | <view class="action-buttons" v-if="taskDetail"> |
| | | <!-- 待处理状态: 显示出发、取消 --> |
| | | <template v-if="taskDetail.taskStatus === 'PENDING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('depart')" |
| | | > |
| | | 出发 |
| | | </button> |
| | | <button |
| | | class="action-btn cancel" |
| | | @click="handleTaskAction('cancel')" |
| | | > |
| | | 取消 |
| | | </button> |
| | | </template> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | <!-- 出发中状态: 显示已到达、强制结束 --> |
| | | <template v-else-if="taskDetail.taskStatus === 'DEPARTING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('arrive')" |
| | | > |
| | | 已到达 |
| | | </button> |
| | | <button |
| | | class="action-btn cancel" |
| | | @click="handleTaskAction('forceCancel')" |
| | | > |
| | | 强制结束 |
| | | </button> |
| | | </template> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | <!-- 已到达状态: 显示已返程 --> |
| | | <template v-else-if="taskDetail.taskStatus === 'ARRIVED'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('return')" |
| | | > |
| | | 已返程 |
| | | </button> |
| | | </template> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | <!-- 返程中状态: 显示已完成 --> |
| | | <template v-else-if="taskDetail.taskStatus === 'RETURNING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('complete')" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </template> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">归属机构:</view> |
| | | <view class="value">{{ task.organization || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ task.emergencyTaskType || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">转运时间:</view> |
| | | <view class="value">{{ task.transferTime || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">患者信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">联系人:</view> |
| | | <view class="value">{{ task.patient.contact || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">联系电话:</view> |
| | | <view class="value">{{ task.patient.phone || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">患者姓名:</view> |
| | | <view class="value">{{ task.patient.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">性别:</view> |
| | | <view class="value">{{ task.patient.gender === 'male' ? '男' : '女' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">身份证:</view> |
| | | <view class="value">{{ task.patient.idCard || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">病情:</view> |
| | | <view class="value">{{ task.patient.condition || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">转出医院信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">医院名称:</view> |
| | | <view class="value">{{ task.hospitalOut.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">科室:</view> |
| | | <view class="value">{{ task.hospitalOut.department || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">床号:</view> |
| | | <view class="value">{{ task.hospitalOut.bedNumber || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">地址:</view> |
| | | <view class="value">{{ task.hospitalOut.address || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">转入医院信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">医院名称:</view> |
| | | <view class="value">{{ task.hospitalIn.name || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">科室:</view> |
| | | <view class="value">{{ task.hospitalIn.department || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">床号:</view> |
| | | <view class="value">{{ task.hospitalIn.bedNumber || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">地址:</view> |
| | | <view class="value">{{ task.hospitalIn.address || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">转运公里数:</view> |
| | | <view class="value">{{ task.transferDistance || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">成交价:</view> |
| | | <view class="value">¥{{ task.price || '未填写' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 福祉车任务详情 --> |
| | | <view class="task-info-section" v-else-if="task.type === 'welfare'"> |
| | | <view class="info-item"> |
| | | <view class="label">任务编号:</view> |
| | | <view class="value">{{ task.taskNo }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">任务类型:</view> |
| | | <view class="value">{{ getTaskTypeText(task.type) }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">车辆信息:</view> |
| | | <view class="value">{{ task.vehicle }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">执行人员:</view> |
| | | <view class="value">{{ task.assignee }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">归属机构:</view> |
| | | <view class="value">{{ task.organization || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">服务时间:</view> |
| | | <view class="value">{{ task.serviceTime || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="section-title">乘客信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">联系人:</view> |
| | | <view class="value">{{ task.passenger.contact || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">联系电话:</view> |
| | | <view class="value">{{ task.passenger.phone || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">出发地址:</view> |
| | | <view class="value">{{ task.startAddress || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">目的地址:</view> |
| | | <view class="value">{{ task.endAddress || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">公里数:</view> |
| | | <view class="value">{{ task.distance || '未填写' }}</view> |
| | | </view> |
| | | |
| | | <view class="info-item"> |
| | | <view class="label">成交价:</view> |
| | | <view class="value">¥{{ task.price || '未填写' }}</view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 任务操作按钮 (任务未完成时显示) --> |
| | | <view class="task-actions" v-if="task.status !== 'completed'"> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('depart') }" |
| | | @click="handleTaskAction('depart')" |
| | | > |
| | | 出发 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('arrive') }" |
| | | @click="handleTaskAction('arrive')" |
| | | > |
| | | 已到达 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('return') }" |
| | | @click="handleTaskAction('return')" |
| | | > |
| | | 返程 |
| | | </button> |
| | | <button |
| | | class="action-btn" |
| | | :class="{ disabled: isActionDisabled('settle') }" |
| | | @click="handleTaskAction('settle')" |
| | | > |
| | | 结算 |
| | | </button> |
| | | <button |
| | | class="action-btn primary" |
| | | :class="{ disabled: isActionDisabled('complete') }" |
| | | @click="handleTaskAction('complete')" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </view> |
| | | |
| | | <view class="action-section"> |
| | | <button class="back-btn" @click="goBack">返回</button> |
| | | <!-- 已完成/已取消: 不显示按钮 --> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getTask, changeTaskStatus } from '@/api/task' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | task: { |
| | | id: 1, |
| | | title: '紧急维修任务', |
| | | type: 'maintenance', |
| | | startLocation: '广州市天河区XX路123号', |
| | | endLocation: '广州市白云区YY路456号', |
| | | startTime: '2023-05-15 15:00', |
| | | assignee: '张三', |
| | | status: 'pending', |
| | | vehicle: '粤A12345', |
| | | taskNo: 'RW20230515001', |
| | | description: '设备故障,需要紧急维修', |
| | | // 普通任务字段 |
| | | distance: '25', |
| | | endTime: '2023-05-15 17:00', |
| | | remark: '维修完成后需要测试', |
| | | // 急救转运任务字段 |
| | | organization: '广州急救中心', |
| | | emergencyTaskType: '急救转运', |
| | | transferTime: '2023-05-15 16:00', |
| | | patient: { |
| | | contact: '李四', |
| | | phone: '13800138000', |
| | | name: '王五', |
| | | gender: 'male', |
| | | idCard: '440100198001011234', |
| | | condition: '突发心脏病' |
| | | }, |
| | | hospitalOut: { |
| | | name: '广州市第一人民医院', |
| | | department: '心内科', |
| | | bedNumber: '101', |
| | | address: '广州市越秀区医院路1号' |
| | | }, |
| | | hospitalIn: { |
| | | name: '广东省人民医院', |
| | | department: '心内科', |
| | | bedNumber: '205', |
| | | address: '广州市天河区医院路2号' |
| | | }, |
| | | transferDistance: '15', |
| | | price: '800', |
| | | // 福祉车任务字段 |
| | | serviceTime: '2023-05-16 09:00', |
| | | passenger: { |
| | | contact: '赵六', |
| | | phone: '13900139000' |
| | | }, |
| | | startAddress: '广州市荔湾区社区路10号', |
| | | endAddress: '广州市天河区养老院路20号' |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | // 判断是否为普通任务 |
| | | isNormalTask() { |
| | | return this.task.type === 'maintenance' || this.task.type === 'refuel' || this.task.type === 'inspection'; |
| | | taskDetail: null, |
| | | taskId: null |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 实际项目中这里会通过API获取任务详情 |
| | | // const taskId = options.id; |
| | | // this.getTaskDetail(taskId); |
| | | this.taskId = options.id |
| | | this.loadTaskDetail() |
| | | }, |
| | | methods: { |
| | | goBack() { |
| | | this.$tab.navigateBack(); |
| | | // 加载任务详情 |
| | | loadTaskDetail() { |
| | | if (!this.taskId) { |
| | | this.$modal.showToast('任务ID不能为空') |
| | | return |
| | | } |
| | | |
| | | getTask(this.taskId).then(response => { |
| | | this.taskDetail = response.data || response |
| | | // 调试:打印返回的数据 |
| | | console.log('任务详情数据:', this.taskDetail) |
| | | console.log('出发地址:', this.taskDetail.departureAddress) |
| | | console.log('目的地址:', this.taskDetail.destinationAddress) |
| | | }).catch(error => { |
| | | console.error('加载任务详情失败:', error) |
| | | this.$modal.showToast('加载任务详情失败') |
| | | }) |
| | | }, |
| | | |
| | | // 获取车辆信息 |
| | | getVehicleInfo(task) { |
| | | if (task.assignedVehicles && task.assignedVehicles.length > 0) { |
| | | const firstVehicle = task.assignedVehicles[0] |
| | | let vehicleInfo = firstVehicle.vehicleNo || '未知车牌' |
| | | if (task.assignedVehicles.length > 1) { |
| | | vehicleInfo += ` 等${task.assignedVehicles.length}辆` |
| | | } |
| | | return vehicleInfo |
| | | } |
| | | return '未分配车辆' |
| | | }, |
| | | |
| | | // 获取出发地址 |
| | | getDepartureAddress(task) { |
| | | // 优先使用departureAddress,如果为空则尝试其他可能的字段 |
| | | return task.departureAddress || task.startAddress || task.startLocation || '未设置' |
| | | }, |
| | | |
| | | // 获取目的地址 |
| | | getDestinationAddress(task) { |
| | | // 优先使用destinationAddress,如果为空则尝试其他可能的字段 |
| | | return task.destinationAddress || task.endAddress || task.endLocation || '未设置' |
| | | }, |
| | | |
| | | // 获取距离信息:根据任务类型返回不同字段 |
| | | getDistanceInfo(task) { |
| | | // 急救转运:优先使用transferDistance |
| | | if (task.taskType === 'EMERGENCY_TRANSFER' && task.emergencyInfo && task.emergencyInfo.transferDistance) { |
| | | return task.emergencyInfo.transferDistance |
| | | } |
| | | // 福祉车:优先使用serviceDistance |
| | | if (task.taskType === 'WELFARE' && task.welfareInfo && task.welfareInfo.serviceDistance) { |
| | | return task.welfareInfo.serviceDistance |
| | | } |
| | | // 其他任务类型:使用estimatedDistance |
| | | return task.estimatedDistance || null |
| | | }, |
| | | |
| | | // 返回上一页 |
| | | goBack() { |
| | | uni.navigateBack() |
| | | }, |
| | | |
| | | // 格式化日期时间 |
| | | formatDateTime(dateTime) { |
| | | if (!dateTime) return '未设置' |
| | | const date = new Date(dateTime) |
| | | return date.toLocaleString('zh-CN', { |
| | | year: 'numeric', |
| | | month: '2-digit', |
| | | day: '2-digit', |
| | | hour: '2-digit', |
| | | minute: '2-digit' |
| | | }) |
| | | }, |
| | | |
| | | // 获取状态文本 |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | 'pending': '待处理', |
| | | 'processing': '处理中', |
| | | 'completed': '已完成' |
| | | 'PENDING': '待处理', |
| | | 'DEPARTING': '出发中', |
| | | 'ARRIVED': '已到达', |
| | | 'RETURNING': '返程中', |
| | | 'COMPLETED': '已完成', |
| | | 'CANCELLED': '已取消', |
| | | 'IN_PROGRESS': '处理中' // 兼容旧数据 |
| | | } |
| | | return statusMap[status] || '未知' |
| | | }, |
| | | |
| | | // 获取任务类型文本 |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'maintenance': '维修保养', |
| | | 'refuel': '加油', |
| | | 'inspection': '巡检', |
| | | 'emergency': '急救转运', |
| | | 'welfare': '福祉车' |
| | | 'MAINTENANCE': '维修保养', |
| | | 'FUEL': '加油', |
| | | 'OTHER': '其他', |
| | | 'EMERGENCY_TRANSFER': '急救转运', |
| | | 'WELFARE': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | }, |
| | | |
| | | // 判断操作按钮是否禁用 |
| | | isActionDisabled(action) { |
| | | // 根据任务状态和操作类型判断是否禁用 |
| | | switch (action) { |
| | | case 'depart': |
| | | return this.task.status !== 'pending'; |
| | | case 'arrive': |
| | | return this.task.status !== 'processing'; |
| | | case 'return': |
| | | return this.task.status !== 'processing'; |
| | | case 'settle': |
| | | return this.task.status !== 'processing'; |
| | | case 'complete': |
| | | return this.task.status !== 'processing'; |
| | | default: |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 处理任务操作 |
| | | handleTaskAction(action) { |
| | | if (this.isActionDisabled(action)) { |
| | | return; |
| | | } |
| | | |
| | | switch (action) { |
| | | case 'depart': |
| | | // 出发操作,根据任务类型显示不同的确认信息 |
| | | let departMessage = '确定要标记为已出发吗?'; |
| | | if (this.task.type !== 'maintenance' && this.task.type !== 'refuel' && this.task.type !== 'inspection') { |
| | | departMessage = '发出去目的地,确认?'; |
| | | } |
| | | this.$modal.confirm(departMessage).then(() => { |
| | | this.task.status = 'processing'; |
| | | this.$modal.showToast('已出发'); |
| | | // 这里可以调用API更新任务状态 |
| | | // 出发 -> 状态变为出发中 |
| | | this.$modal.confirm('确定要出发吗?').then(() => { |
| | | this.updateTaskStatus('DEPARTING', '任务已出发') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'cancel': |
| | | // 取消 -> 二次确认后状态变为已取消 |
| | | this.$modal.confirm('确定要取消此任务吗?').then(() => { |
| | | this.updateTaskStatus('CANCELLED', '任务已取消') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'arrive': |
| | | // 已到达操作 |
| | | this.$modal.confirm('已经到达目的地,确认?').then(() => { |
| | | this.$modal.showToast('已到达'); |
| | | // 这里可以调用API更新任务状态 |
| | | // 已到达 -> 状态变为已到达 |
| | | this.$modal.confirm('确认已到达目的地?').then(() => { |
| | | this.updateTaskStatus('ARRIVED', '已到达目的地') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'forceCancel': |
| | | // 强制结束 -> 状态变为已取消 |
| | | this.$modal.confirm('确定要强制结束此任务吗?').then(() => { |
| | | this.updateTaskStatus('CANCELLED', '任务已强制结束') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'return': |
| | | // 返程操作 |
| | | this.$modal.confirm('现在已经返程中,确认?').then(() => { |
| | | this.$modal.showToast('返程中'); |
| | | // 这里可以调用API更新任务状态 |
| | | // 已返程 -> 状态变为返程中 |
| | | this.$modal.confirm('确认开始返程?').then(() => { |
| | | this.updateTaskStatus('RETURNING', '已开始返程') |
| | | }).catch(() => {}); |
| | | break; |
| | | case 'settle': |
| | | // 结算操作,跳转到结算页面 |
| | | this.$tab.navigateTo(`/pages/task/settlement?id=${this.task.id}`); |
| | | break; |
| | | |
| | | case 'complete': |
| | | // 已完成操作 |
| | | this.$modal.confirm('任务是否已经全部完成,确认?').then(() => { |
| | | this.task.status = 'completed'; |
| | | this.$modal.showToast('任务已完成'); |
| | | // 这里可以调用API更新任务状态 |
| | | // 已完成 -> 状态变为已完成 |
| | | this.$modal.confirm('确认任务已完成?').then(() => { |
| | | this.updateTaskStatus('COMPLETED', '任务已完成') |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | // 模拟获取任务详情 |
| | | getTaskDetail(taskId) { |
| | | // 这里应该调用API获取任务详情 |
| | | // 暂时使用模拟数据 |
| | | // 更新任务状态 |
| | | updateTaskStatus(status, remark) { |
| | | // 获取GPS位置信息 |
| | | this.getLocationAndUpdateStatus(status, remark) |
| | | }, |
| | | |
| | | // 获取位置信息并更新状态 |
| | | getLocationAndUpdateStatus(status, remark) { |
| | | const that = this |
| | | |
| | | // 使用uni.getLocation获取GPS位置 |
| | | uni.getLocation({ |
| | | type: 'gcj02', // 返回可以用于uni.openLocation的坐标 |
| | | geocode: true, // 解析地址信息 |
| | | altitude: true, // 高精度定位,包含高度信息 |
| | | success: function(res) { |
| | | console.log('GPS定位成功:', res) |
| | | |
| | | const statusData = { |
| | | taskStatus: status, |
| | | remark: remark, |
| | | // GPS位置信息 |
| | | latitude: res.latitude, |
| | | longitude: res.longitude, |
| | | locationAddress: res.address ? res.address.street || res.address.poiName || '' : '', |
| | | locationProvince: res.address ? res.address.province || '' : '', |
| | | locationCity: res.address ? res.address.city || '' : '', |
| | | locationDistrict: res.address ? res.address.district || '' : '', |
| | | gpsAccuracy: res.accuracy, |
| | | altitude: res.altitude, |
| | | speed: res.speed, |
| | | heading: res.direction || res.heading |
| | | } |
| | | |
| | | changeTaskStatus(that.taskId, statusData).then(response => { |
| | | that.$modal.showToast('状态更新成功') |
| | | // 重新加载任务详情 |
| | | that.loadTaskDetail() |
| | | }).catch(error => { |
| | | console.error('更新任务状态失败:', error) |
| | | that.$modal.showToast('状态更新失败,请重试') |
| | | }) |
| | | }, |
| | | fail: function(err) { |
| | | console.error('GPS定位失败:', err) |
| | | |
| | | // 定位失败时提示用户,但仍然允许更新状态(不带GPS信息) |
| | | that.$modal.confirm('GPS定位失败,是否继续更新状态?').then(() => { |
| | | const statusData = { |
| | | taskStatus: status, |
| | | remark: remark |
| | | } |
| | | |
| | | changeTaskStatus(that.taskId, statusData).then(response => { |
| | | that.$modal.showToast('状态更新成功') |
| | | that.loadTaskDetail() |
| | | }).catch(error => { |
| | | console.error('更新任务状态失败:', error) |
| | | that.$modal.showToast('状态更新失败,请重试') |
| | | }) |
| | | }).catch(() => { |
| | | // 用户取消操作 |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | <style lang="scss"> |
| | | .task-detail-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .task-header { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .task-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .task-status { |
| | | padding: 10rpx 20rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 24rpx; |
| | | font-weight: bold; |
| | | |
| | | &.status-pending { |
| | | background-color: #fff3cd; |
| | | color: #856404; |
| | | } |
| | | |
| | | &.status-processing { |
| | | background-color: #cce5ff; |
| | | color: #004085; |
| | | } |
| | | |
| | | &.status-completed { |
| | | background-color: #d4edda; |
| | | color: #155724; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin: 30rpx 0 20rpx 0; |
| | | padding-bottom: 10rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-item { |
| | | .detail-header { |
| | | display: flex; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 20rpx; |
| | | align-items: center; |
| | | padding: 20rpx; |
| | | background-color: white; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | padding-bottom: 0; |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .label { |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | .back-btn { |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | border-radius: 50%; |
| | | background-color: #f0f0f0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 20rpx; |
| | | white-space: nowrap; |
| | | width: 150rpx; |
| | | } |
| | | |
| | | .value { |
| | | .title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | .detail-content { |
| | | padding: 20rpx; |
| | | height: calc(100vh - 220rpx); // 减去header(100rpx)和按钮区域(120rpx)的高度 |
| | | padding-bottom: 20rpx; // 底部留出空间 |
| | | } |
| | | |
| | | .detail-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | margin-bottom: 20rpx; |
| | | color: #333; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | padding-bottom: 10rpx; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | margin-bottom: 20rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .label { |
| | | width: 200rpx; |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .value { |
| | | flex: 1; |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | word-break: break-all; |
| | | |
| | | &.status { |
| | | &.pending { |
| | | color: #ff9500; |
| | | } |
| | | &.in_progress { |
| | | color: #007AFF; |
| | | } |
| | | &.completed { |
| | | color: #34C759; |
| | | } |
| | | &.cancelled { |
| | | color: #ff3b30; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .description { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | line-height: 1.6; |
| | | background-color: #f9f9f9; |
| | | padding: 20rpx; |
| | | border-radius: 10rpx; |
| | | } |
| | | } |
| | | |
| | | .loading { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 400rpx; |
| | | color: #999; |
| | | |
| | | text { |
| | | margin-top: 20rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | display: flex; |
| | | padding: 20rpx; |
| | | background-color: white; |
| | | box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | word-break: break-all; |
| | | height: 80rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 30rpx; |
| | | margin: 0 10rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.cancel { |
| | | background-color: #ff3b30; |
| | | color: white; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | min-width: 30%; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 10rpx 5rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .action-section { |
| | | margin-top: 40rpx; |
| | | text-align: center; |
| | | |
| | | .back-btn { |
| | | width: 80%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | </style> |