wlzboy
2026-03-24 6676a35122fd9c97d1b1679c211bc8a9b97f08f2
app/pages/index.vue
@@ -89,42 +89,55 @@
    </view>
    <!-- 正在运行的任务列表 -->
    <scroll-view class="running-tasks-section" scroll-y="true">
    <scroll-view
      class="running-tasks-section"
      scroll-y="true"
      @scrolltolower="onScrollToLower"
    >
      <view class="task-list">
        <view class="task-item" v-for="task in runningTasks" :key="task.id">
          <view class="task-main" @click="viewTaskDetail(task)">
            <!-- 任务头部:标题和状态标签 -->
            <view class="task-header">
              <view class="task-title"
                >{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view
              >
              <view class="task-title">
                {{ getTaskTypeText(task.type) }} - {{ task.vehicle }}
                <text v-if="task.emergencyInfo && task.emergencyInfo.serviceOrdVip === '1'" class="vip-tag">VIP</text>
                <text v-if="task.emergencyInfo && task.emergencyInfo.fromHq2Is === '1'" class="hq-tag">广总</text>
              </view>
              <view
                class="task-status"
                :class="
                  task.taskStatus === 'PENDING'
                  task.taskStatus === TaskStatus.PENDING
                    ? 'status-pending'
                    : task.taskStatus === 'DEPARTING'
                    : task.taskStatus === TaskStatus.NOT_CONFIRMED
                    ? 'status-not-confirmed'
                    : task.taskStatus === TaskStatus.NOT_DEPARTED
                    ? 'status-not-departed'
                    : task.taskStatus === TaskStatus.PARTIALLY_CONFIRMED
                    ? 'status-partially-confirmed'
                    : task.taskStatus === TaskStatus.DEPARTING
                    ? 'status-departing'
                    : task.taskStatus === 'ARRIVED'
                    : task.taskStatus === TaskStatus.ARRIVED
                    ? 'status-arrived'
                    : task.taskStatus === 'RETURNING'
                    : task.taskStatus === TaskStatus.RETURNING
                    ? 'status-returning'
                    : task.taskStatus === 'COMPLETED'
                    : task.taskStatus === TaskStatus.COMPLETED
                    ? 'status-completed'
                    : task.taskStatus === 'CANCELLED'
                    : task.taskStatus === TaskStatus.CANCELLED
                    ? 'status-cancelled'
                    : task.taskStatus === 'IN_PROGRESS'
                    : task.taskStatus === TaskStatus.IN_PROGRESS
                    ? 'status-in-progress'
                    : 'status-default'
                    : 'status-pending'
                "
              >
                {{ getStatusText(task.status) }}
                {{ getStatusText(task.taskStatus) }}
              </view>
            </view>
            <!-- 任务编号单独一行 -->
            <!-- 任务编号和开始时间在同一行显示,但分开一些 -->
            <view class="task-code-row">
              <text class="task-code">{{ task.showTaskCode }}</text>
              <text class="task-time">{{ task.startTime }}</text>
            </view>
            <!-- 任务详细信息 -->
@@ -132,21 +145,21 @@
              <view class="info-row">
                <view class="info-item">
                  <view class="label">出发地:</view>
                  <view class="value">{{ task.startLocation }}</view>
                  <view class="value">{{ getStartLocationDisplay(task) }}</view>
                </view>
                <view class="info-item">
                  <view class="label">目的地:</view>
                  <view class="value">{{ task.endLocation }}</view>
                </view>
              </view>
              <view class="info-row">
                <view class="info-item">
                  <view class="label">出发时间:</view>
                  <view class="value">{{ task.startTime }}</view>
                  <view class="label">目的地:</view>
                  <view class="value">{{ getEndLocationDisplay(task) }}</view>
                </view>
              </view>
              <view class="info-row">
                <view class="info-item">
                  <view class="label">执行人员:</view>
                  <view class="value">{{ task.assignee }}</view>
                  <view class="value">{{ getAssigneesDisplay(task) }}</view>
                </view>
              </view>
            </view>
@@ -154,8 +167,8 @@
          <!-- 操作按钮 -->
          <view class="task-actions">
            <!-- 待处理状态: 显示出发、取消 -->
            <template v-if="task.taskStatus === 'PENDING'">
            <!-- 待处理状态:显示出发、取消 -->
            <template v-if="task.taskStatus === TaskStatus.PENDING || task.taskStatus === TaskStatus.NOT_DEPARTED || task.taskStatus === TaskStatus.NOT_CONFIRMED || task.taskStatus === TaskStatus.PARTIALLY_CONFIRMED">
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'depart')"
@@ -170,8 +183,8 @@
              </button>
            </template>
            <!-- 出发中状态: 显示已到达、强制结束 -->
            <template v-else-if="task.taskStatus === 'DEPARTING'">
            <!-- 出发中状态:显示已到达、强制结束 -->
            <template v-else-if="task.taskStatus === TaskStatus.DEPARTING">
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'arrive')"
@@ -186,8 +199,8 @@
              </button>
            </template>
            <!-- 已到达状态: 显示已返程 -->
            <template v-else-if="task.taskStatus === 'ARRIVED'">
            <!-- 已到达状态:显示已返程 -->
            <template v-else-if="task.taskStatus === TaskStatus.ARRIVED">
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'return')"
@@ -196,8 +209,8 @@
              </button>
            </template>
            <!-- 返程中状态: 显示已完成 -->
            <template v-else-if="task.taskStatus === 'RETURNING'">
            <!-- 返程中状态:显示已完成 -->
            <template v-else-if="task.taskStatus === TaskStatus.RETURNING">
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'complete')"
@@ -214,23 +227,84 @@
          <uni-icons type="info" size="40" color="#ccc"></uni-icons>
          <text>暂无正在运行的任务</text>
        </view>
        <!-- 加载更多提示 -->
        <view class="load-more" v-if="runningTasks.length > 0 && hasMore && loading">
          <uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons>
          <text>正在加载更多数据...</text>
        </view>
        <view class="load-more no-more" v-else-if="runningTasks.length > 0 && !hasMore">
          <text>没有更多数据了</text>
        </view>
      </view>
    </scroll-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 { mapState } from "vuex";
