wlzboy
2025-12-04 4f2925f1974844b66225ac70ae35065b8262b315
ruoyi-ui/src/views/task/vehicle/index.vue
@@ -1,25 +1,14 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="任务" prop="taskId">
        <el-select v-model="queryParams.taskId" placeholder="请选择任务" clearable filterable style="width: 200px">
          <el-option
            v-for="task in taskList"
            :key="task.taskId"
            :label="task.taskCode + ' - ' + getTaskTypeName(task.taskType)"
            :value="task.taskId"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="车辆" prop="vehicleId">
        <el-select v-model="queryParams.vehicleId" placeholder="请选择车辆" clearable filterable style="width: 200px">
          <el-option
            v-for="vehicle in vehicleList"
            :key="vehicle.vehicleId"
            :label="vehicle.vehicleNo + ' - ' + vehicle.deptName"
            :value="vehicle.vehicleId"
          />
        </el-select>
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
      <el-form-item label="任务编号" prop="taskCode">
        <el-input
          v-model="queryParams.taskCode"
          placeholder="请输入任务编号"
          clearable
          @keyup.enter.native="handleQuery"
          style="width: 200px"
        />
      </el-form-item>
      <el-form-item label="车牌号" prop="vehicleNo">
        <el-input
@@ -27,13 +16,14 @@
          placeholder="请输入车牌号"
          clearable
          @keyup.enter.native="handleQuery"
          style="width: 200px"
        />
      </el-form-item>
      <el-form-item label="关联状态" prop="status">
        <el-select v-model="queryParams.status" placeholder="请选择关联状态" clearable>
          <el-option
            v-for="dict in dict.type.sys_task_vehicle_status"
            :key="dict.value"
            :key="'search-' + dict.value"
            :label="dict.label"
            :value="dict.value"
          />
@@ -108,9 +98,20 @@
        </template>
      </el-table-column>
      <el-table-column label="车牌号" align="center" prop="vehicleNo" />
      <el-table-column label="车辆类型" align="center" prop="vehicleType">
      <el-table-column label="当前任务状态" align="center" prop="currentTaskStatus" width="180">
        <template slot-scope="scope">
          <dict-tag :options="dict.type.sys_vehicle_type" :value="scope.row.vehicleType"/>
          <div v-if="scope.row.currentTaskCode">
            <el-tag type="success" size="mini">
              <i class="el-icon-loading"></i> 任务中
            </el-tag>
            <div style="font-size: 12px; color: #409EFF; margin-top: 5px;">
              {{ scope.row.currentTaskCode }}
            </div>
          </div>
          <el-tag v-else type="info" size="mini">
            <i class="el-icon-circle-check"></i> 空闲
          </el-tag>
        </template>
      </el-table-column>
      
@@ -149,6 +150,12 @@
            @click="handleStatusChange(scope.row)"
            v-hasPermi="['task:vehicle:edit']"
          >状态变更</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-tickets"
            @click="handleViewTaskList(scope.row)"
          >任务清单</el-button>
        </template>
      </el-table-column>
    </el-table>
@@ -210,7 +217,7 @@
          <el-select v-model="form.status" placeholder="请选择关联状态" style="width: 100%">
            <el-option
              v-for="dict in dict.type.sys_task_vehicle_status"
              :key="dict.value"
              :key="'form-' + dict.value"
              :label="dict.label"
              :value="dict.value"
            ></el-option>
@@ -236,7 +243,7 @@
          <el-select v-model="statusForm.newStatus" placeholder="请选择新状态">
            <el-option
              v-for="dict in dict.type.sys_task_vehicle_status"
              :key="dict.value"
              :key="'status-' + dict.value"
              :label="dict.label"
              :value="dict.value"
            ></el-option>
@@ -248,16 +255,68 @@
        <el-button @click="cancelStatusChange">取 消</el-button>
      </div>
    </el-dialog>
    <!-- 车辆任务清单对话框 -->
    <el-dialog :title="'车辆任务清单 - ' + currentVehicleNo" :visible.sync="taskListOpen" width="1200px" append-to-body>
      <el-table v-loading="taskListLoading" :data="vehicleTaskList" max-height="500">
        <el-table-column label="任务编号" align="center" prop="taskCode" width="180">
          <template slot-scope="scope">
            <el-button
              type="text"
              @click="handleViewTaskDetail(scope.row.taskId)"
              style="font-family: 'Courier New', monospace; font-size: 13px;"
            >{{ scope.row.taskCode }}</el-button>
          </template>
        </el-table-column>
        <el-table-column label="任务类型" align="center" prop="taskType" width="120">
          <template slot-scope="scope">
            <dict-tag :options="dict.type.sys_task_type" :value="scope.row.taskType"/>
          </template>
        </el-table-column>
        <el-table-column label="计划开始时间" align="center" prop="plannedStartTime" width="160">
          <template slot-scope="scope">
            <span v-if="scope.row.plannedStartTime">{{ parseTime(scope.row.plannedStartTime, '{y}-{m}-{d} {h}:{i}') }}</span>
            <span v-else style="color: #C0C4CC;">--</span>
          </template>
        </el-table-column>
        <el-table-column label="出发地址" align="center" prop="departureAddress" show-overflow-tooltip min-width="150" />
        <el-table-column label="目标地址" align="center" prop="destinationAddress" show-overflow-tooltip min-width="150" />
        <el-table-column label="预计公里数" align="center" prop="estimatedDistance" width="110">
          <template slot-scope="scope">
            <span v-if="scope.row.estimatedDistance">{{ scope.row.estimatedDistance }} km</span>
            <span v-else style="color: #C0C4CC;">--</span>
          </template>
        </el-table-column>
        <el-table-column label="任务状态" align="center" prop="taskStatus" width="100">
          <template slot-scope="scope">
            <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" width="100">
          <template slot-scope="scope">
            <el-button
              size="mini"
              type="text"
              icon="el-icon-view"
              @click="handleViewTaskDetail(scope.row.taskId)"
            >查看</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div slot="footer" class="dialog-footer">
        <el-button @click="taskListOpen = false">关 闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { listTaskVehicle, getTaskVehicle, delTaskVehicle, addTaskVehicle, updateTaskVehicle, updateTaskVehicleStatus, listTask } from "@/api/task";
