wlzboy
6 小时以前 5f2ee03958a1a16dc27195c76ea7cffb422c95d1
app/pages/index.vue
@@ -5,25 +5,45 @@
      <view class="user-info-content">
        <view class="user-details">
          <view class="user-info-row">
            <text class="user-name">{{ userName || '未登录' }}</text>
            <text class="separator" v-if="currentUser.branchCompanyName">|</text>
            <text class="user-name">{{ userName || "未登录" }}</text>
            <text class="separator" v-if="currentUser.branchCompanyName"
              >|</text
            >
            <view class="branch-company" v-if="currentUser.branchCompanyName">
              <uni-icons type="location" size="16" color="#666" style="margin-right: 4rpx;"></uni-icons>
              <uni-icons
                type="location"
                size="16"
                color="#666"
                style="margin-right: 4rpx"
              ></uni-icons>
              <text>{{ currentUser.branchCompanyName }}</text>
            </view>
            <text class="separator" v-if="boundVehicle">|</text>
            <view class="vehicle-info" @click.stop="goToBindVehicle" v-if="boundVehicle">
            <view
              class="vehicle-info"
              @click.stop="goToBindVehicle"
              v-if="boundVehicle"
            >
              <text>{{ boundVehicle }}</text>
              <uni-icons
                type="loop"
                size="16"
              <uni-icons
                type="loop"
                size="16"
                color="#007AFF"
                style="margin-left: 4rpx;"
                style="margin-left: 4rpx"
              ></uni-icons>
            </view>
          </view>
          <view class="bind-vehicle-btn" v-if="!boundVehicle" @click="goToBindVehicle">
            <uni-icons type="plus-filled" size="16" color="#007AFF" style="margin-right: 4rpx;"></uni-icons>
          <view
            class="bind-vehicle-btn"
            v-if="!boundVehicle"
            @click="goToBindVehicle"
          >
            <uni-icons
              type="plus-filled"
              size="16"
              color="#007AFF"
              style="margin-right: 4rpx"
            ></uni-icons>
            <text>绑定车牌</text>
          </view>
        </view>
@@ -36,9 +56,30 @@
        <uni-icons type="chat" size="24" color="#007AFF"></uni-icons>
      </view>
      <view class="message-text">消息中心</view>
      <view class="unread-dot" v-if="unreadMessageCount > 0">{{ unreadMessageCount }}</view>
      <view class="unread-dot" v-if="unreadMessageCount > 0">{{
        unreadMessageCount
      }}</view>
      <view class="arrow">
        <uni-icons type="arrowright" size="16" color="#999"></uni-icons>
      </view>
    </view>
    <!-- 订阅通知提示卡片(未订阅时显示) -->
    <view
      class="subscribe-banner"
      v-if="!hasSubscribed"
      @click="clickConfirmsubscribeTaskNotify"
    >
      <view class="banner-icon">
        <uni-icons type="bell" size="28" color="#ff9500"></uni-icons>
      </view>
      <view class="banner-content">
        <view class="banner-title">开启任务通知</view>
        <view class="banner-desc">及时接收任务分配和状态更新提醒</view>
      </view>
      <view class="banner-action">
        <text>立即开启</text>
        <uni-icons type="arrowright" size="16" color="#007AFF"></uni-icons>
      </view>
    </view>
@@ -48,23 +89,49 @@
    </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-status" :class="getStatusClass(task.taskStatus)">
              <view class="task-title">
                {{ getTaskTypeText(task.type) }} - {{ task.vehicle }}
                <text v-if="task.isHeadPush === '1'" class="head-push-tag">总</text>
              </view>
              <view
                class="task-status"
                :class="
                  task.taskStatus === 'PENDING'
                    ? 'status-pending'
                    : task.taskStatus === 'DEPARTING'
                    ? 'status-departing'
                    : task.taskStatus === 'ARRIVED'
                    ? 'status-arrived'
                    : task.taskStatus === 'RETURNING'
                    ? 'status-returning'
                    : task.taskStatus === 'COMPLETED'
                    ? 'status-completed'
                    : task.taskStatus === 'CANCELLED'
                    ? 'status-cancelled'
                    : task.taskStatus === 'IN_PROGRESS'
                    ? 'status-in-progress'
                    : 'status-default'
                "
              >
                {{ getStatusText(task.status) }}
              </view>
            </view>
            <!-- 任务编号单独一行 -->
            <view class="task-code-row">
              <text class="task-code">{{ task.taskNo }}</text>
              <text class="task-code">{{ task.showTaskCode }}</text>
            </view>
            <!-- 任务详细信息 -->
            <view class="task-info">
              <view class="info-row">
@@ -89,68 +156,77 @@
              </view>
            </view>
          </view>
          <!-- 操作按钮 -->
          <view class="task-actions">
            <!-- 待处理状态: 显示出发、取消 -->
            <template v-if="task.taskStatus === 'PENDING'">
              <button
                class="action-btn primary"
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'depart')"
              >
                出发
              </button>
              <button
                class="action-btn cancel"
              <button
                class="action-btn cancel"
                @click="handleTaskAction(task, 'cancel')"
              >
                取消
              </button>
            </template>
            <!-- 出发中状态: 显示已到达、强制结束 -->
            <template v-else-if="task.taskStatus === 'DEPARTING'">
              <button
                class="action-btn primary"
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'arrive')"
              >
                已到达
              </button>
              <button
                class="action-btn cancel"
              <button
                class="action-btn cancel"
                @click="handleTaskAction(task, 'forceCancel')"
              >
                强制结束
              </button>
            </template>
            <!-- 已到达状态: 显示已返程 -->
            <template v-else-if="task.taskStatus === 'ARRIVED'">
              <button
                class="action-btn primary"
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'return')"
              >
                已返程
              </button>
            </template>
            <!-- 返程中状态: 显示已完成 -->
            <template v-else-if="task.taskStatus === 'RETURNING'">
              <button
                class="action-btn primary"
              <button
                class="action-btn primary"
                @click="handleTaskAction(task, 'complete')"
              >
                已完成
              </button>
            </template>
            <!-- 已完成/已取消: 不显示按钮 -->
          </view>
        </view>
        <view class="no-data" v-if="runningTasks.length === 0">
          <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>