import { getMyTasks, changeTaskStatus } from "@/api/task";
import { getMyTasks, changeTaskStatus, checkTaskConsentAttachment } from "@/api/task";
import { getUserProfile } from "@/api/system/user";
import { getUserBoundVehicle } from "@/api/vehicle";
import { getUnreadCount } from "@/api/message";
import { getDicts } from "@/api/dict";
import { formatDateTime } from "@/utils/common";
import subscribeManager from "@/utils/subscribe";
import { checkTaskCanDepart } from "@/utils/taskValidator";
import { getStatusText as getTaskStatusText, TaskStatus } from "@/utils/TaskUtil";
// 任务类型映射(临时定义,避免导入问题)
const TASK_TYPE_MAP = {
  MAINTENANCE: "维修保养",
  FUEL: "加油",
  OTHER: "其他",
  EMERGENCY_TRANSFER: "转运任务",
  WELFARE: "福祉车",
  maintenance: "维修保养",
  refuel: "加油",
  inspection: "巡检",
  emergency: "转运任务",
  welfare: "福祉车"
};
// 任务状态映射(临时定义,避免导入问题)
const TASK_STATUS_MAP = {
  PENDING: "待处理",
  NOT_CONFIRMED: "完全未确认",
  NOT_DEPARTED: "待出发",
  PARTIALLY_CONFIRMED: "部分确认",
  DEPARTING: "出发中",
  ARRIVED: "已到达",
  RETURNING: "返程中",
  COMPLETED: "已完成",
  CANCELLED: "已取消",
  IN_PROGRESS: "任务中"
};
export default {
  data() {
    return {
      TaskStatus, // 暴露 TaskStatus 给模板使用
      // 用户绑定的车辆信息
      boundVehicle: "",
      boundVehicleId: null,
@@ -240,11 +314,23 @@
      unreadMessageCount: 0,
      // 正在运行的任务列表
      taskList: [],
      allTaskList: [], // 存储所有任务数据
      displayedTaskList: [], // 存储当前显示的任务数据
      loading: false,
      // 订阅状态
      hasSubscribed: false,
      // 前端分页相关
      currentPage: 1,
      pageSize: 10,
      hasMore: true,
      // 取消原因相关
      cancelReasonList: [], // 取消原因列表
      showCancelDialog: false, // 显示取消原因对话框
      selectedCancelReason: '', // 选中的取消原因
      currentCancelTask: null // 当前要取消的任务
    };
  },
  computed: {
@@ -255,16 +341,29 @@
    // 正在运行的任务(待处理和各种处理中的任务)
    runningTasks() {
      return this.taskList.filter((task) => {
      return this.displayedTaskList.filter((task) => {
        // 包含待处理、出发中、已到达、返程中等所有未完成的状态
        return [
          "PENDING",
          "DEPARTING",
          "ARRIVED",
          "RETURNING",
          "IN_PROGRESS",
        ].includes(task.taskStatus);
        const activeStatuses = [
          TaskStatus.NOT_CONFIRMED,
          TaskStatus.NOT_DEPARTED,
          TaskStatus.PARTIALLY_CONFIRMED,
          TaskStatus.PENDING,
          TaskStatus.DEPARTING,
          TaskStatus.ARRIVED,
          TaskStatus.RETURNING,
          TaskStatus.IN_PROGRESS,
        ];
        return activeStatuses.includes(task.taskStatus);
      });
    },
    // 获取选中的取消原因标签(用于弹窗显示)
    selectedCancelReasonLabel() {
      if (!this.selectedCancelReason || !this.cancelReasonList.length) {
        return '请选择'
      }
      const reason = this.cancelReasonList.find(r => r.value === this.selectedCancelReason)
      return reason ? reason.label : '请选择'
    },
  },
  onLoad() {
@@ -276,10 +375,10 @@
    }
    // 检查订阅状态(先检查本地,后面会检查微信官方状态)
    this.hasSubscribed = subscribeManager.checkLocalSubscribeStatus();
    this.hasSubscribed = true;//subscribeManager.checkLocalSubscribeStatus();
    // 自动订阅(如果未订阅则显示确认弹窗)
    this.autoSubscribeOnLaunch();
    // this.autoSubscribeOnLaunch();
    // 加载用户绑定车辆信息
    this.loadUserVehicle();
@@ -287,6 +386,8 @@
    this.loadRunningTasks();
    // 加载未读消息数量
    this.loadUnreadMessageCount();
    // 加载取消原因字典
    this.loadCancelReasonDict();
  },
  onShow() {
    // 检查用户是否已登录
@@ -298,10 +399,16 @@
    // 每次显示页面时刷新任务列表、绑定车辆和消息数量
    this.loadUserVehicle();
    // 重新加载任务列表时重置分页
    this.currentPage = 1;
    this.hasMore = true;
    this.loadRunningTasks();
    this.loadUnreadMessageCount();
  },
  onPullDownRefresh() {
    // 下拉刷新时重置分页参数
    this.currentPage = 1;
    this.hasMore = true;
    // 下拉刷新
    this.loadRunningTasks();
    setTimeout(() => {
@@ -309,6 +416,13 @@
    }, 1000);
  },
  methods: {
    // 滚动到底部时加载更多
    onScrollToLower() {
      if (this.hasMore && !this.loading) {
        this.loadMoreTasks();
      }
    },
    // 自动订阅(小程序启动时调用)
    autoSubscribeOnLaunch() {
      subscribeManager.autoSubscribe()
@@ -437,9 +551,16 @@
          this.loading = false;
          // 根据后端返回的数据结构进行解析
          const data = response.data || response.rows || response || [];
          // 过滤出未完成的任务
          const allTasks = Array.isArray(data) ? data : [];
          this.taskList = allTasks
          // 如果是第一页,直接替换数据;否则追加数据
          if (this.currentPage === 1) {
            this.allTaskList = data;
          } else {
            this.allTaskList = [...this.allTaskList, ...data];
          }
          // 格式化任务数据
          this.allTaskList = this.allTaskList
            .filter((task) => {
              // 只显示未完成和未取消的任务
              return (
@@ -465,25 +586,42 @@
                type: task.taskType,
                vehicle: vehicleInfo,
                vehicleList: task.assignedVehicles || [],
                startLocation: this.formatAddress(
                  task.departureAddress || task.startLocation || "未设置"
                ),
                endLocation: this.formatAddress(
                  task.destinationAddress || task.endLocation || "未设置"
                ),
                startLocation: task.departureAddress || task.startLocation || "未设置",
                endLocation: task.destinationAddress || task.endLocation || "未设置",
                startTime: task.plannedStartTime
                  ? formatDateTime(task.plannedStartTime, "YYYY-MM-DD HH:mm")
                  ? (task.plannedStartTime.startsWith('1900') || task.plannedStartTime.startsWith('1970')
                    ? '未分配时间'
                    : formatDateTime(task.plannedStartTime, "YYYY-MM-DD HH:mm"))
                  : "未设置",
                assignee: task.assigneeName || "未分配",
                taskNo: task.taskCode || "未知编号",
                status: this.convertStatus(task.taskStatus), // 转换状态格式以兼容旧UI
              };
            });
          // 更新显示的任务列表
          this.updateDisplayedTaskList();
        })
        .catch((error) => {
          this.loading = false;
          console.error("加载任务列表失败:", error);
        });
    },
    // 更新显示的任务列表(前端分页)
    updateDisplayedTaskList() {
      const start = 0;
      const end = this.currentPage * this.pageSize;
      this.displayedTaskList = this.allTaskList.slice(start, end);
      this.hasMore = end < this.allTaskList.length;
    },
    // 加载更多任务(前端分页)
    loadMoreTasks() {
      if (!this.hasMore || this.loading) return;
      this.currentPage++;
      this.updateDisplayedTaskList();
    },
    // 格式化地址 - 只显示-前面的部分
@@ -496,10 +634,67 @@
      return address;
    },
    // 获取出发地显示内容(转运任务显示转出医院名称)
    getStartLocationDisplay(task) {
      // 如果是转运任务且有emergencyInfo信息
      if (task.taskType === 'EMERGENCY_TRANSFER' && task.emergencyInfo && task.emergencyInfo.hospitalOutName) {
        return task.emergencyInfo.hospitalOutName;
      }
      // 其他情况使用原来的startLocation
      return this.formatAddress(task.startLocation || "未设置");
    },
    // 获取目的地显示内容(转运任务显示转入医院名称或详细地址)
    getEndLocationDisplay(task) {
      // 如果是转运任务且有emergencyInfo信息
      // console.log("get end location display",task.taskType,task.emergencyInfo.hospitalInAddress,task.showTaskCode);
      if (task.taskType === 'EMERGENCY_TRANSFER' && task.emergencyInfo) {
        // console.log('转运任务 - 紧急信息:', task.emergencyInfo)
        // 优先显示转入医院名称
        // console.log("get end local",task.emergencyInfo.hospitalInAddress);
        return task.emergencyInfo.hospitalInAddress;
        // if (task.emergencyInfo.hospitalInName) {
        //   if(task.emergencyInfo.hospitalInName.includes("家中")){
        //     return task.emergencyInfo.destinationAddress;
        //   }
        //   return task.emergencyInfo.hospitalInName;
        // }
        // // 如果没有转入医院名称,但有转入医院地址,则显示地址
        // if (task.emergencyInfo.hospitalInAddress) {
        //   return task.emergencyInfo.hospitalInAddress;
        // }
      }
      // 其他情况使用原来的endLocation
      return this.formatAddress(task.endLocation || "未设置");
    },
    // 获取执行人员显示(从 assignees 数组中提取 userName)
    getAssigneesDisplay(task) {
      // 如果有 assignees 数组且不为空
      if (task.assignees && task.assignees.length > 0) {
        // 提取所有 userName,过滤掉空值
        const userNames = task.assignees
          .map(assignee => assignee.userName)
          .filter(name => name); // 过滤掉 null/undefined/空字符串
        // 如果有有效的用户名,用逗号连接
        if (userNames.length > 0) {
          return userNames.join('、');
        }
      }
      // 如果没有 assignees 数组,使用旧的 assigneeName 或 assignee 字段
      return task.assigneeName || task.assignee || '未分配';
    },
    // 转换状态格式(将数据库状态转换为UI使用的状态)
    convertStatus(dbStatus) {
      const statusMap = {
        PENDING: "pending",
        NOT_CONFIRMED: "pending",
        NOT_DEPARTED: "pending",
        PARTIALLY_CONFIRMED: "pending",
        DEPARTING: "processing",
        ARRIVED: "processing",
        RETURNING: "processing",
@@ -527,26 +722,102 @@
    },
    // 处理任务操作
    handleTaskAction(task, action) {
    async handleTaskAction(task, action) {
      switch (action) {
        case "depart":
          // 出发 -> 状态变为出发中
          this.$modal
            .confirm("确定要出发吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "DEPARTING", "任务已出发");
            })
            .catch(() => {});
          // 显示加载提示
          uni.showLoading({
            title: "检查任务状态...",
          });
          try {
            // 调用工具类检查任务是否可以出发(包含基本校验和冲突检查)
            const checkResult = await checkTaskCanDepart(task);
            uni.hideLoading();
            console.log("出发检查结果:", checkResult);
            console.log("valid:", checkResult.valid);
            console.log("conflicts:", checkResult.conflicts);
            if (!checkResult.valid) {
              // 校验失败,显示提示信息并提供跳转选项
              const conflicts = checkResult.conflicts || [];
              const conflictInfo = conflicts.length > 0 ? conflicts[0] : null;
              console.log("冲突信息:", conflictInfo);
              // 如果有冲突任务信息,提供跳转按钮
              if (conflictInfo && conflictInfo.taskId) {
                console.log(
                  "显示带跳转按钮的弹窗,任务ID:",
                  conflictInfo.taskId
                );
                const conflictTaskId = conflictInfo.taskId;
                const message =
                  checkResult.message || conflictInfo.message || "存在冲突任务";
                uni.showModal({
                  title: "提示",
                  content: message,
                  confirmText: "去处理",
                  cancelText: "知道了",
                  success: function (res) {
                    console.log("弹窗点击结果:", res);
                    if (res.confirm) {
                      // 用户点击"现在去处理",跳转到冲突任务详情页
                      console.log("准备跳转到任务详情页:", conflictTaskId);
                      uni.navigateTo({
                        url: `/pagesTask/detail?id=${conflictTaskId}`,
                      });
                    }
                  },
                  fail: function (err) {
                    console.error("显示弹窗失败:", err);
                  },
                });
              } else {
                // 没有冲突任务ID,只显示提示
                console.log("显示普通提示弹窗");
                uni.showModal({
                  title: "提示",
                  content: checkResult.message || "任务校验失败",
                  showCancel: false,
                  confirmText: "知道了",
                  fail: function (err) {
                    console.error("显示弹窗失败:", err);
                  },
                });
              }
              return;
            }
            // 所有检查通过,可以出发
            this.$modal
              .confirm("确定要出发吗?")
              .then(() => {
                this.updateTaskStatus(task.taskId, TaskStatus.DEPARTING, "任务已出发");
              })
              .catch(() => {});
          } catch (error) {
            uni.hideLoading();
            console.error("检查任务状态失败:", error);
            // 检查失败时,仍然允许出发
            this.$modal
              .confirm("检查任务状态失败,是否继续出发?")
              .then(() => {
                this.updateTaskStatus(task.taskId, TaskStatus.DEPARTING, "任务已出发");
              })
              .catch(() => {});
          }
          break;
        case "cancel":
          // 取消 -> 二次确认后状态变为已取消
          this.$modal
            .confirm("确定要取消此任务吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "CANCELLED", "任务已取消");
            })
            .catch(() => {});
          // 取消 -> 显示取消原因选择对话框
          this.currentCancelTask = task;
          this.showCancelReasonDialog();
          break;
        case "arrive":
@@ -554,7 +825,7 @@
          this.$modal
            .confirm("确认已到达目的地?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "ARRIVED", "已到达目的地");
              this.updateTaskStatus(task.taskId, TaskStatus.ARRIVED, "已到达目的地");
            })
            .catch(() => {});
          break;
@@ -564,7 +835,7 @@
          this.$modal
            .confirm("确定要强制结束此任务吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "CANCELLED", "任务已强制结束");
              this.updateTaskStatus(task.taskId, TaskStatus.CANCELLED, "任务已强制结束");
            })
            .catch(() => {});
          break;