import { listTaskVehicle, getTaskVehicle, delTaskVehicle, addTaskVehicle, updateTaskVehicle, updateTaskVehicleStatus, listTask, getTask, batchGetVehicleCurrentTaskStatus } from "@/api/task";
import { listVehicle } from "@/api/system/vehicle";
export default {
  name: "TaskVehicle",
  dicts: ['sys_task_vehicle_status', 'sys_vehicle_type', 'sys_task_type'],
  dicts: ['sys_task_vehicle_status', 'sys_vehicle_type', 'sys_task_type', 'sys_task_status'],
  data() {
    return {
      // 遮罩层
@@ -288,12 +347,19 @@
      open: false,
      // 是否显示状态变更弹出层
      statusOpen: false,
      // 是否显示任务清单弹出层
      taskListOpen: false,
      // 车辆任务列表
      vehicleTaskList: [],
      // 车辆任务列表加载状态
      taskListLoading: false,
      // 当前查看的车牌号
      currentVehicleNo: '',
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        taskId: null,
        vehicleId: null,
        taskCode: null,
        vehicleNo: null,
        status: null,
        assignBy: null,
@@ -334,7 +400,39 @@
      listTaskVehicle(this.queryParams).then(response => {
        this.taskVehicleList = response.rows;
        this.total = response.total;
        // 为每个车辆加载当前任务状态
        this.loadCurrentTaskStatus();
        this.loading = false;
      });
    },
    /** 加载车辆当前任务状态(优化:批量查询) */
    loadCurrentTaskStatus() {
      // 提取所有车辆ID
      const vehicleIds = this.taskVehicleList
        .map(item => item.vehicleId)
        .filter(id => id != null);
      if (vehicleIds.length === 0) {
        return;
      }
      // 批量查询车辆当前任务状态
      batchGetVehicleCurrentTaskStatus(vehicleIds).then(response => {
        const statusMap = response.data || {};
        // 更新每个车辆的任务状态
        this.taskVehicleList.forEach(item => {
          if (item.vehicleId && statusMap[item.vehicleId]) {
            const taskInfo = statusMap[item.vehicleId];
            this.$set(item, 'currentTaskCode', taskInfo.taskCode);
            this.$set(item, 'currentTaskStatus', taskInfo.taskStatus);
          } else {
            this.$set(item, 'currentTaskCode', null);
            this.$set(item, 'currentTaskStatus', null);
          }
        });
      }).catch(error => {
        console.error('加载车辆任务状态失败:', error);
      });
    },
    /** 获取任务列表 */
@@ -484,6 +582,61 @@
      this.statusOpen = false;
      this.statusForm = {};
    },
    /** 查看车辆任务清单 */
    handleViewTaskList(row) {
      this.currentVehicleNo = row.vehicleNo;
      this.taskListOpen = true;
      this.taskListLoading = true;
      // 查询该车辆的所有任务关联
      listTaskVehicle({
        vehicleId: row.vehicleId,
        pageNum: 1,
        pageSize: 1000
      }).then(response => {
        const taskVehicles = response.rows || [];
        // 获取所有任务ID
        const taskIds = [...new Set(taskVehicles.map(item => item.taskId).filter(id => id))];
        if (taskIds.length === 0) {
          this.vehicleTaskList = [];
          this.taskListLoading = false;
          return;
        }
        // 批量查询任务详情
        const taskPromises = taskIds.map(taskId =>
          getTask(taskId).then(res => res.data).catch(() => null)
        );
        Promise.all(taskPromises).then(tasks => {
          // 过滤掉空值并按时间排序
          this.vehicleTaskList = tasks
            .filter(task => task !== null)
            .sort((a, b) => {
              const timeA = new Date(a.plannedStartTime || a.createTime).getTime();
              const timeB = new Date(b.plannedStartTime || b.createTime).getTime();
              return timeB - timeA; // 降序排列
            });
          this.taskListLoading = false;
        }).catch(error => {
          console.error('查询任务详情失败:', error);
          this.$modal.msgError('加载任务清单失败');
          this.taskListLoading = false;
        });
      }).catch(error => {
        console.error('查询车辆任务关联失败:', error);
        this.$modal.msgError('加载任务清单失败');
        this.taskListLoading = false;
      });
    },
    /** 查看任务详情 */
    handleViewTaskDetail(taskId) {
      // 跳转到任务详情页面
      this.$router.push('/task/general-detail/index/' + taskId);
    },
    /** 任务选择变化 */
    handleTaskChange(taskId) {
      if (taskId) {