| New file |
| | |
| | | <template> |
| | | <view class="task-detail-container"> |
| | | <view class="detail-header"> |
| | | <view class="back-btn" @click="goBack"> |
| | | <uni-icons type="arrowleft" size="20"></uni-icons> |
| | | </view> |
| | | <view class="title">任务详情</view> |
| | | </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">{{ displayTaskType }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">任务状态</view> |
| | | <view class="value status" :class="statusClass"> |
| | | {{ displayTaskStatus }} |
| | | </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="detail-section"> |
| | | <view class="section-title">时间信息</view> |
| | | <view class="info-item"> |
| | | <view class="label">计划开始时间</view> |
| | | <view class="value">{{ displayPlannedStartTime }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="label">计划结束时间</view> |
| | | <view class="value">{{ displayPlannedEndTime }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.actualStartTime"> |
| | | <view class="label">实际开始时间</view> |
| | | <view class="value">{{ displayActualStartTime }}</view> |
| | | </view> |
| | | <view class="info-item" v-if="taskDetail.actualEndTime"> |
| | | <view class="label">实际结束时间</view> |
| | | <view class="value">{{ displayActualEndTime }}</view> |
| | | </view> |
| | | </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="detail-section" v-if="taskDetail.taskDescription"> |
| | | <view class="section-title">任务描述</view> |
| | | <view class="description">{{ taskDetail.taskDescription }}</view> |
| | | </view> |
| | | |
| | | <view class="detail-section" v-if="taskDetail.remark"> |
| | | <view class="section-title">备注信息</view> |
| | | <view class="description">{{ taskDetail.remark }}</view> |
| | | </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="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="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="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="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="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="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> |
| | | |
| | | <!-- 出发中状态: 显示已到达、强制结束 --> |
| | | <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> |
| | | |
| | | <!-- 已到达状态: 显示已返程 --> |
| | | <template v-else-if="taskDetail.taskStatus === 'ARRIVED'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('return')" |
| | | > |
| | | 已返程 |
| | | </button> |
| | | </template> |
| | | |
| | | <!-- 返程中状态: 显示已完成 --> |
| | | <template v-else-if="taskDetail.taskStatus === 'RETURNING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction('complete')" |
| | | > |
| | | 已完成 |
| | | </button> |
| | | </template> |
| | | |
| | | <!-- 已完成/已取消: 不显示按钮 --> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getTask, changeTaskStatus } from '@/api/task' |
| | | import { formatDateTime } from '@/utils/common' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | taskDetail: null, |
| | | taskId: null |
| | | } |
| | | }, |
| | | computed: { |
| | | // 显示任务类型 |
| | | displayTaskType() { |
| | | if (!this.taskDetail || !this.taskDetail.taskType) { |
| | | return '未设置' |
| | | } |
| | | return this.getTaskTypeText(this.taskDetail.taskType) |
| | | }, |
| | | // 显示任务状态 |
| | | displayTaskStatus() { |
| | | if (!this.taskDetail || !this.taskDetail.taskStatus) { |
| | | return '未设置' |
| | | } |
| | | return this.getStatusText(this.taskDetail.taskStatus) |
| | | }, |
| | | // 状态样式类 |
| | | statusClass() { |
| | | if (!this.taskDetail || !this.taskDetail.taskStatus) { |
| | | return '' |
| | | } |
| | | const status = this.taskDetail.taskStatus |
| | | if (status === 'PENDING') return 'pending' |
| | | if (['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(status)) return 'in_progress' |
| | | if (status === 'COMPLETED') return 'completed' |
| | | if (status === 'CANCELLED') return 'cancelled' |
| | | return '' |
| | | }, |
| | | // 显示计划开始时间 |
| | | displayPlannedStartTime() { |
| | | if (!this.taskDetail || !this.taskDetail.plannedStartTime) { |
| | | return '未设置' |
| | | } |
| | | return formatDateTime(this.taskDetail.plannedStartTime, 'YYYY-MM-DD HH:mm') |
| | | }, |
| | | // 显示计划结束时间 |
| | | displayPlannedEndTime() { |
| | | if (!this.taskDetail || !this.taskDetail.plannedEndTime) { |
| | | return '未设置' |
| | | } |
| | | return formatDateTime(this.taskDetail.plannedEndTime, 'YYYY-MM-DD HH:mm') |
| | | }, |
| | | // 显示实际开始时间 |
| | | displayActualStartTime() { |
| | | if (!this.taskDetail || !this.taskDetail.actualStartTime) { |
| | | return '未设置' |
| | | } |
| | | return formatDateTime(this.taskDetail.actualStartTime, 'YYYY-MM-DD HH:mm') |
| | | }, |
| | | // 显示实际结束时间 |
| | | displayActualEndTime() { |
| | | if (!this.taskDetail || !this.taskDetail.actualEndTime) { |
| | | return '未设置' |
| | | } |
| | | return formatDateTime(this.taskDetail.actualEndTime, 'YYYY-MM-DD HH:mm') |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | this.taskId = options.id |
| | | this.loadTaskDetail() |
| | | }, |
| | | methods: { |
| | | // 加载任务详情 |
| | | loadTaskDetail() { |
| | | if (!this.taskId) { |
| | | this.$modal.showToast('任务ID不能为空') |
| | | return |
| | | } |
| | | |
| | | getTask(this.taskId).then(response => { |
| | | this.taskDetail = response.data || response |
| | | // 调试:打印返回的数据 |
| | | console.log('任务详情完整数据:', JSON.stringify(this.taskDetail, null, 2)) |
| | | console.log('任务类型字段值:', this.taskDetail.taskType) |
| | | console.log('任务状态字段值:', this.taskDetail.taskStatus) |
| | | 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() |
| | | }, |
| | | |
| | | // 获取状态文本 |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | 'PENDING': '待处理', |
| | | 'DEPARTING': '出发中', |
| | | 'ARRIVED': '已到达', |
| | | 'RETURNING': '返程中', |
| | | 'COMPLETED': '已完成', |
| | | 'CANCELLED': '已取消', |
| | | 'IN_PROGRESS': '处理中' // 兼容旧数据 |
| | | } |
| | | return statusMap[status] || '未知' |
| | | }, |
| | | |
| | | // 获取任务类型文本 |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | 'MAINTENANCE': '维修保养', |
| | | 'FUEL': '加油', |
| | | 'OTHER': '其他', |
| | | 'EMERGENCY_TRANSFER': '转运任务', |
| | | 'WELFARE': '福祉车' |
| | | } |
| | | return typeMap[type] || '未知类型' |
| | | }, |
| | | |
| | | // 处理任务操作 |
| | | handleTaskAction(action) { |
| | | switch (action) { |
| | | case 'depart': |
| | | // 出发 -> 状态变为出发中 |
| | | 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.updateTaskStatus('ARRIVED', '已到达目的地') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'forceCancel': |
| | | // 强制结束 -> 状态变为已取消 |
| | | this.$modal.confirm('确定要强制结束此任务吗?').then(() => { |
| | | this.updateTaskStatus('CANCELLED', '任务已强制结束') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'return': |
| | | // 已返程 -> 状态变为返程中 |
| | | this.$modal.confirm('确认开始返程?').then(() => { |
| | | this.updateTaskStatus('RETURNING', '已开始返程') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'complete': |
| | | // 已完成 -> 状态变为已完成 |
| | | this.$modal.confirm('确认任务已完成?').then(() => { |
| | | this.updateTaskStatus('COMPLETED', '任务已完成') |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | // 更新任务状态 |
| | | 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(() => { |
| | | // 用户取消操作 |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .task-detail-container { |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | |
| | | .detail-header { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20rpx; |
| | | background-color: white; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .back-btn { |
| | | width: 60rpx; |
| | | height: 60rpx; |
| | | border-radius: 50%; |
| | | background-color: #f0f0f0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .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; |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |