wlzboy
2025-12-25 77b8624957ea9afafc81af72e52212c15b5f091e
app/pages/task/index.vue
@@ -5,12 +5,12 @@
      <view class="task-header">
        <view class="header-title">任务列表</view>
        <view class="header-actions">
          <button class="search-toggle-btn" @click="toggleSearch">
          <!-- <button class="search-toggle-btn" @click="toggleSearch">
            <uni-icons
              :type="showSearch ? 'close' : 'search'"
              size="20"
            ></uni-icons>
          </button>
          </button> -->
          <button class="refresh-btn" @click="refreshList">
            <uni-icons type="refresh" size="20"></uni-icons>
          </button>
@@ -270,12 +270,33 @@
        </view>
      </scroll-view>
    </view>
    <!-- 取消原因选择对话框 -->
    <uni-popup ref="cancelPopup" type="center" :is-mask-click="false">
      <view class="cancel-dialog">
        <view class="dialog-title">请选择取消原因</view>
        <picker mode="selector" :range="cancelReasonList" range-key="label" @change="selectCancelReason">
          <view class="reason-picker">
            <view class="picker-label">取消原因</view>
            <view class="picker-value">
              {{ selectedCancelReasonLabel }}
            </view>
            <uni-icons type="arrowright" size="16"></uni-icons>
          </view>
        </picker>
        <view class="dialog-buttons">
          <button class="cancel-btn" @click="closeCancelDialog">取消</button>
          <button class="confirm-btn" @click="confirmCancelTask">确定</button>
        </view>
      </view>
    </uni-popup>
  </view>
</template>
<script>
import uniDatetimePicker from "@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
import { listTask, changeTaskStatus, checkTaskConsentAttachment } from "@/api/task";
import { getDicts } from "@/api/dict";
import { mapState } from "vuex";
import { formatDateTime } from "@/utils/common";
import { checkTaskCanDepart } from "@/utils/taskValidator";
@@ -294,8 +315,8 @@
        vehicle: "",
        taskNo: "",
      },
      statusOptions: ["全部状态", "待处理", "处理中", "已完成"],
      statusValues: ["", "pending", "processing", "completed"],
      statusOptions: ["全部状态", "待处理", "处理中", "已完成", "已取消"],
      statusValues: ["", "pending", "processing", "completed", "cancelled"],
      selectedStatus: "",
      selectedStatusText: "",
      startDate: "",
@@ -312,6 +333,12 @@
      pageSize: 10,
      total: 0,
      hasMore: true,
      // 取消原因相关
      cancelReasonList: [], // 取消原因列表
      showCancelDialog: false, // 显示取消原因对话框
      selectedCancelReason: '', // 选中的取消原因
      currentCancelTask: null // 当前要取消的任务
    };
  },
  computed: {
@@ -323,12 +350,24 @@
      // 实际的筛选将在请求服务器时完成
      return this.taskList;
    },
    // 获取选中的取消原因标签(用于弹窗显示)
    selectedCancelReasonLabel() {
      if (!this.selectedCancelReason || !this.cancelReasonList.length) {
        return '请选择'
      }
      const reason = this.cancelReasonList.find(r => r.value === this.selectedCancelReason)
      return reason ? reason.label : '请选择'
    },
  },
  onLoad() {
    this.loadTaskList();
    // 监听任务列表刷新事件
    uni.$on("refreshTaskList", this.handleRefreshEvent);
    // 加载取消原因字典
    this.loadCancelReasonDict();
  },
  onShow() {
    // 页面显示时刷新列表(从其他页面返回时)
@@ -382,7 +421,8 @@
          "IN_PROGRESS",
        ].join(",");
      } else if (this.currentFilter === "completed") {
        queryParams.taskStatus = "COMPLETED";
        // 已完成包含:已完成和已取消
        queryParams.taskStatusList = "COMPLETED,CANCELLED";
      } else {
        // 如果没有使用顶部tab筛选,则使用查询条件中的状态筛选
        if (this.selectedStatus) {
@@ -395,11 +435,13 @@
              "IN_PROGRESS",
            ].join(","),
            completed: "COMPLETED",
            cancelled: "CANCELLED",
          };
          if (statusMap[this.selectedStatus]) {
            if (
              this.selectedStatus === "pending" ||
              this.selectedStatus === "completed"
              this.selectedStatus === "completed" ||
              this.selectedStatus === "cancelled"
            ) {
              queryParams.taskStatus = statusMap[this.selectedStatus];
            } else {
@@ -497,7 +539,8 @@
          "IN_PROGRESS",
        ].join(",");
      } else if (this.currentFilter === "completed") {
        queryParams.taskStatus = "COMPLETED";
        // 已完成包含:已完成和已取消
        queryParams.taskStatusList = "COMPLETED,CANCELLED";
      } else {
        // 如果没有使用顶部tab筛选,则使用查询条件中的状态筛选
        if (this.selectedStatus) {
@@ -510,11 +553,13 @@
              "IN_PROGRESS",
            ].join(","),
            completed: "COMPLETED",
            cancelled: "CANCELLED",
          };
          if (statusMap[this.selectedStatus]) {
            if (
              this.selectedStatus === "pending" ||
              this.selectedStatus === "completed"
              this.selectedStatus === "completed" ||
              this.selectedStatus === "cancelled"
            ) {
              queryParams.taskStatus = statusMap[this.selectedStatus];
            } else {
@@ -654,6 +699,8 @@
      this.endDate = "";
      this.searchForm.vehicle = "";
      this.searchForm.taskNo = "";
      // 重置后重新加载数据
      this.loadTaskList();
    },
    // 刷新列表
@@ -671,6 +718,9 @@
    // 筛选
    changeFilter(filter) {
      this.currentFilter = filter;
      // 重置分页
      this.currentPage = 1;
      this.hasMore = true;
      // 重新加载数据
      this.loadTaskList();
    },
@@ -784,13 +834,9 @@
          break;
        case "cancel":
          // 取消 -> 二次确认后状态变为已取消
          this.$modal
            .confirm("确定要取消此任务吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "CANCELLED", "任务已取消");
            })
            .catch(() => {});
          // 取消 -> 显示取消原因选择对话框
          this.currentCancelTask = task;
          this.showCancelReasonDialog();
          break;
        case "arrive":