@@ -158,154 +234,270 @@
</template>
<script>
  import { mapState } from 'vuex'
  import { getMyTasks, changeTaskStatus } from '@/api/task'
  import { getUserProfile } from '@/api/system/user'
  import { getUserBoundVehicle } from '@/api/vehicle'
  import { getUnreadCount } from '@/api/message'
  export default {
    data() {
      return {
        // 用户绑定的车辆信息
        boundVehicle: '',
        boundVehicleId: null,
        // 消息数据
        messages: [],
        unreadMessageCount: 0,
        // 正在运行的任务列表
        taskList: [],
        loading: false
import { mapState } from "vuex";
import { getMyTasks, changeTaskStatus } from "@/api/task";
import { getUserProfile } from "@/api/system/user";
import { getUserBoundVehicle } from "@/api/vehicle";
import { getUnreadCount } from "@/api/message";
import { formatDateTime } from "@/utils/common";
import subscribeManager from "@/utils/subscribe";
export default {
  data() {
    return {
      // 用户绑定的车辆信息
      boundVehicle: "",
      boundVehicleId: null,
      // 消息数据
      messages: [],
      unreadMessageCount: 0,
      // 正在运行的任务列表
      allTaskList: [], // 存储所有任务数据
      displayedTaskList: [], // 存储当前显示的任务数据
      loading: false,
      // 订阅状态
      hasSubscribed: false,
      // 前端分页相关
      currentPage: 1,
      pageSize: 10,
      hasMore: true,
    };
  },
  computed: {
    ...mapState({
      userName: (state) => state.user.nickName,
      currentUser: (state) => state.user,
    }),
    // 正在运行的任务(待处理和各种处理中的任务)
    runningTasks() {
      return this.displayedTaskList.filter((task) => {
        // 包含待处理、出发中、已到达、返程中等所有未完成的状态
        return [
          "PENDING",
          "DEPARTING",
          "ARRIVED",
          "RETURNING",
          "IN_PROGRESS",
        ].includes(task.taskStatus);
      });
    },
  },
  onLoad() {
    // 检查用户是否已登录
    const userId = this.currentUser.userId;
    if (!userId) {
      console.log("用户未登录,跳过加载数据");
      return;
    }
    // 检查订阅状态(先检查本地,后面会检查微信官方状态)
    this.hasSubscribed = true;//subscribeManager.checkLocalSubscribeStatus();
    // 自动订阅(如果未订阅则显示确认弹窗)
    // this.autoSubscribeOnLaunch();
    // 加载用户绑定车辆信息
    this.loadUserVehicle();
    // 加载正在运行的任务
    this.loadRunningTasks();
    // 加载未读消息数量
    this.loadUnreadMessageCount();
  },
  onShow() {
    // 检查用户是否已登录
    const userId = this.currentUser.userId;
    if (!userId) {
      console.log("用户未登录,跳过加载数据");
      return;
    }
    // 每次显示页面时刷新任务列表、绑定车辆和消息数量
    this.loadUserVehicle();
    // 重新加载任务列表时重置分页
    this.currentPage = 1;
    this.hasMore = true;
    this.loadRunningTasks();
    this.loadUnreadMessageCount();
  },
  onPullDownRefresh() {
    // 下拉刷新时重置分页参数
    this.currentPage = 1;
    this.hasMore = true;
    // 下拉刷新
    this.loadRunningTasks();
    setTimeout(() => {
      uni.stopPullDownRefresh();
    }, 1000);
  },
  methods: {
    // 滚动到底部时加载更多
    onScrollToLower() {
      if (this.hasMore && !this.loading) {
        this.loadMoreTasks();
      }
    },
    computed: {
      ...mapState({
        userName: state => state.user.nickName,
        currentUser: state => state.user
      }),
      // 正在运行的任务(待处理和各种处理中的任务)
      runningTasks() {
        return this.taskList.filter(task => {
          // 包含待处理、出发中、已到达、返程中等所有未完成的状态
          return ['PENDING', 'DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(task.taskStatus)
    // 自动订阅(小程序启动时调用)
    autoSubscribeOnLaunch() {
      subscribeManager.autoSubscribe()
        .then((result) => {
          if (result.skipped) {
            console.log('用户已订阅,无需重复订阅');
            this.hasSubscribed = true;
          } else if (result.success) {
            this.hasSubscribed = true;
            console.log('自动订阅成功');
          } else {
            // 订阅失败或被拒绝,更新状态
            this.hasSubscribed = false;
          }
          // 如果返回了状态信息,输出详细状态
          if (result.status) {
            console.log('详细订阅状态:', result.status);
          }
        })
        .catch((error) => {
          console.log('自动订阅取消或失败:', error);
          this.hasSubscribed = false;
        });
    },
    // 加载用户绑定的车辆信息
    loadUserVehicle() {
      const userId = this.currentUser.userId;
      if (!userId) {
        console.error("用户未登录,无法获取绑定车辆信息");
        this.boundVehicle = "";
        this.boundVehicleId = null;
        return;
      }
      getUserBoundVehicle(userId)
        .then((response) => {
          if (response.code === 200 && response.data) {
            const vehicle = response.data;
            this.boundVehicle = vehicle.vehicleNumber || "未知车牌";
            this.boundVehicleId = vehicle.vehicleId;
            console.log("用户绑定车辆:", this.boundVehicle);
          } else {
            this.boundVehicle = "";
            this.boundVehicleId = null;
          }
        })
        .catch((error) => {
          console.error("获取绑定车辆信息失败:", error);
          this.boundVehicle = "";
          this.boundVehicleId = null;
        });
    },
    // 加载未读消息数量
    loadUnreadMessageCount() {
      // 检查用户是否已登录
      const userId = this.currentUser.userId;
      if (!userId) {
        console.log("用户未登录,跳过获取未读消息数量");
        return;
      }
      getUnreadCount()
        .then((response) => {
          if (response.code === 200) {
            this.unreadMessageCount = response.data || 0;
            // 更新TabBar徽标
            this.updateTabBarBadge(this.unreadMessageCount);
          }
        })
        .catch((error) => {
          console.error("获取未读消息数量失败:", error);
        });
    },
    // 更新TabBar徽标
    updateTabBarBadge(count) {
      if (count > 0) {
        uni.setTabBarBadge({
          index: 3, // 消息页面在tabBar中的索引
          text: count > 99 ? "99+" : count.toString(),
        });
      } else {
        uni.removeTabBarBadge({
          index: 3,
        });
      }
    },
    onLoad() {
      // 加载用户绑定车辆信息
      this.loadUserVehicle()
      // 加载正在运行的任务
      this.loadRunningTasks()
      // 加载未读消息数量
      this.loadUnreadMessageCount()
    },
    onShow() {
      // 每次显示页面时刷新任务列表、绑定车辆和消息数量
      this.loadUserVehicle()
      this.loadRunningTasks()
      this.loadUnreadMessageCount()
    },
    onPullDownRefresh() {
      // 下拉刷新
      this.loadRunningTasks()
      setTimeout(() => {
        uni.stopPullDownRefresh()
      }, 1000)
    },
    methods: {
      // 加载用户绑定的车辆信息
      loadUserVehicle() {
        const userId = this.currentUser.userId
        if (!userId) {
          console.error('用户未登录,无法获取绑定车辆信息')
          this.boundVehicle = ''
          this.boundVehicleId = null
          return
        }
        getUserBoundVehicle(userId).then(response => {
          if (response.code === 200 && response.data) {
            const vehicle = response.data
            this.boundVehicle = vehicle.vehicleNumber || '未知车牌'
            this.boundVehicleId = vehicle.vehicleId
            console.log('用户绑定车辆:', this.boundVehicle)
          } else {
            this.boundVehicle = ''
            this.boundVehicleId = null
          }
        }).catch(error => {
          console.error('获取绑定车辆信息失败:', error)
          this.boundVehicle = ''
          this.boundVehicleId = null
        })
      },
      // 加载未读消息数量
      loadUnreadMessageCount() {
        getUnreadCount().then(response => {
          if (response.code === 200) {
            this.unreadMessageCount = response.data || 0
          }
        }).catch(error => {
          console.error('获取未读消息数量失败:', error)
        })
      },
      // 加载用户信息(保留以兼容之前的代码)
      loadUserProfile() {
        const userId = this.currentUser.userId
        if (!userId) {
          console.error('用户未登录,无法获取用户信息')
          return
        }
        getUserProfile().then(response => {
          const userInfo = response.data || response
    // 加载用户信息(保留以兼容之前的代码)
    loadUserProfile() {
      const userId = this.currentUser.userId;
      if (!userId) {
        console.error("用户未登录,无法获取用户信息");
        return;
      }
      getUserProfile()
        .then((response) => {
          const userInfo = response.data || response;
          // 获取用户绑定的车辆信息
          if (userInfo.boundVehicle) {
            this.boundVehicle = userInfo.boundVehicle.vehicleNumber
            this.boundVehicleId = userInfo.boundVehicle.vehicleId
            this.boundVehicle = userInfo.boundVehicle.vehicleNumber;
            this.boundVehicleId = userInfo.boundVehicle.vehicleId;
          }
        }).catch(error => {
          console.error('获取用户信息失败:', error)
        })
      },
      // 加载正在运行的任务
      loadRunningTasks() {
        const userId = this.currentUser.userId
        if (!userId) {
          console.error('用户未登录,无法加载任务列表')
          return
        }
        this.loading = true
        // 使用 /task/my 接口获取当前用户相关的所有任务(用户创建、分配给用户、执行人是用户)
        getMyTasks().then(response => {
          this.loading = false
        .catch((error) => {
          console.error("获取用户信息失败:", error);
        });
    },
    // 加载正在运行的任务
    loadRunningTasks() {
      const userId = this.currentUser.userId;
      if (!userId) {
        console.error("用户未登录,无法加载任务列表");
        return;
      }
      this.loading = true;
      // 使用 /task/my 接口获取当前用户相关的所有任务(用户创建、分配给用户、执行人是用户)
      getMyTasks()
        .then((response) => {
          this.loading = false;
          // 根据后端返回的数据结构进行解析
          const data = response.data || response.rows || response || []
          // 过滤出未完成的任务
          const allTasks = Array.isArray(data) ? data : []
          this.taskList = allTasks
            .filter(task => {
          const data = response.data || response.rows || response || [];
          // 如果是第一页,直接替换数据;否则追加数据
          if (this.currentPage === 1) {
            this.allTaskList = data;
          } else {
            this.allTaskList = [...this.allTaskList, ...data];
          }
          // 格式化任务数据
          this.allTaskList = this.allTaskList
            .filter((task) => {
              // 只显示未完成和未取消的任务
              return task.taskStatus !== 'COMPLETED' && task.taskStatus !== 'CANCELLED'
              return (
                task.taskStatus !== "COMPLETED" &&
                task.taskStatus !== "CANCELLED"
              );
            })
            .map(task => {
            .map((task) => {
              // 从assignedVehicles数组中获取车辆信息
              let vehicleInfo = '未分配车辆'
              let vehicleInfo = "未分配车辆";
              if (task.assignedVehicles && task.assignedVehicles.length > 0) {
                const firstVehicle = task.assignedVehicles[0]
                vehicleInfo = firstVehicle.vehicleNo || '未知车牌'
                const firstVehicle = task.assignedVehicles[0];
                vehicleInfo = firstVehicle.vehicleNo || "未知车牌";
                if (task.assignedVehicles.length > 1) {
                  vehicleInfo += ` 等${task.assignedVehicles.length}辆`
                  vehicleInfo += ` 等${task.assignedVehicles.length}辆`;
                }
              }
              return {
                ...task,
                // 格式化显示字段
@@ -313,579 +505,721 @@
                type: task.taskType,
                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 || '未分配',
                taskNo: task.taskCode || '未知编号',
                status: this.convertStatus(task.taskStatus) // 转换状态格式以兼容旧UI
              }
            })
        }).catch(error => {
          this.loading = false
          console.error('加载任务列表失败:', error)
                startLocation: this.formatAddress(
                  task.departureAddress || task.startLocation || "未设置"
                ),
                endLocation: this.formatAddress(
                  task.destinationAddress || task.endLocation || "未设置"
                ),
                startTime: task.plannedStartTime
                  ? 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;
      
      // 格式化日期时间
      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
      },
      // 转换状态格式(将数据库状态转换为UI使用的状态)
      convertStatus(dbStatus) {
        const statusMap = {
          'PENDING': 'pending',
          'DEPARTING': 'processing',
          'ARRIVED': 'processing',
          'RETURNING': 'processing',
          'IN_PROGRESS': 'processing',
          'COMPLETED': 'completed',
          'CANCELLED': 'cancelled'
        }
        return statusMap[dbStatus] || 'pending'
      },
      // 跳转到绑定车辆页面
      goToBindVehicle() {
        // 跳转到绑定车辆的页面
        this.$tab.navigateTo('/pages/bind-vehicle');
      },
      // 跳转到消息页面
      goToMessages() {
        this.$tab.switchTab('/pages/message/index');
      },
      // 查看任务详情
      viewTaskDetail(task) {
        // 跳转到任务详情页面 - 使用taskId
        this.$tab.navigateTo(`/pages/task/detail?id=${task.taskId || task.id}`);
      },
      // 处理任务操作
      handleTaskAction(task, action) {
        switch (action) {
          case 'depart':
            // 出发 -> 状态变为出发中
            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.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.updateTaskStatus(task.taskId, 'RETURNING', '已开始返程')
            }).catch(() => {});
            break;
          case 'complete':
            // 已完成 -> 状态变为已完成
            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.loadRunningTasks()
            }).catch(error => {
              console.error('更新任务状态失败:', error)
              that.$modal.showToast('状态更新失败,请重试')
      this.currentPage++;
      this.updateDisplayedTaskList();
    },
    // 格式化地址 - 只显示-前面的部分
    formatAddress(address) {
      if (!address) return "未设置";
      const dashIndex = address.indexOf("-");
      if (dashIndex > 0) {
        return address.substring(0, dashIndex);
      }
      return address;
    },
    // 转换状态格式(将数据库状态转换为UI使用的状态)
    convertStatus(dbStatus) {
      const statusMap = {
        PENDING: "pending",
        DEPARTING: "processing",
        ARRIVED: "processing",
        RETURNING: "processing",
        IN_PROGRESS: "processing",
        COMPLETED: "completed",
        CANCELLED: "cancelled",
      };
      return statusMap[dbStatus] || "pending";
    },
    // 跳转到绑定车辆页面
    goToBindVehicle() {
      // 跳转到绑定车辆的页面
      this.$tab.navigateTo("/pages/bind-vehicle");
    },
    // 跳转到消息页面
    goToMessages() {
      this.$tab.switchTab("/pages/message/index");
    },
    // 查看任务详情
    viewTaskDetail(task) {
      // 跳转到任务详情页面 - 使用taskId
      this.$tab.navigateTo(`/pagesTask/detail?id=${task.taskId || task.id}`);
    },
    // 处理任务操作
    handleTaskAction(task, action) {
      switch (action) {
        case "depart":
          // 出发 -> 状态变为出发中
          this.$modal
            .confirm("确定要出发吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "DEPARTING", "任务已出发");
            })
          },
          fail: function(err) {
            console.error('GPS定位失败:', err)
            that.$modal.confirm('GPS定位失败,是否继续更新状态?').then(() => {
            .catch(() => {});
          break;
        case "cancel":
          // 取消 -> 二次确认后状态变为已取消
          this.$modal
            .confirm("确定要取消此任务吗?")
            .then(() => {
              this.updateTaskStatus(task.taskId, "CANCELLED", "任务已取消");
            })
            .catch(() => {});
          break;
        case "arrive":
          // 已到达 -> 状态变为已到达
          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.updateTaskStatus(task.taskId, "RETURNING", "已开始返程");
            })
            .catch(() => {});
          break;
        case "complete":
          // 已完成 -> 状态变为已完成
          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.loadRunningTasks();
            })
            .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.loadRunningTasks()
              }).catch(error => {
                console.error('更新任务状态失败:', error)
                that.$modal.showToast('状态更新失败,请重试')
              })
            }).catch(() => {})
                remark: remark,
              };
              changeTaskStatus(taskId, statusData)
                .then((response) => {
                  that.$modal.showToast("状态更新成功");
                  that.loadRunningTasks();
                })
                .catch((error) => {
                  console.error("更新任务状态失败:", error);
                  that.$modal.showToast("状态更新失败,请重试");
                });
            })
            .catch(() => {});
        },
      });
    },
    // 获取状态样式类
    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] || "未知类型";
    },
    clickConfirmsubscribeTaskNotify() {
      subscribeManager.subscribeWithConfirm()
        .then((result) => {
          if (result.success) {
            this.hasSubscribed = true;
          }
        })
      },
      // 获取状态样式类
      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] || '未知类型'
      }
    }
  }
        .catch((error) => {
          console.log('订阅取消或失败:', error);
        });
    },
    // 订阅任务通知(直接调用,不显示确认弹窗)
    subscribeTaskNotify() {
      subscribeManager.subscribeDirect()
        .then((result) => {
          if (result.success) {
            this.hasSubscribed = true;
          }
        })
        .catch((error) => {
          console.log('订阅失败:', error);
        });
    },
  },
};
</script>
<style lang="scss">
  .home-container {
    padding: 20rpx;
    background-color: #f5f5f5;
    height: 100vh;
    display: flex;
    flex-direction: column;
    // 隐藏滚动条但保持滚动功能
    ::-webkit-scrollbar {
      display: none;
      width: 0 !important;
      height: 0 !important;
      background: transparent;
    }
    // Firefox滚动条隐藏
    * {
      scrollbar-width: none; /* Firefox */
    }
    // IE/Edge滚动条隐藏
    * {
      -ms-overflow-style: none; /* IE 10+ */
    }
.home-container {
  padding: 20rpx;
  background-color: #f5f5f5;
  height: 100vh;
  display: flex;
  flex-direction: column;
  // 隐藏滚动条但保持滚动功能
  ::-webkit-scrollbar {
    display: none;
    width: 0 !important;
    height: 0 !important;
    background: transparent;
  }
  
  // 用户信息区域
  .user-info-section {
    background-color: white;
    border-radius: 15rpx;
    padding: 30rpx;
    margin-bottom: 20rpx;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
    flex-shrink: 0; // 防止收缩
    .user-info-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
      .user-details {
        flex: 1;
        .user-info-row {
          display: flex;
          align-items: center;
          flex-wrap: wrap;
          margin-bottom: 12rpx;
          .user-name {
            font-size: 32rpx;
            font-weight: bold;
            color: #333;
          }
          .separator {
            margin: 0 12rpx;
            color: #ddd;
            font-size: 28rpx;
          }
          .branch-company {
            font-size: 26rpx;
            color: #666;
            display: flex;
            align-items: center;
          }
          .vehicle-info {
            font-size: 26rpx;
            color: #007AFF;
            display: flex;
            align-items: center;
          }
  // Firefox滚动条隐藏
  * {
    scrollbar-width: none; /* Firefox */
  }
  // IE/Edge滚动条隐藏
  * {
    -ms-overflow-style: none; /* IE 10+ */
  }
}
// 总部推送标记样式
.head-push-tag {
  color: #ff0000;
  font-size: 24rpx;
  font-weight: bold;
  margin-left: 10rpx;
  padding: 2rpx 8rpx;
  border: 1rpx solid #ff0000;
  border-radius: 4rpx;
}
// 用户信息区域
.user-info-section {
  background-color: white;
  border-radius: 15rpx;
  padding: 30rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  flex-shrink: 0; // 防止收缩
  .user-info-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    .user-details {
      flex: 1;
      .user-info-row {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        margin-bottom: 12rpx;
        .user-name {
          font-size: 32rpx;
          font-weight: bold;
          color: #333;
        }
        .bind-vehicle-btn {
        .separator {
          margin: 0 12rpx;
          color: #ddd;
          font-size: 28rpx;
        }
        .branch-company {
          font-size: 26rpx;
          color: #007AFF;
          color: #666;
          display: flex;
          align-items: center;
          &:active {
            opacity: 0.7;
          }
        }
        .vehicle-info {
          font-size: 26rpx;
          color: #007aff;
          display: flex;
          align-items: center;
        }
      }
      .bind-vehicle-btn {
        font-size: 26rpx;
        color: #007aff;
        display: flex;
        align-items: center;
        &:active {
          opacity: 0.7;
        }
      }
    }
  }
  // 消息入口
  .message-entry {
}
// 消息入口
.message-entry {
  display: flex;
  align-items: center;
  background-color: white;
  border-radius: 15rpx;
  padding: 30rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  position: relative;
  .message-icon {
    margin-right: 20rpx;
  }
  .message-text {
    flex: 1;
    font-size: 32rpx;
    color: #333;
  }
  .unread-dot {
    position: absolute;
    top: 15rpx;
    right: 60rpx;
    background-color: #ff4d4f;
    color: white;
    border-radius: 50%;
    width: 32rpx;
    height: 32rpx;
    display: flex;
    align-items: center;
    background-color: white;
    border-radius: 15rpx;
    padding: 30rpx;
    margin-bottom: 20rpx;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
    position: relative;
    .message-icon {
      margin-right: 20rpx;
    }
    .message-text {
      flex: 1;
      font-size: 32rpx;
      color: #333;
    }
    .unread-dot {
      position: absolute;
      top: 15rpx;
      right: 60rpx;
      background-color: #ff4d4f;
      color: white;
      border-radius: 50%;
      width: 32rpx;
      height: 32rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 20rpx;
    }
    .arrow {
      margin-left: 20rpx;
    }
    justify-content: center;
    font-size: 20rpx;
  }
  // 正在运行的任务标题
  .running-tasks-header {
    margin-bottom: 20rpx;
    flex-shrink: 0; // 防止收缩
    .header-title {
      font-size: 36rpx;
  .arrow {
    margin-left: 20rpx;
  }
}
// 订阅通知横幅
.subscribe-banner {
  display: flex;
  align-items: center;
  background: linear-gradient(135deg, #fff9e6 0%, #fff3e0 100%);
  border-radius: 15rpx;
  padding: 30rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 2rpx 10rpx rgba(255, 149, 0, 0.1);
  border: 1rpx solid #ffe0b2;
  .banner-icon {
    margin-right: 20rpx;
    flex-shrink: 0;
  }
  .banner-content {
    flex: 1;
    .banner-title {
      font-size: 30rpx;
      font-weight: bold;
      color: #333;
      margin-bottom: 8rpx;
    }
    .banner-desc {
      font-size: 24rpx;
      color: #666;
      line-height: 1.4;
    }
  }
  // 正在运行的任务列表
  .running-tasks-section {
    flex: 1;
  .banner-action {
    display: flex;
    align-items: center;
    padding: 12rpx 24rpx;
    background-color: white;
    border-radius: 15rpx;
    padding: 30rpx;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
    // 隐藏滚动条但保持滚动功能
    ::-webkit-scrollbar {
      display: none;
      width: 0 !important;
      height: 0 !important;
      background: transparent;
    border-radius: 30rpx;
    flex-shrink: 0;
    text {
      font-size: 26rpx;
      color: #007aff;
      margin-right: 4rpx;
    }
    // Firefox滚动条隐藏
    * {
      scrollbar-width: none; /* Firefox */
    }
    // IE/Edge滚动条隐藏
    * {
      -ms-overflow-style: none; /* IE 10+ */
    }
    .task-list {
      .task-item {
        background-color: #fafafa;
        border-radius: 15rpx;
        margin-bottom: 30rpx;
        overflow: hidden;
        .task-main {
          padding: 30rpx;
          border-bottom: 1rpx solid #f0f0f0;
          // 任务头部:标题和状态
          .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;
              }
            }
  }
  &:active {
    opacity: 0.9;
  }
}
// 正在运行的任务标题
.running-tasks-header {
  margin-bottom: 20rpx;
  flex-shrink: 0; // 防止收缩
  .header-title {
    font-size: 36rpx;
    font-weight: bold;
    color: #333;
  }
}
// 正在运行的任务列表
.running-tasks-section {
  flex: 1;
  background-color: white;
  border-radius: 15rpx;
  padding: 30rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  // 隐藏滚动条但保持滚动功能
  ::-webkit-scrollbar {
    display: none;
    width: 0 !important;
    height: 0 !important;
    background: transparent;
  }
  // Firefox滚动条隐藏
  * {
    scrollbar-width: none; /* Firefox */
  }
  // IE/Edge滚动条隐藏
  * {
    -ms-overflow-style: none; /* IE 10+ */
  }
  .task-list {
    .task-item {
      background-color: #fafafa;
      border-radius: 15rpx;
      margin-bottom: 30rpx;
      overflow: hidden;
      .task-main {
        padding: 30rpx;
        border-bottom: 1rpx solid #f0f0f0;
        // 任务头部:标题和状态
        .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-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-status {
            padding: 8rpx 20rpx;
            border-radius: 30rpx;
            font-size: 24rpx;
            white-space: nowrap;
            flex-shrink: 0;
            // 待处理 - 橙色
            &.status-pending {
              background-color: #fff3e0;
              color: #ff9500;
            }
          }
          .task-info {
            .info-row {
              display: flex;
              margin-bottom: 15rpx;
              &:last-child {
                margin-bottom: 0;
              }
              .info-item {
                flex: 1;
                display: flex;
                .label {
                  font-size: 26rpx;
                  color: #666;
                  margin-right: 10rpx;
                  white-space: nowrap;
                }
                .value {
                  font-size: 26rpx;
                  flex: 1;
                  word-break: break-all;
                }
              }
            // 出发中 - 蓝色
            &.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-actions {
          display: flex;
          padding: 20rpx;
          .action-btn {
            flex: 1;
            height: 70rpx;
            border-radius: 10rpx;
            font-size: 26rpx;
            margin: 0 5rpx;
            background-color: #f0f0f0;
        // 任务编号单独一行
        .task-code-row {
          margin-bottom: 15rpx;
          padding: 10rpx 0;
          border-bottom: 1rpx dashed #e0e0e0;
          .task-code {
            font-size: 28rpx;
            color: #333;
            &.primary {
              background-color: #007AFF;
              color: white;
            }
            &.cancel {
              background-color: #ff3b30;
              color: white;
            }
            &.disabled {
              opacity: 0.5;
            }
            &:first-child {
              margin-left: 0;
            }
            font-weight: 500;
            font-family: monospace;
          }
        }
        .task-info {
          .info-row {
            display: flex;
            margin-bottom: 15rpx;
            &:last-child {
              margin-right: 0;
              margin-bottom: 0;
            }
            .info-item {
              flex: 1;
              display: flex;
              .label {
                font-size: 26rpx;
                color: #666;
                margin-right: 10rpx;
                white-space: nowrap;
              }
              .value {
                font-size: 26rpx;
                flex: 1;
                word-break: break-all;
              }
            }
          }
        }
      }
      .no-data {
        text-align: center;
        padding: 100rpx 0;
        color: #999;
        text {
          display: block;
          margin-top: 20rpx;
      .task-actions {
        display: flex;
        padding: 20rpx;
        .action-btn {
          flex: 1;
          height: 70rpx;
          border-radius: 10rpx;
          font-size: 26rpx;
          margin: 0 5rpx;
          background-color: #f0f0f0;
          color: #333;
          &.primary {
            background-color: #007aff;
            color: white;
          }
          &.cancel {
            background-color: #ff3b30;
            color: white;
          }
          &.disabled {
            opacity: 0.5;
          }
          &:first-child {
            margin-left: 0;
          }
          &:last-child {
            margin-right: 0;
          }
        }
      }
    }
    .no-data {
      text-align: center;
      padding: 100rpx 0;
      color: #999;
      text {
        display: block;
        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;
      }
    }
  }
}
</style>