wlzboy
2025-10-18 b46065a201c09ce69f111806f2bda4a5f476bc4e
app/pages/task/index.vue
@@ -110,18 +110,21 @@
        <view class="task-list">
          <view class="task-item" v-for="task in filteredTaskList" :key="task.id">
            <view class="task-main" @click="viewTaskDetail(task)">
              <view class="task-title">{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view>
              <view class="task-info">
                <view class="info-row">
                  <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">{{ getStatusText(task.status) }}</view>
                  </view>
              <!-- 任务头部:标题和状态标签 -->
              <view class="task-header">
                <view class="task-title">{{ getTaskTypeText(task.taskType) }} - {{ task.vehicle }}</view>
                <view class="task-status" :class="getStatusClass(task.taskStatus)">
                  {{ getStatusText(task.taskStatus) }}
                </view>
              </view>
              <!-- 任务编号单独一行 -->
              <view class="task-code-row">
                <text class="task-code">{{ task.taskCode }}</text>
              </view>
              <!-- 任务详细信息 -->
              <view class="task-info">
                <view class="info-row">
                  <view class="info-item">
                    <view class="label">出发地:</view>
@@ -147,46 +150,59 @@
            
            <!-- 操作按钮 -->
            <view class="task-actions">
              <button
                class="action-btn"
                :class="{ disabled: isActionDisabled(task, 'depart') }"
                @click="handleTaskAction(task, 'depart')"
                v-if="task.status !== 'completed'"
              >
                出发
              </button>
              <button
                class="action-btn"
                :class="{ disabled: isActionDisabled(task, 'arrive') }"
                @click="handleTaskAction(task, 'arrive')"
                v-if="task.status !== 'completed'"
              >
                已到达
              </button>
              <button
                class="action-btn"
                :class="{ disabled: isActionDisabled(task, 'return') }"
                @click="handleTaskAction(task, 'return')"
                v-if="task.status !== 'completed'"
              >
                返程
              </button>
              <button
                class="action-btn"
                :class="{ disabled: isActionDisabled(task, 'settle') }"
                @click="handleTaskAction(task, 'settle')"
                v-if="task.status !== 'completed'"
              >
                结算
              </button>
              <button
                class="action-btn primary"
                :class="{ disabled: isActionDisabled(task, 'complete') }"
                @click="handleTaskAction(task, 'complete')"
                v-if="task.status !== 'completed'"
              >
                已完成
              </button>
              <!-- 待处理状态: 显示出发、取消 -->
              <template v-if="task.taskStatus === 'PENDING'">
                <button
                  class="action-btn primary"
                  @click="handleTaskAction(task, 'depart')"
                >
                  出发
                </button>
                <button
                  class="action-btn cancel"
                  @click="handleTaskAction(task, 'cancel')"
                >
                  取消
                </button>
              </template>
              <!-- 出发中状态: 显示已到达、强制结束 -->
              <template v-else-if="task.taskStatus === 'DEPARTING'">
                <button
                  class="action-btn primary"
                  @click="handleTaskAction(task, 'arrive')"
                >
                  已到达
                </button>
                <button
                  class="action-btn cancel"
                  @click="handleTaskAction(task, 'forceCancel')"
                >
                  强制结束
                </button>
              </template>
              <!-- 已到达状态: 显示已返程 -->
              <template v-else-if="task.taskStatus === 'ARRIVED'">
                <button
                  class="action-btn primary"
                  @click="handleTaskAction(task, 'return')"
                >
                  已返程
                </button>
              </template>
              <!-- 返程中状态: 显示已完成 -->
              <template v-else-if="task.taskStatus === 'RETURNING'">
                <button
                  class="action-btn primary"
                  @click="handleTaskAction(task, 'complete')"
                >
                  已完成
                </button>
              </template>
              <!-- 已完成/已取消: 不显示按钮 -->
            </view>
          </view>
          
@@ -202,6 +218,8 @@
<script>
  import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue'
  import { listTask, changeTaskStatus } from '@/api/task'
  import { mapState } from 'vuex'
  
  export default {
    components: {
@@ -226,119 +244,65 @@
        currentFilter: 'all',
        
        // 任务列表
        taskList: [
          {
            id: 1,
            title: '紧急维修任务',
            type: 'maintenance', // 维修保养
            startLocation: '广州市天河区XX路123号',
            endLocation: '广州市白云区YY路456号',
            startTime: '2023-05-15 15:00',
            assignee: '张三',
            status: 'pending',
            vehicle: '粤A12345',
            taskNo: 'RW20230515001'
          },
          {
            id: 2,
            title: '定期保养任务',
            type: 'maintenance', // 维修保养
            startLocation: '深圳市南山区XX路789号',
            endLocation: '深圳市福田区YY路999号',
            startTime: '2023-05-14 10:00',
            assignee: '李四',
            status: 'processing',
            vehicle: '粤B67890',
            taskNo: 'RW20230514002'
          },
          {
            id: 3,
            title: '设备巡检任务',
            type: 'inspection', // 巡检任务
            startLocation: '珠海市香洲区XX路321号',
            endLocation: '珠海市金湾区YY路654号',
            startTime: '2023-05-13 17:00',
            assignee: '王五',
            status: 'completed',
            vehicle: '粤C11111',
            taskNo: 'RW20230513003'
          },
          {
            id: 4,
            title: '加油任务',
            type: 'refuel', // 加油
            startLocation: '佛山市禅城区AA路555号',
            endLocation: '佛山市南海区BB路888号',
            startTime: '2023-05-12 09:00',
            assignee: '赵六',
            status: 'completed',
            vehicle: '粤D22222',
            taskNo: 'RW20230512004'
          },
          {
            id: 5,
            title: '急救转运任务',
            type: 'emergency', // 急救转运
            startLocation: '广州市越秀区医院路1号',
            endLocation: '广州市海珠区医院路2号',
            startTime: '2023-05-16 14:00',
            assignee: '张医生,李护士',
            status: 'pending',
            vehicle: '粤E33333',
            taskNo: 'RW20230516005'
          },
          {
            id: 6,
            title: '福祉车任务',
            type: 'welfare', // 福祉车
            startLocation: '广州市荔湾区社区路10号',
            endLocation: '广州市天河区养老院路20号',
            startTime: '2023-05-17 08:00',
            assignee: '王司机',
            status: 'processing',
            vehicle: '粤F44444',
            taskNo: 'RW20230517006'
          }
        ]
        taskList: [],
        loading: false,
        refreshing: false
      }
    },
    computed: {
      ...mapState({
        currentUser: state => state.user
      }),
      filteredTaskList() {
        let filtered = this.taskList;
        
        // 应用筛选器
        if (this.currentFilter !== 'all') {
          filtered = filtered.filter(task => {
            if (this.currentFilter === 'pending') return task.status === 'pending';
            if (this.currentFilter === 'processing') return task.status === 'processing';
            if (this.currentFilter === 'completed') return task.status === 'completed';
            if (this.currentFilter === 'pending') return task.taskStatus === 'PENDING';
            if (this.currentFilter === 'processing') return ['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(task.taskStatus);
            if (this.currentFilter === 'completed') return task.taskStatus === 'COMPLETED';
            return true;
          });
        }
        
        // 应用状态筛选
        if (this.selectedStatus) {
          filtered = filtered.filter(task => task.status === this.selectedStatus);
          const statusMap = {
            'pending': ['PENDING'],
            'processing': ['DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'],
            'completed': ['COMPLETED']
          }
          const validStatuses = statusMap[this.selectedStatus];
          if (validStatuses) {
            filtered = filtered.filter(task => validStatuses.includes(task.taskStatus));
          }
        }
        
        // 应用车牌号筛选
        // 应用车牌号筛选 - 搜索assignedVehicles数组中的车辆
        if (this.searchForm.vehicle) {
          filtered = filtered.filter(task =>
            task.vehicle.includes(this.searchForm.vehicle)
          );
          filtered = filtered.filter(task => {
            // 在车辆列表中查找匹配的车牌号
            if (task.vehicleList && task.vehicleList.length > 0) {
              return task.vehicleList.some(vehicle =>
                vehicle.vehicleNo && vehicle.vehicleNo.includes(this.searchForm.vehicle)
              )
            }
            return false
          });
        }
        
        // 应用任务编号筛选
        // 应用任务编号筛选 - 使用taskCode而不是taskNo
        if (this.searchForm.taskNo) {
          filtered = filtered.filter(task => 
            task.taskNo.includes(this.searchForm.taskNo)
            task.taskCode && task.taskCode.includes(this.searchForm.taskNo)
          );
        }
        
        // 应用时间范围筛选
        if (this.startDate) {
          filtered = filtered.filter(task => 
            task.startTime >= this.startDate
            task.plannedStartTime && task.plannedStartTime >= this.startDate
          );
        }
        
@@ -349,14 +313,87 @@
          const endDateStr = end.toISOString().split('T')[0];
          
          filtered = filtered.filter(task => 
            task.startTime < endDateStr
            task.plannedStartTime && task.plannedStartTime < endDateStr
          );
        }
        
        return filtered;
      }
    },
    onLoad() {
      this.loadTaskList()
    },
    onPullDownRefresh() {
      this.refreshList()
    },
    methods: {
      // 加载任务列表
      loadTaskList() {
        this.loading = true
        // 后端会自动获取当前用户信息,实现综合查询
        // 综合查询:当前用户所在机构任务 + 当前用户创建的任务 + 分配给当前用户的任务
        const queryParams = {
          pageNum: 1,
          pageSize: 100
        }
        listTask(queryParams).then(response => {
          this.loading = false
          const data = response.data || response.rows || []
          this.taskList = data.map(task => {
            // 从assignedVehicles数组中获取车辆信息
            let vehicleInfo = '未分配车辆'
            if (task.assignedVehicles && task.assignedVehicles.length > 0) {
              // 如果有多个车辆,显示第一个,并标注数量
              const firstVehicle = task.assignedVehicles[0]
              vehicleInfo = firstVehicle.vehicleNo || '未知车牌'
              if (task.assignedVehicles.length > 1) {
                vehicleInfo += ` 等${task.assignedVehicles.length}辆`
              }
            }
            return {
              ...task,
              // 格式化显示字段 - 使用后端返回的assignedVehicles数据
              vehicle: vehicleInfo,
              vehicleList: task.assignedVehicles || [],
              startLocation: this.formatAddress(task.departureAddress || task.startLocation || '未设置'),
              endLocation: this.formatAddress(task.destinationAddress || task.endLocation || '未设置'),
              startTime: task.plannedStartTime ? this.formatDateTime(task.plannedStartTime) : '未设置',
              assignee: task.assigneeName || '未分配'
            }
          })
        }).catch(error => {
          this.loading = false
          console.error('加载任务列表失败:', error)
          this.$modal.showToast('加载任务列表失败')
        })
      },
      // 格式化日期时间
      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'
        })
      },
      // 格式化地址 - 只显示-前面的部分
      formatAddress(address) {
        if (!address) return '未设置'
        // 如果地址包含-,只返回-前面的部分
        const dashIndex = address.indexOf('-')
        if (dashIndex > 0) {
          return address.substring(0, dashIndex)
        }
        return address
      },
      // 切换查询界面显示/隐藏
      toggleSearch() {
        this.showSearch = !this.showSearch;
@@ -370,17 +407,10 @@
      
      // 查询
      handleSearch() {
        this.loadTaskList()
        this.$modal.showToast('查询成功');
        console.log('查询条件:', {
          status: this.selectedStatus,
          startDate: this.startDate,
          endDate: this.endDate,
          vehicle: this.searchForm.vehicle,
          taskNo: this.searchForm.taskNo
        });
        // 查询完成后隐藏查询界面
        this.showSearch = false;
        // 这里可以调用API进行查询
      },
      
      // 重置查询条件
@@ -395,8 +425,14 @@
      
      // 刷新列表
      refreshList() {
        this.$modal.showToast('列表已刷新');
        // 这里可以重新加载数据
        this.refreshing = true
        this.loadTaskList()
        setTimeout(() => {
          this.refreshing = false
          this.$modal.showToast('列表已刷新');
          // 停止下拉刷新
          uni.stopPullDownRefresh()
        }, 1000)
      },
      
      // 筛选
@@ -406,93 +442,153 @@
      
      // 查看任务详情
      viewTaskDetail(task) {
        // 跳转到任务详情页面
        this.$tab.navigateTo(`/pages/task/detail?id=${task.id}`);
      },
      // 判断操作按钮是否禁用
      isActionDisabled(task, action) {
        // 根据任务状态和操作类型判断是否禁用
        switch (action) {
          case 'depart':
            return task.status !== 'pending';
          case 'arrive':
            return task.status !== 'processing';
          case 'return':
            return task.status !== 'processing';
          case 'settle':
            return task.status !== 'processing';
          case 'complete':
            return task.status !== 'processing';
          default:
            return false;
        }
        // 跳转到任务详情页面 - 修复:使用taskId而不是id
        this.$tab.navigateTo(`/pages/task/detail?id=${task.taskId}`);
      },
      
      // 处理任务操作
      handleTaskAction(task, action) {
        if (this.isActionDisabled(task, action)) {
          return;
        }
        switch (action) {
          case 'depart':
            // 出发操作,根据任务类型显示不同的确认信息
            let departMessage = '确定要标记为已出发吗?';
            if (task.type !== 'maintenance' && task.type !== 'refuel' && task.type !== 'inspection') {
              departMessage = '发出去目的地,确认?';
            }
            this.$modal.confirm(departMessage).then(() => {
              task.status = 'processing';
              this.$modal.showToast('已出发');
              // 这里可以调用API更新任务状态
            // 出发 -> 状态变为出发中
            this.$modal.confirm('确定要出发吗?').then(() => {
              this.updateTaskStatus(task.taskId, 'DEPARTING', '任务已出发')
            }).catch(() => {});
            break;
          case 'cancel':
            // 取消 -> 二次确认后状态变为已取消
            this.$modal.confirm('确定要取消此任务吗?').then(() => {
              this.updateTaskStatus(task.taskId, 'CANCELLED', '任务已取消')
            }).catch(() => {});
            break;
          case 'arrive':
            // 已到达操作
            this.$modal.confirm('已经到达目的地,确认?').then(() => {
              this.$modal.showToast('已到达');
              // 这里可以调用API更新任务状态
            // 已到达 -> 状态变为已到达
            this.$modal.confirm('确认已到达目的地?').then(() => {
              this.updateTaskStatus(task.taskId, 'ARRIVED', '已到达目的地')
            }).catch(() => {});
            break;
          case 'forceCancel':
            // 强制结束 -> 状态变为已取消
            this.$modal.confirm('确定要强制结束此任务吗?').then(() => {
              this.updateTaskStatus(task.taskId, 'CANCELLED', '任务已强制结束')
            }).catch(() => {});
            break;
          case 'return':
            // 返程操作
            this.$modal.confirm('现在已经返程中,确认?').then(() => {
              this.$modal.showToast('返程中');
              // 这里可以调用API更新任务状态
            // 已返程 -> 状态变为返程中
            this.$modal.confirm('确认开始返程?').then(() => {
              this.updateTaskStatus(task.taskId, 'RETURNING', '已开始返程')
            }).catch(() => {});
            break;
          case 'settle':
            // 结算操作,跳转到结算页面
            this.$tab.navigateTo(`/pages/task/settlement?id=${task.id}`);
            break;
          case 'complete':
            // 已完成操作
            this.$modal.confirm('任务是否已经全部完成,确认?').then(() => {
              task.status = 'completed';
              this.$modal.showToast('任务已完成');
              // 这里可以调用API更新任务状态
            // 已完成 -> 状态变为已完成
            this.$modal.confirm('确认任务已完成?').then(() => {
              this.updateTaskStatus(task.taskId, 'COMPLETED', '任务已完成')
            }).catch(() => {});
            break;
        }
      },
      // 更新任务状态
      updateTaskStatus(taskId, status, remark) {
        // 获取GPS位置信息
        this.getLocationAndUpdateStatus(taskId, status, remark)
      },
      // 获取位置信息并更新状态
      getLocationAndUpdateStatus(taskId, status, remark) {
        const that = this
        // 使用uni.getLocation获取GPS位置
        uni.getLocation({
          type: 'gcj02',
          geocode: true,
          altitude: true,
          success: function(res) {
            console.log('GPS定位成功:', res)
            const statusData = {
              taskStatus: status,
              remark: remark,
              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(taskId, statusData).then(response => {
              that.$modal.showToast('状态更新成功')
              that.loadTaskList()
            }).catch(error => {
              console.error('更新任务状态失败:', error)
              that.$modal.showToast('状态更新失败,请重试')
            })
          },
          fail: function(err) {
            console.error('GPS定位失败:', err)
            that.$modal.confirm('GPS定位失败,是否继续更新状态?').then(() => {
              const statusData = {
                taskStatus: status,
                remark: remark
              }
              changeTaskStatus(taskId, statusData).then(response => {
                that.$modal.showToast('状态更新成功')
                that.loadTaskList()
              }).catch(error => {
                console.error('更新任务状态失败:', error)
                that.$modal.showToast('状态更新失败,请重试')
              })
            }).catch(() => {})
          }
        })
      },
      
      getStatusText(status) {
        const statusMap = {
          'pending': '待处理',
          'processing': '处理中',
          'completed': '已完成'
          'PENDING': '待处理',
          'DEPARTING': '出发中',
          'ARRIVED': '已到达',
          'RETURNING': '返程中',
          'COMPLETED': '已完成',
          'CANCELLED': '已取消',
          'IN_PROGRESS': '处理中' // 兼容旧数据
        }
        return statusMap[status] || '未知'
      },
      
      // 获取状态样式类
      getStatusClass(status) {
        const statusClassMap = {
          'PENDING': 'status-pending',
          'DEPARTING': 'status-departing',
          'ARRIVED': 'status-arrived',
          'RETURNING': 'status-returning',
          'COMPLETED': 'status-completed',
          'CANCELLED': 'status-cancelled',
          'IN_PROGRESS': 'status-in-progress'
        }
        return statusClassMap[status] || 'status-default'
      },
      getTaskTypeText(type) {
        const typeMap = {
          'maintenance': '维修保养',
          'refuel': '加油',
          'inspection': '巡检',
          'emergency': '急救转运',
          'welfare': '福祉车'
          'MAINTENANCE': '维修保养',
          'FUEL': '加油',
          'OTHER': '其他',
          'EMERGENCY_TRANSFER': '急救转运',
          'WELFARE': '福祉车'
        }
        return typeMap[type] || '未知类型'
      }
@@ -715,10 +811,90 @@
        padding: 30rpx;
        border-bottom: 1rpx solid #f0f0f0;
        
        .task-title {
          font-size: 32rpx;
          font-weight: bold;
          margin-bottom: 20rpx;
        // 任务头部:标题和状态
        .task-header {
          display: flex;
          justify-content: space-between;
          align-items: flex-start;
          margin-bottom: 15rpx;
          .task-title {
            flex: 1;
            font-size: 32rpx;
            font-weight: bold;
            padding-right: 20rpx;
            line-height: 1.4;
          }
          .task-status {
            padding: 8rpx 20rpx;
            border-radius: 30rpx;
            font-size: 24rpx;
            white-space: nowrap;
            flex-shrink: 0;
            // 待处理 - 橙色
            &.status-pending {
              background-color: #fff3e0;
              color: #ff9500;
            }
            // 出发中 - 蓝色
            &.status-departing {
              background-color: #e3f2fd;
              color: #007AFF;
            }
            // 已到达 - 紫色
            &.status-arrived {
              background-color: #f3e5f5;
              color: #9c27b0;
            }
            // 返程中 - 青色
            &.status-returning {
              background-color: #e0f2f1;
              color: #009688;
            }
            // 已完成 - 绿色
            &.status-completed {
              background-color: #e8f5e9;
              color: #34C759;
            }
            // 已取消 - 灰色
            &.status-cancelled {
              background-color: #f5f5f5;
              color: #999;
            }
            // 处理中 (兼容旧数据) - 蓝色
            &.status-in-progress {
              background-color: #e3f2fd;
              color: #007AFF;
            }
            // 默认样式
            &.status-default {
              background-color: #f5f5f5;
              color: #666;
            }
          }
        }
        // 任务编号单独一行
        .task-code-row {
          margin-bottom: 15rpx;
          padding: 10rpx 0;
          border-bottom: 1rpx dashed #e0e0e0;
          .task-code {
            font-size: 28rpx;
            color: #333;
            font-weight: 500;
            font-family: monospace;
          }
        }
        
        .task-info {
@@ -769,6 +945,11 @@
            color: white;
          }
          
          &.cancel {
            background-color: #ff3b30;
            color: white;
          }
          &.disabled {
            opacity: 0.5;
          }