@@ -837,6 +883,56 @@
      this.getLocationAndUpdateStatus(taskId, status, remark);
    },
    
    // 加载取消原因字典
    loadCancelReasonDict() {
      getDicts('task_cancel_reason').then(response => {
        if (response.code === 200 && response.data) {
          this.cancelReasonList = response.data.map(item => ({
            value: item.dictValue,
            label: item.dictLabel
          }))
        }
      }).catch(error => {
        console.error('加载取消原因字典失败:', error)
      })
    },
    // 显示取消原因对话框
    showCancelReasonDialog() {
      this.selectedCancelReason = ''
      this.$refs.cancelPopup.open()
    },
    // 确认取消任务
    confirmCancelTask() {
      if (!this.selectedCancelReason) {
        this.$modal.showToast('请选择取消原因')
        return
      }
      this.$refs.cancelPopup.close()
      // 调用更新状态方法,传递取消原因
      this.updateTaskStatusWithCancelReason(this.currentCancelTask.taskId, 'CANCELLED', '任务已取消', this.selectedCancelReason)
    },
    // 取消对话框关闭
    closeCancelDialog() {
      this.$refs.cancelPopup.close()
      this.selectedCancelReason = ''
      this.currentCancelTask = null
    },
    // 选择取消原因
    selectCancelReason(e) {
      this.selectedCancelReason = this.cancelReasonList[e.detail.value].value
    },
    // 带取消原因的状态更新
    updateTaskStatusWithCancelReason(taskId, status, remark, cancelReason) {
      this.getLocationAndUpdateStatus(taskId, status, remark, cancelReason)
    },
    // 检查知情同意书附件并更新状态
    async checkConsentAttachmentAndThen(taskId, status, remark) {
      try {
@@ -877,7 +973,7 @@
    },
    // 获取位置信息并更新状态
    getLocationAndUpdateStatus(taskId, status, remark) {
    getLocationAndUpdateStatus(taskId, status, remark, cancelReason) {
      const that = this;
      // 使用uni.getLocation获取GPS位置
@@ -904,6 +1000,11 @@
            speed: res.speed,
            heading: res.direction || res.heading,
          };
          // 如果有取消原因,添加到请求数据中
          if (cancelReason) {
            statusData.cancelReason = cancelReason
          }
          changeTaskStatus(taskId, statusData)
            .then((response) => {
@@ -926,6 +1027,11 @@
                taskStatus: status,
                remark: remark,
              };
              // 如果有取消原因,添加到请求数据中
              if (cancelReason) {
                statusData.cancelReason = cancelReason
              }
              changeTaskStatus(taskId, statusData)
                .then((response) => {
@@ -1410,4 +1516,67 @@
    vertical-align: middle;
  }
}
// 取消原因对话框样式
.cancel-dialog {
  width: 600rpx;
  background-color: white;
  border-radius: 20rpx;
  padding: 40rpx;
  .dialog-title {
    font-size: 32rpx;
    font-weight: bold;
    text-align: center;
    margin-bottom: 30rpx;
    color: #333;
  }
  .reason-picker {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20rpx 30rpx;
    background-color: #f5f5f5;
    border-radius: 10rpx;
    margin-bottom: 30rpx;
    .picker-label {
      font-size: 28rpx;
      color: #666;
    }
    .picker-value {
      flex: 1;
      text-align: right;
      margin: 0 20rpx;
      font-size: 28rpx;
      color: #333;
    }
  }
  .dialog-buttons {
    display: flex;
    gap: 20rpx;
    button {
      flex: 1;
      height: 80rpx;
      line-height: 80rpx;
      border-radius: 10rpx;
      font-size: 28rpx;
      border: none;
    }
    .cancel-btn {
      background-color: #f5f5f5;
      color: #666;
    }
    .confirm-btn {
      background-color: #007AFF;
      color: white;
    }
  }
}
</style>