@@ -170,7 +172,7 @@ import taskSteps from "./task-steps.vue";
import taskLog from "./task-log.vue";
import { useContainerHeight } from "@/hooks/tableHeight";
import { getTaskList, getWaypointByTaskId } from "@/api/inspection/task";
-import { onMounted, onUnmounted } from "vue";
+import { computed, onMounted, onUnmounted } from "vue";
import { addRunTask, getRunTaskList, startRunTask, rerunRunTask, pauseRunTask, stopRunTask, resumeRunTask, deleteRunTask, getTaskLogListApi } from "@/api/inspection/runTask";
import { ElMessage, ElMessageBox } from "element-plus";
import { formatDate } from "@/utils/index";
@@ -220,6 +222,23 @@ const rules = reactive({
const taskList = ref([]);
const runTaskList = ref([]);
+// 接口和 WebSocket 可能分别以数字、字符串返回任务实例 ID,统一转换后再判断是否为选中任务。
+const isSelectedTask = (task) => String(task?.id ?? '') === String(selectedTaskId.value)
+
+// 当前任务详情直接从完整任务队列中取得,因此未执行、执行中和已暂停任务都可以被选中查看。
+const selectedRunTask = computed(() => runTaskList.value.find(isSelectedTask) || null)
+
+/**
+ * 点击左侧任务卡片时切换右侧当前任务详情,并从历史记录面板返回当前任务面板。
+ * 卡片内的启动、暂停、停止和删除图标均使用 .stop 阻止冒泡,执行操作时不会意外改变当前选择。
+ *
+ * @param {Object} task 左侧任务队列中被点击的任务实例
+ */
+const selectTask = (task) => {
+ selectedTaskId.value = task.id
+ activePanel.value = 'current'
+}
+
const normalizeTaskStatus = (tasks = []) => tasks.map(item => ({
...item,
status: String(item.status),
@@ -264,9 +283,12 @@ const cancelTaskDialog = () => {
}
-const runingTaskList = ref([])
/**
- * 获取任务队列
+ * 获取任务队列并维护当前选中的任务:
+ * 1. 页面首次加载时默认选中队列第一条任务;
+ * 2. 队列刷新后,如果原任务仍存在,则保留用户当前选择;
+ * 3. 如果原任务已经结束或被删除,则选择刷新后队列中的第一条任务;
+ * 4. 如果任务队列为空,则清空选择并由模板展示空状态。
*/
const getList = () => {
return getRunTaskList({
@@ -275,7 +297,9 @@ const getList = () => {
if (res.code === 200) {
const tasks = normalizeTaskStatus(res.rows)
runTaskList.value = tasks;
- runingTaskList.value = tasks.filter(item => item.status !== '5')
+ if (!tasks.some(isSelectedTask)) {
+ selectedTaskId.value = tasks[0]?.id ?? ''
+ }
for (let i = 0; i < runTaskList.value.length; i++) {
getPointByTaskId(runTaskList.value[i].taskId)
getTaskLogList(runTaskList.value[i].id)
@@ -618,6 +642,17 @@ onUnmounted(() => {
box-shadow: inset 0 0 0 1px #eee;
border-radius: 8px;
margin-bottom: 16px;
+ cursor: pointer;
+ transition: background-color 0.2s ease, box-shadow 0.2s ease;
+
+ &:hover {
+ background: var(--el-fill-color-light);
+ }
+
+ &.is-selected {
+ background: var(--el-color-primary-light-9);
+ box-shadow: inset 0 0 0 2px var(--el-color-primary);
+ }
.task-content {
display: flex;
@@ -684,10 +719,6 @@ onUnmounted(() => {
border-radius: 20px;
margin-bottom: 12px;
- &--selected {
- box-shadow: inset 0 0 0 2px var(--el-color-primary);
- }
-
.task-header {
display: flex;
justify-content: space-between;
diff --git a/src/views/intelligenceTest/runningTask/index.vue b/src/views/intelligenceTest/runningTask/index.vue
index cdd5794..ab3e0de 100644
--- a/src/views/intelligenceTest/runningTask/index.vue
+++ b/src/views/intelligenceTest/runningTask/index.vue
@@ -6,18 +6,20 @@
添加任务
-
+
{{ task.taskName }}
+ @click.stop="pauseTask(task)" />
+ :size="24" color="#00FF88" @click.stop="startTask(task)" />
+ @click.stop="stopTask(task)" />
+ @click.stop="removeTask(task)" />
手机:{{ task.phoneName }}
@@ -36,44 +38,44 @@
-
-
+
+
执行进度
-
+ :percentage="parseFloat(taskRunningInfo[selectedRunTask.id]?.progress?.toFixed(2)) || 0" />
+
+
@@ -191,7 +193,7 @@ import { useContainerHeight } from "@/hooks/tableHeight";
import { getTaskList, getTestCaseByTaskId } from "@/api/intelligenceTest/taskManage";
import { getPhoneList } from "@/api/intelligenceTest/mobilePhone";
import { getVehicleList } from "@/api/intelligenceTest/car";
-import { onMounted, onUnmounted } from "vue";
+import { computed, onMounted, onUnmounted } from "vue";
import {
addTaskinstance,
getTaskinstanceList,
@@ -253,6 +255,21 @@ const phoneList = ref([]);
const runTaskList = ref([]);
+// 任务实例 ID 在接口和 WebSocket 中可能分别是数字或字符串,统一按字符串比较选中状态。
+const isSelectedTask = (task) => String(task?.id ?? '') === String(selectedTaskId.value)
+
+// 右侧当前任务始终从完整任务队列中取选中的一条,包括尚未执行、执行中和已暂停任务。
+const selectedRunTask = computed(() => runTaskList.value.find(isSelectedTask) || null)
+
+/**
+ * 点击左侧任务卡片时切换右侧详情,并自动回到“当前任务”面板。
+ * 卡片内部操作按钮使用 .stop 阻止冒泡,因此执行暂停/启动等命令时不会意外切换选择。
+ */
+const selectTask = (task) => {
+ selectedTaskId.value = task.id
+ activePanel.value = 'current'
+}
+
const normalizeTaskStatus = (tasks = []) => tasks.map(item => ({
...item,
status: String(item.status),
@@ -317,9 +334,11 @@ const cancelTaskDialog = () => {
}
-const runingTaskList = ref([])
/**
- * 获取任务队列
+ * 获取任务队列,并维护当前选中任务:
+ * 1. 首次加载默认选择队列第一条;
+ * 2. 刷新后原任务仍在队列中则保持选择;
+ * 3. 原任务已结束或被删除时回退到新的第一条,队列为空时清空选择。
*/
const getList = () => {
return getTaskinstanceList({
@@ -328,7 +347,9 @@ const getList = () => {
if (res.code === 200) {
const tasks = normalizeTaskStatus(res.rows)
runTaskList.value = tasks;
- runingTaskList.value = tasks.filter(item => item.status !== '5')
+ if (!tasks.some(isSelectedTask)) {
+ selectedTaskId.value = tasks[0]?.id ?? ''
+ }
for (let i = 0; i < runTaskList.value.length; i++) {
getCaseByTaskId(runTaskList.value[i].taskId)
getTaskLogList(runTaskList.value[i].id)
@@ -684,6 +705,17 @@ onUnmounted(() => {
box-shadow: inset 0 0 0 1px #eee;
border-radius: 8px;
margin-bottom: 16px;
+ cursor: pointer;
+ transition: background-color 0.2s ease, box-shadow 0.2s ease;
+
+ &:hover {
+ background: var(--el-fill-color-light);
+ }
+
+ &.is-selected {
+ background: var(--el-color-primary-light-9);
+ box-shadow: inset 0 0 0 2px var(--el-color-primary);
+ }
.task-content {
display: flex;
@@ -750,10 +782,6 @@ onUnmounted(() => {
border-radius: 20px;
margin-bottom: 12px;
- &--selected {
- box-shadow: inset 0 0 0 2px var(--el-color-primary);
- }
-
.task-header {
display: flex;
justify-content: space-between;