Merge remote-tracking branch 'origin/lxl-dev' into lxl-dev
This commit is contained in:
commit
e6d379f571
@ -209,7 +209,9 @@ const handleRobotChange = async (robotId) => {
|
|||||||
|
|
||||||
/** 获取在线机器人列表 */
|
/** 获取在线机器人列表 */
|
||||||
const loadRobotOptions = async () => {
|
const loadRobotOptions = async () => {
|
||||||
const res = await getRobotList({ pageNum: 1, pageSize: 1000, connectStatus: '1' })
|
// 试运行不需要要有连接状态为连接的,因为可以选择未连接的机器人进行试运行来保存流程数据
|
||||||
|
// , connectStatus: '1'
|
||||||
|
const res = await getRobotList({ pageNum: 1, pageSize: 1000 })
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
robotIdOptions.value = res.rows?.map((item) => {
|
robotIdOptions.value = res.rows?.map((item) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="bot-name">{{ item.robotName }}</div>
|
<div class="bot-name">{{ item.robotName }}</div>
|
||||||
<div class="bot-local">{{ agvRuntimeStatusLabel(item.status) }}</div>
|
<div class="bot-local" :class="agvRuntimeStatusClass(item.status)">{{ agvRuntimeStatusLabel(item.status) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -134,7 +134,7 @@ import { getJointStateApi, moveJApi, torqueOnApi, speedJApi, stopMotionApi, clea
|
|||||||
import { Remove, CirclePlus } from '@element-plus/icons-vue'
|
import { Remove, CirclePlus } from '@element-plus/icons-vue'
|
||||||
import VoiceConversation from "./VoiceConversation.vue";
|
import VoiceConversation from "./VoiceConversation.vue";
|
||||||
import IPlayer from "@/components/IPlayer/index.vue";
|
import IPlayer from "@/components/IPlayer/index.vue";
|
||||||
import { agvRuntimeStatusLabel } from '@/utils/agvRuntimeStatus'
|
import { agvRuntimeStatusClass, agvRuntimeStatusLabel } from '@/utils/agvRuntimeStatus'
|
||||||
|
|
||||||
const robotList = ref([])
|
const robotList = ref([])
|
||||||
const robotDevices = ref([])
|
const robotDevices = ref([])
|
||||||
@ -310,7 +310,7 @@ onMounted(() => {
|
|||||||
fetchRobotList()
|
fetchRobotList()
|
||||||
robotRefreshTimer = window.setInterval(() => {
|
robotRefreshTimer = window.setInterval(() => {
|
||||||
if (!document.hidden) fetchRobotList(false)
|
if (!document.hidden) fetchRobotList(false)
|
||||||
}, 5000)
|
}, 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@ -353,10 +353,10 @@ onUnmounted(() => {
|
|||||||
background: #0F1E38;
|
background: #0F1E38;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 12px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
@ -367,10 +367,34 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bot-local {
|
.bot-local {
|
||||||
color: #00d4ff;
|
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.online {
|
||||||
|
color: #0f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unknown,
|
||||||
|
.offline,
|
||||||
|
.stopped {
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual,
|
||||||
|
.running {
|
||||||
|
color: #00d4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.charging,
|
||||||
|
.paused {
|
||||||
|
color: #ffb300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fault,
|
||||||
|
.emergency {
|
||||||
|
color: #ff6b6d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
|
|||||||
@ -73,6 +73,11 @@ const applicationState = {
|
|||||||
let mapCanvas; // 主渲染画布 DOM 元素
|
let mapCanvas; // 主渲染画布 DOM 元素
|
||||||
let canvasCtx; // 2D 渲染上下文
|
let canvasCtx; // 2D 渲染上下文
|
||||||
|
|
||||||
|
// 保存当前动画帧 ID,组件卸载时用于停止 Canvas 渲染循环。
|
||||||
|
let animationFrameId;
|
||||||
|
// 地图请求版本号:当多个地图请求并发时,只允许最后一次请求更新画布。
|
||||||
|
let mapLoadVersion = 0;
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
mapCanvas = document.getElementById('map-canvas');
|
mapCanvas = document.getElementById('map-canvas');
|
||||||
canvasCtx = mapCanvas.getContext('2d');
|
canvasCtx = mapCanvas.getContext('2d');
|
||||||
@ -186,7 +191,7 @@ function renderFrame(timestamp) {
|
|||||||
|
|
||||||
// 如果地图未加载,跳过绘制
|
// 如果地图未加载,跳过绘制
|
||||||
if (!applicationState.isMapLoaded) {
|
if (!applicationState.isMapLoaded) {
|
||||||
requestAnimationFrame(renderFrame); // 继续请求下一帧
|
animationFrameId = requestAnimationFrame(renderFrame); // 继续请求下一帧
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +241,7 @@ function renderFrame(timestamp) {
|
|||||||
drawMapBoundary(canvasCtx, map);
|
drawMapBoundary(canvasCtx, map);
|
||||||
|
|
||||||
// 请求下一帧渲染
|
// 请求下一帧渲染
|
||||||
requestAnimationFrame(renderFrame);
|
animationFrameId = requestAnimationFrame(renderFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
const drawAllRobots = (ctx) => {
|
const drawAllRobots = (ctx) => {
|
||||||
@ -349,14 +354,40 @@ const centerCanvasView = () => {
|
|||||||
inspectionStore.camera.centerY = (map.originY + map.maxY) / 2;
|
inspectionStore.camera.centerY = (map.originY + map.maxY) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadSourceMap = async () => {
|
/**
|
||||||
const connectedRobot = props.robotList.find(item => item.connectStatus == 1);
|
* 从机器人列表中选出地图数据来源。
|
||||||
|
* 当前沿用原有规则:使用第一台已连接的机器人获取地图。
|
||||||
|
*/
|
||||||
|
const getConnectedRobot = (robotList = props.robotList) => {
|
||||||
|
return robotList.find(item => item?.connectStatus == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成地图来源的稳定标识。
|
||||||
|
* 机器人轮询时位置等字段会不断变化,但机器人 ID 和地图名称不变,
|
||||||
|
* 因此监听该标识可以避免位置更新触发底图重新加载。
|
||||||
|
*/
|
||||||
|
const getMapIdentity = (robotList = props.robotList) => {
|
||||||
|
const robot = getConnectedRobot(robotList)
|
||||||
|
return robot ? `${robot.id ?? ''}:${robot.robotMapName ?? ''}` : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求并加载机器人当前使用的地图。
|
||||||
|
* @param {Object} connectedRobot 用于提供地图的已连接机器人
|
||||||
|
*/
|
||||||
|
const loadSourceMap = async (connectedRobot = getConnectedRobot()) => {
|
||||||
if (!connectedRobot) return;
|
if (!connectedRobot) return;
|
||||||
|
|
||||||
|
// 记录本次请求版本。若等待响应期间又发起了新请求,则丢弃本次旧结果。
|
||||||
|
const currentLoadVersion = ++mapLoadVersion;
|
||||||
|
|
||||||
const res = await getMapJson({
|
const res = await getMapJson({
|
||||||
robotId: connectedRobot.id,
|
robotId: connectedRobot.id,
|
||||||
mapName: connectedRobot.robotMapName
|
mapName: connectedRobot.robotMapName
|
||||||
});
|
});
|
||||||
|
// 防止较慢返回的旧地图覆盖用户刚切换的新地图。
|
||||||
|
if (currentLoadVersion !== mapLoadVersion) return;
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
try {
|
try {
|
||||||
const rawJsonObject = JSON.parse(res.data); // 解析 JSON
|
const rawJsonObject = JSON.parse(res.data); // 解析 JSON
|
||||||
@ -369,19 +400,9 @@ const loadSourceMap = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 将接口返回的 "x,y,angle" 字符串转换为数值坐标。
|
||||||
* @param id 机器人编号
|
* 无位置或包含非法数值时返回 null,避免无效机器人进入绘制列表。
|
||||||
* @param name 机器人名称
|
|
||||||
* @param angleRad 角度
|
|
||||||
* @param color 颜色
|
|
||||||
*/
|
*/
|
||||||
const addRobot = (id, name,x, y, angleRad, color) => {
|
|
||||||
const map = applicationState.parsedMap;
|
|
||||||
// 放置于地图中央附近
|
|
||||||
const robot = new MobileRobot(id, name, x, y, angleRad, color);
|
|
||||||
applicationState.robots.push(robot);
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseRobotPosition = (currentPosition) => {
|
const parseRobotPosition = (currentPosition) => {
|
||||||
if (!currentPosition) return null
|
if (!currentPosition) return null
|
||||||
const values = String(currentPosition).split(',').map(Number)
|
const values = String(currentPosition).split(',').map(Number)
|
||||||
@ -389,55 +410,69 @@ const parseRobotPosition = (currentPosition) => {
|
|||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
const moveRobot = (robot, dx, dy, dtheta = 0) => {
|
/**
|
||||||
robot.x += dx;
|
* 将最新机器人列表同步到 Canvas 使用的机器人实例中。
|
||||||
robot.y += dy;
|
*
|
||||||
robot.angle += dtheta;
|
* 已存在的机器人会复用原 MobileRobot 实例,仅修改位置和名称;新增机器人
|
||||||
|
* 创建实例,接口中已移除或没有有效位置的机器人不会进入 nextRobots。
|
||||||
|
* 该函数不会加载地图或重置相机,因此可安全用于高频轮询。
|
||||||
|
*/
|
||||||
|
const syncRobots = (robotList) => {
|
||||||
|
// 用 ID 建立索引,避免为每台机器人遍历整个旧列表。
|
||||||
|
const previousRobots = new Map(applicationState.robots.map(robot => [robot.id, robot]));
|
||||||
|
const nextRobots = [];
|
||||||
|
|
||||||
|
robotList.forEach(item => {
|
||||||
|
const position = parseRobotPosition(item.currentPosition)
|
||||||
|
if (!position) return
|
||||||
|
|
||||||
|
const [x, y, angle] = position
|
||||||
|
const robot = previousRobots.get(item.id)
|
||||||
|
if (robot) {
|
||||||
|
// 保留原实例和颜色,只更新轮询产生的动态信息。
|
||||||
|
robot.name = item.robotName
|
||||||
|
robot.x = x
|
||||||
|
robot.y = y
|
||||||
|
robot.angle = angle
|
||||||
|
nextRobots.push(robot)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列表中首次出现的机器人需要创建绘制实例并分配颜色。
|
||||||
|
nextRobots.push(new MobileRobot(
|
||||||
|
item.id,
|
||||||
|
item.robotName,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
angle,
|
||||||
|
colorList[nextRobots.length % colorList.length]
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 整体替换绘制列表,同时自然移除本轮接口中不存在的机器人。
|
||||||
|
applicationState.robots = nextRobots
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
if (props.robotList.length > 0) {
|
window.addEventListener('resize', resizeCanvasToContainer);
|
||||||
loadSourceMap()
|
resizeCanvasToContainer();
|
||||||
requestAnimationFrame(renderFrame);
|
|
||||||
window.addEventListener('resize', resizeCanvasToContainer); // 监听窗口大小变化
|
|
||||||
resizeCanvasToContainer(); // 初始调用一次
|
|
||||||
setTimeout(() => {
|
|
||||||
bindEvent()
|
bindEvent()
|
||||||
props.robotList.forEach(item => {
|
syncRobots(props.robotList)
|
||||||
const position = parseRobotPosition(item.currentPosition)
|
loadSourceMap()
|
||||||
if (!position) return
|
animationFrameId = requestAnimationFrame(renderFrame);
|
||||||
const [x, y, angle] = position
|
|
||||||
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
|
||||||
})
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const colorList = ['#00D4FF', '#FFB300', '#00FF88', '#ff5100', '#fff', '#15ff00', '#ff00d4', '#00d4ff']
|
const colorList = ['#00D4FF', '#FFB300', '#00FF88', '#ff5100', '#fff', '#15ff00', '#ff00d4', '#00d4ff']
|
||||||
|
|
||||||
watch(() => props.robotList,
|
// 轮询只同步机器人实例,不重新请求、解析或重置地图。
|
||||||
(newVal) => {
|
watch(() => props.robotList, syncRobots)
|
||||||
if (newVal.length > 0) {
|
|
||||||
const ids = applicationState.robots.map(r => r.id);
|
// 只有用于加载地图的机器人或地图名称改变时,才重新加载底图。
|
||||||
props.robotList.forEach(item => {
|
watch(
|
||||||
const position = parseRobotPosition(item.currentPosition)
|
() => getMapIdentity(props.robotList),
|
||||||
if (!position) return
|
(newIdentity, oldIdentity) => {
|
||||||
const [x, y, angle] = position
|
if (newIdentity && newIdentity !== oldIdentity) loadSourceMap()
|
||||||
if (!ids.includes(item.id)) {
|
|
||||||
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
|
||||||
} else {
|
|
||||||
applicationState.robots.forEach(robot => {
|
|
||||||
if (robot.id === item.id) {
|
|
||||||
// moveRobot(robot, parseFloat(x) - robot.x, parseFloat(y) - robot.y, parseFloat(angle) - robot.angle)
|
|
||||||
robot.x = x
|
|
||||||
robot.y = y
|
|
||||||
robot.angle = angle
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -448,6 +483,9 @@ defineExpose({
|
|||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize', resizeCanvasToContainer)
|
window.removeEventListener('resize', resizeCanvasToContainer)
|
||||||
|
// 停止渲染循环,并使仍在进行中的地图请求全部失效。
|
||||||
|
cancelAnimationFrame(animationFrameId)
|
||||||
|
mapLoadVersion += 1
|
||||||
canvasCtx = null
|
canvasCtx = null
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -13,8 +13,8 @@
|
|||||||
<SvgIcon name="bot" :color="colorList[index]" />
|
<SvgIcon name="bot" :color="colorList[index]" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="bot-name">机器人#0{{ index + 1}}</div>
|
<div class="bot-name">{{ item.robotName }}</div>
|
||||||
<div class="bot-local">厂区A-在线</div>
|
<div class="bot-local" :class="agvRuntimeStatusClass(item.status)">{{ agvRuntimeStatusLabel(item.status) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -42,6 +42,7 @@
|
|||||||
import SvgIcon from "@/components/SvgIcon";
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
import IPlayer from "@/components/IPlayer/index.vue";
|
import IPlayer from "@/components/IPlayer/index.vue";
|
||||||
import { getRobotList } from '@/api/inspection/robot'
|
import { getRobotList } from '@/api/inspection/robot'
|
||||||
|
import { agvRuntimeStatusClass, agvRuntimeStatusLabel } from '@/utils/agvRuntimeStatus'
|
||||||
|
|
||||||
const videoUrl = ref('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
|
const videoUrl = ref('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
|
||||||
|
|
||||||
@ -112,10 +113,34 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bot-local {
|
.bot-local {
|
||||||
color: #00d4ff;
|
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.online {
|
||||||
|
color: #0f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unknown,
|
||||||
|
.offline,
|
||||||
|
.stopped {
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual,
|
||||||
|
.running {
|
||||||
|
color: #00d4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.charging,
|
||||||
|
.paused {
|
||||||
|
color: #ffb300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fault,
|
||||||
|
.emergency {
|
||||||
|
color: #ff6b6d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
|
|||||||
@ -122,7 +122,7 @@
|
|||||||
<div class="task-title">待选择点位</div>
|
<div class="task-title">待选择点位</div>
|
||||||
|
|
||||||
<draggable :animation="340" :forceFallback="true" :list="taskLeftList" class="draggable-group"
|
<draggable :animation="340" :forceFallback="true" :list="taskLeftList" class="draggable-group"
|
||||||
ghostClass="dragClass" group="people" itemKey="name">
|
ghostClass="dragClass" :group="{ name: 'people', pull: 'clone', put: false}" itemKey="name">
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@ -138,10 +138,11 @@
|
|||||||
<div style="height: 55vh">
|
<div style="height: 55vh">
|
||||||
<div class="task-title">点位排序</div>
|
<div class="task-title">点位排序</div>
|
||||||
<draggable :animation="340" :forceFallback="true" :list="taskRightList" class="draggable-group"
|
<draggable :animation="340" :forceFallback="true" :list="taskRightList" class="draggable-group"
|
||||||
ghostClass="dragClass" group="people" itemKey="name">
|
ghostClass="dragClass" :group="{ name: 'people', pull: false, put: true }" itemKey="name">
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
{{ index + 1 }} 、{{ element.waypointName }}
|
{{ index + 1 }} 、{{ element.waypointName }}
|
||||||
|
<el-icon color="red" @click="removeFromB(element.id)" style="margin-left: 10px;"><Delete /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
@ -377,6 +378,11 @@ const cancelPoint = () => {
|
|||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const removeFromB = (id) => {
|
||||||
|
const index = taskRightList.value.findIndex(item => item.id === id)
|
||||||
|
if (index !== -1) taskRightList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getMapArr();
|
getMapArr();
|
||||||
|
|||||||
@ -227,13 +227,14 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div style="height: 55vh">
|
<div style="height: 55vh">
|
||||||
<div class="task-title">待检测项</div>
|
<div class="task-title">待检测项</div>
|
||||||
|
<!-- group="people" -->
|
||||||
<draggable
|
<draggable
|
||||||
:animation="340"
|
:animation="340"
|
||||||
:forceFallback="true"
|
:forceFallback="true"
|
||||||
:list="taskLeftList"
|
:list="taskLeftList"
|
||||||
class="draggable-group"
|
class="draggable-group"
|
||||||
ghostClass="dragClass"
|
ghostClass="dragClass"
|
||||||
group="people"
|
:group="{ name: 'people', pull: 'clone', put: false}"
|
||||||
itemKey="name"
|
itemKey="name"
|
||||||
>
|
>
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
@ -256,12 +257,13 @@
|
|||||||
:list="taskRightList"
|
:list="taskRightList"
|
||||||
class="draggable-group"
|
class="draggable-group"
|
||||||
ghostClass="dragClass"
|
ghostClass="dragClass"
|
||||||
group="people"
|
:group="{ name: 'people', pull: false, put: true }"
|
||||||
itemKey="name"
|
itemKey="name"
|
||||||
>
|
>
|
||||||
<template #item="{ element, index }">
|
<template #item="{ element, index }">
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
{{ index + 1 }} 、{{ element.name }}
|
{{ index + 1 }} 、{{ element.name }}
|
||||||
|
<el-icon color="red" @click="removeFromB(element.id)" style="margin-left: 10px;"><Delete /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
@ -347,7 +349,7 @@ import { flowExecute } from "@/api/flow/flow";
|
|||||||
import TableSearch from "@/components/TableSearch/index.vue";
|
import TableSearch from "@/components/TableSearch/index.vue";
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import { listDetect } from "@/api/test/detect.js";
|
import { listDetect } from "@/api/test/detect.js";
|
||||||
import { Tools } from "@element-plus/icons-vue";
|
import { Tools, Delete } from "@element-plus/icons-vue";
|
||||||
import { listGroup } from "@/api/system/group.js";
|
import { listGroup } from "@/api/system/group.js";
|
||||||
import { listTerminal } from "@/api/device/terminal.js";
|
import { listTerminal } from "@/api/device/terminal.js";
|
||||||
import Run from "./Run.vue";
|
import Run from "./Run.vue";
|
||||||
@ -677,6 +679,11 @@ function handleGetTerminalGroup(row) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeFromB = (id) => {
|
||||||
|
const index = taskRightList.value.findIndex(item => item.id === id)
|
||||||
|
if (index !== -1) taskRightList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
handleGetSystemGroup();
|
handleGetSystemGroup();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user