@@ -574,19 +845,15 @@
          this.$modal
            .confirm("确认开始返程?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "RETURNING", "已开始返程");
              this.updateTaskStatus(task.taskId, TaskStatus.RETURNING, "已开始返程");
            })
            .catch(() => {});
          break;
        case "complete":
          // 已完成 -> 状态变为已完成
          this.$modal
            .confirm("确认任务已完成?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "COMPLETED", "任务已完成");
            })
            .catch(() => {});
          // 需要检查是否上传了知情同意书
          this.checkConsentAttachmentAndThen(task.taskId, TaskStatus.COMPLETED, "任务已完成");
          break;
      }
    },
@@ -596,19 +863,114 @@
      // 获取GPS位置信息
      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 {
        uni.showLoading({
          title: '检查附件...'
        });
        // 注意:这里会被请求拦截器处理,code !== 200 时会 reject
        const response = await checkTaskConsentAttachment(taskId).catch(err => {
          // 拦截器 reject 的情况,返回一个默认对象
          console.log('请求被拦截器 reject,err:', err);
          return { code: -1, msg: '未上传知情同意书' };
        });
        uni.hideLoading();
        console.log('检查附件结果:', response);
        if (response && response.code === 200) {
          // 已上传知情同意书,继续更新状态
          console.log('已上传知情同意书,继续完成任务');
          this.$modal
            .confirm("确认任务已完成?")
            .then(() => {
              this.updateTaskStatus(taskId, status, remark);
            })
            .catch(() => {});
        } else {
          // 未上传知情同意书或其他错误,阻止完成
          const message = (response && response.msg) || '任务未上传知情同意书,无法完成任务';
          console.log('未上传知情同意书,阻止完成');
          this.$modal.confirm(message + '。是否现在去上传?').then(() => {
            // 跳转到任务详情页上传附件
            this.$tab.navigateTo(`/pagesTask/detail?id=${taskId}`);
          }).catch(() => {});
        }
      } catch (error) {
        uni.hideLoading();
        console.error('检查附件异常:', error);
        // 如果检查失败(网络异常等),不允许完成任务
        this.$modal.showToast('检查附件状态失败,无法完成任务');
      }
    },
    // 获取位置信息并更新状态
    getLocationAndUpdateStatus(taskId, status, remark) {
    getLocationAndUpdateStatus(taskId, status, remark, cancelReason) {
      const that = this;
      // 使用uni.getLocation获取GPS位置
      // 使用 uni.getLocation 获取 GPS 位置
      uni.getLocation({
        type: "gcj02",
        geocode: true,
        altitude: true,
        success: function (res) {
          console.log("GPS定位成功:", res);
          console.log("GPS 定位成功:", res);
          const statusData = {
            taskStatus: status,
            remark: remark,
@@ -625,6 +987,11 @@
            speed: res.speed,
            heading: res.direction || res.heading,
          };
          // 如果有取消原因,添加到请求数据中
          if (cancelReason) {
            statusData.cancelReason = cancelReason
          }
          changeTaskStatus(taskId, statusData)
            .then((response) => {
@@ -646,6 +1013,11 @@
                taskStatus: status,
                remark: remark,
              };
              // 如果有取消原因,添加到请求数据中
              if (cancelReason) {
                statusData.cancelReason = cancelReason
              }
              changeTaskStatus(taskId, statusData)
                .then((response) => {
@@ -662,55 +1034,14 @@
      });
    },
    // 获取状态样式类
    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";
    },
    getStatusText(status) {
      // 支持新旧两种状态格式
      const statusMap = {
        // 新格式(数据库状态)
        PENDING: "待处理",
        DEPARTING: "出发中",
        ARRIVED: "已到达",
        RETURNING: "返程中",
        COMPLETED: "已完成",
        CANCELLED: "已取消",
        IN_PROGRESS: "处理中",
        // 旧格式(UI状态)
        pending: "待处理",
        processing: "处理中",
        completed: "已完成",
      };
      return statusMap[status] || "未知";
    },
    // 获取任务类型文本
    getTaskTypeText(type) {
      const typeMap = {
        // 新格式(数据库类型)
        MAINTENANCE: "维修保养",
        FUEL: "加油",
        OTHER: "其他",
        EMERGENCY_TRANSFER: "转运任务",
        WELFARE: "福祉车",
        // 旧格式(UI类型)
        maintenance: "维修保养",
        refuel: "加油",
        inspection: "巡检",
        emergency: "转运任务",
        welfare: "福祉车",
      };
      return typeMap[type] || "未知类型";
      return TASK_TYPE_MAP[type] || "未知类型";
    },
    // 获取任务状态文本
    getStatusText(status) {
      return TASK_STATUS_MAP[status] || "未知";
    },
    clickConfirmsubscribeTaskNotify() {
@@ -755,12 +1086,12 @@
    height: 0 !important;
    background: transparent;
  }
  // Firefox滚动条隐藏
  * {
    scrollbar-width: none; /* Firefox */
  }
  // IE/Edge滚动条隐藏
  * {
    -ms-overflow-style: none; /* IE 10+ */
@@ -1000,6 +1331,18 @@
              background-color: #fff3e0;
              color: #ff9500;
            }
            &.status-not-confirmed {
              background-color: #fff3e0;
              color: #ff9500;
            }
            &.status-not-departed {
              background-color: #fff3e0;
              color: #ff9500;
            }
            &.status-partially-confirmed {
              background-color: #fff3e0;
              color: #ff9500;
            }
            // 出发中 - 蓝色
            &.status-departing {
@@ -1045,13 +1388,22 @@
          }
        }
        // 任务编号单独一行
        // 任务编号和时间在同一行显示
        .task-code-row {
          margin-bottom: 15rpx;
          padding: 10rpx 0;
          border-bottom: 1rpx dashed #e0e0e0;
          display: flex;
          justify-content: space-between;
          .task-code {
            font-size: 28rpx;
            color: #333;
            font-weight: 500;
            font-family: monospace;
          }
          .task-time {
            font-size: 28rpx;
            color: #333;
            font-weight: 500;
@@ -1083,6 +1435,10 @@
                font-size: 26rpx;
                flex: 1;
                word-break: break-all;
                overflow-wrap: break-word;
                line-height: 1.5;
                max-height: none;
                overflow: visible;
              }
            }
          }
@@ -1137,6 +1493,104 @@
        margin-top: 20rpx;
      }
    }
    .load-more {
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 20rpx 0;
      color: #999;
      font-size: 28rpx;
      &.no-more {
        color: #666;
      }
    }
    .vip-tag {
      display: inline-block;
      padding: 2rpx 8rpx;
      font-size: 20rpx;
      color: #fff;
      background-color: #ff0000;
      border-radius: 4rpx;
      margin-left: 10rpx;
      vertical-align: middle;
    }
    .hq-tag {
      display: inline-block;
      padding: 2rpx 8rpx;
      font-size: 20rpx;
      color: #fff;
      background-color: #5856d6;
      border-radius: 4rpx;
      margin-left: 10rpx;
      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>