| | |
| | | <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 |
| | |
| | | placeholder="请输入车牌号" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="关联状态" prop="status"> |
| | |
| | | </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> |
| | | |
| | |
| | | @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> |
| | |
| | | <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 { |
| | | // 遮罩层 |
| | |
| | | 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, |
| | |
| | | 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); |
| | | }); |
| | | }, |
| | | /** 获取任务列表 */ |
| | |
| | | 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) { |