Compare commits
No commits in common. "b332a5461e231bcc1a8e01f0db168dc3bfcdaaec" and "2ae34b1f9ffd5826da6d0e83829502bde33ab237" have entirely different histories.
b332a5461e
...
2ae34b1f9f
@ -1,18 +0,0 @@
|
|||||||
const AGV_RUNTIME_STATUS = {
|
|
||||||
0: { label: '未知', type: 'info', className: 'unknown' },
|
|
||||||
1: { label: '已断开', type: 'info', className: 'offline' },
|
|
||||||
2: { label: '空闲', type: 'success', className: 'online' },
|
|
||||||
3: { label: '手动模式', type: 'primary', className: 'manual' },
|
|
||||||
4: { label: '自动运行', type: 'primary', className: 'running' },
|
|
||||||
5: { label: '充电中', type: 'warning', className: 'charging' },
|
|
||||||
6: { label: '已暂停', type: 'warning', className: 'paused' },
|
|
||||||
7: { label: '已停止', type: 'info', className: 'stopped' },
|
|
||||||
8: { label: '故障', type: 'danger', className: 'fault' },
|
|
||||||
9: { label: '急停', type: 'danger', className: 'emergency' },
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolveStatus = value => AGV_RUNTIME_STATUS[Number(value)] || AGV_RUNTIME_STATUS[0]
|
|
||||||
|
|
||||||
export const agvRuntimeStatusLabel = value => resolveStatus(value).label
|
|
||||||
export const agvRuntimeStatusType = value => resolveStatus(value).type
|
|
||||||
export const agvRuntimeStatusClass = value => resolveStatus(value).className
|
|
||||||
@ -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">{{ robotStatus[item.status] }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -122,7 +122,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, nextTick } from "vue";
|
import { computed, onMounted, nextTick } from "vue";
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import MapCanvas from "../MapCanvas.vue";
|
import MapCanvas from "../MapCanvas.vue";
|
||||||
import SvgIcon from "@/components/SvgIcon";
|
import SvgIcon from "@/components/SvgIcon";
|
||||||
@ -134,7 +134,6 @@ 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'
|
|
||||||
|
|
||||||
const robotList = ref([])
|
const robotList = ref([])
|
||||||
const robotDevices = ref([])
|
const robotDevices = ref([])
|
||||||
@ -148,18 +147,15 @@ const loadRobotDevices = async (robotId) => {
|
|||||||
robotDevices.value = Array.isArray(response.data) ? response.data : []
|
robotDevices.value = Array.isArray(response.data) ? response.data : []
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchRobotList = async (refreshDevices = true) => {
|
const fetchRobotList = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getRobotList({
|
const res = await getRobotList({
|
||||||
robotType: 2,
|
robotType: 2,
|
||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const currentRobotId = activeBotData.value.robotId
|
|
||||||
robotList.value = res.rows
|
robotList.value = res.rows
|
||||||
const currentIndex = robotList.value.findIndex(item => item.robotId === currentRobotId)
|
activeBotData.value = robotList.value[0] || {}
|
||||||
activeBot.value = currentIndex >= 0 ? currentIndex : 0
|
await loadRobotDevices(activeBotData.value.robotId)
|
||||||
activeBotData.value = robotList.value[activeBot.value] || {}
|
|
||||||
if (refreshDevices) await loadRobotDevices(activeBotData.value.robotId)
|
|
||||||
} else {
|
} else {
|
||||||
console.error('获取机器人列表失败:', res.message)
|
console.error('获取机器人列表失败:', res.message)
|
||||||
}
|
}
|
||||||
@ -168,6 +164,13 @@ const fetchRobotList = async (refreshDevices = true) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const robotStatus = {
|
||||||
|
0: '在线',
|
||||||
|
1: '离线',
|
||||||
|
2: '充电中',
|
||||||
|
3: '巡检中'
|
||||||
|
}
|
||||||
|
|
||||||
const activeBot = ref(0)
|
const activeBot = ref(0)
|
||||||
const activeBotData = ref({})
|
const activeBotData = ref({})
|
||||||
const changeBot = async (index) => {
|
const changeBot = async (index) => {
|
||||||
@ -304,17 +307,11 @@ const stop = async () => {
|
|||||||
|
|
||||||
const videoUrl = ref('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
|
const videoUrl = ref('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')
|
||||||
|
|
||||||
let robotRefreshTimer
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchRobotList()
|
fetchRobotList()
|
||||||
robotRefreshTimer = window.setInterval(() => {
|
|
||||||
if (!document.hidden) fetchRobotList(false)
|
|
||||||
}, 5000)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.clearInterval(robotRefreshTimer)
|
|
||||||
if (animationId.value) {
|
if (animationId.value) {
|
||||||
clearInterval(animationId.value)
|
clearInterval(animationId.value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -382,13 +382,6 @@ const addRobot = (id, name,x, y, angleRad, color) => {
|
|||||||
applicationState.robots.push(robot);
|
applicationState.robots.push(robot);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseRobotPosition = (currentPosition) => {
|
|
||||||
if (!currentPosition) return null
|
|
||||||
const values = String(currentPosition).split(',').map(Number)
|
|
||||||
if (values.length < 3 || values.some(value => !Number.isFinite(value))) return null
|
|
||||||
return values
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveRobot = (robot, dx, dy, dtheta = 0) => {
|
const moveRobot = (robot, dx, dy, dtheta = 0) => {
|
||||||
robot.x += dx;
|
robot.x += dx;
|
||||||
robot.y += dy;
|
robot.y += dy;
|
||||||
@ -405,9 +398,7 @@ onMounted(() => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
bindEvent()
|
bindEvent()
|
||||||
props.robotList.forEach(item => {
|
props.robotList.forEach(item => {
|
||||||
const position = parseRobotPosition(item.currentPosition)
|
const [x, y, angle] = item.currentPosition.split(',')
|
||||||
if (!position) return
|
|
||||||
const [x, y, angle] = position
|
|
||||||
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
||||||
})
|
})
|
||||||
}, 300)
|
}, 300)
|
||||||
@ -421,14 +412,13 @@ watch(() => props.robotList,
|
|||||||
if (newVal.length > 0) {
|
if (newVal.length > 0) {
|
||||||
const ids = applicationState.robots.map(r => r.id);
|
const ids = applicationState.robots.map(r => r.id);
|
||||||
props.robotList.forEach(item => {
|
props.robotList.forEach(item => {
|
||||||
const position = parseRobotPosition(item.currentPosition)
|
|
||||||
if (!position) return
|
|
||||||
const [x, y, angle] = position
|
|
||||||
if (!ids.includes(item.id)) {
|
if (!ids.includes(item.id)) {
|
||||||
|
const [x, y, angle] = item.currentPosition.split(',')
|
||||||
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
|
||||||
} else {
|
} else {
|
||||||
applicationState.robots.forEach(robot => {
|
applicationState.robots.forEach(robot => {
|
||||||
if (robot.id === item.id) {
|
if (robot.id === item.id) {
|
||||||
|
const [x, y, angle] = item.currentPosition.split(',')
|
||||||
// moveRobot(robot, parseFloat(x) - robot.x, parseFloat(y) - robot.y, parseFloat(angle) - robot.angle)
|
// moveRobot(robot, parseFloat(x) - robot.x, parseFloat(y) - robot.y, parseFloat(angle) - robot.angle)
|
||||||
robot.x = x
|
robot.x = x
|
||||||
robot.y = y
|
robot.y = y
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="title-box">
|
<div class="title-box">
|
||||||
<div><SvgIcon name="bot" :color="index === 0 ? '#00D4FF' : '#FFB300'" /></div>
|
<div><SvgIcon name="bot" :color="index === 0 ? '#00D4FF' : '#FFB300'" /></div>
|
||||||
<div class="title">{{ item.robotName }}</div>
|
<div class="title">{{ item.robotName }}</div>
|
||||||
<div class="state" :class="agvRuntimeStatusClass(item.status)">{{ agvRuntimeStatusLabel(item.status) }}</div>
|
<div class="state online">{{ robotStatus[item.status] }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<div class="item-box">
|
<div class="item-box">
|
||||||
@ -71,9 +71,12 @@
|
|||||||
<!-- <div class="split-line"></div> -->
|
<!-- <div class="split-line"></div> -->
|
||||||
<div class="alarm-container">
|
<div class="alarm-container">
|
||||||
<div class="container-title">告警记录</div>
|
<div class="container-title">告警记录</div>
|
||||||
<div class="alarm-box" v-for="item, index in 2">
|
<div class="alarm-box" v-for="item, index in alarmRecord">
|
||||||
<div class="title">#01 检测到异常噪声</div>
|
<div class="alarm-title" :class="item.resultStatus">
|
||||||
<div class="alarm-info">14:28:33 — 厂区A 东侧走廊</div>
|
<div class="title">{{ item.resultName }}</div>
|
||||||
|
<div class="status">{{ getOptionLabel(resultStatusOptions, item.resultStatus) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="alarm-info">{{ item.createTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -86,9 +89,15 @@ import MapCanvas from "./MapCanvas.vue";
|
|||||||
import { onMounted, onUnmounted } from "vue";
|
import { onMounted, onUnmounted } from "vue";
|
||||||
import { getRobotList } from '@/api/inspection/robot'
|
import { getRobotList } from '@/api/inspection/robot'
|
||||||
import { getRunTaskList } from '@/api/inspection/runTask'
|
import { getRunTaskList } from '@/api/inspection/runTask'
|
||||||
import { agvRuntimeStatusClass, agvRuntimeStatusLabel } from '@/utils/agvRuntimeStatus'
|
import { getInspectionResultList } from '@/api/inspection/result'
|
||||||
|
|
||||||
const robotList = ref([])
|
const robotList = ref([])
|
||||||
|
const robotStatus = {
|
||||||
|
"0": "在线",
|
||||||
|
"1": "离线",
|
||||||
|
"2": "充电中",
|
||||||
|
"3": "巡检中"
|
||||||
|
}
|
||||||
const getRobot = async () => {
|
const getRobot = async () => {
|
||||||
let robotType
|
let robotType
|
||||||
if (import.meta.env.VITE_INSPECTION_TYPE === 'inspection') {
|
if (import.meta.env.VITE_INSPECTION_TYPE === 'inspection') {
|
||||||
@ -118,7 +127,7 @@ const taskStatus = {
|
|||||||
}
|
}
|
||||||
const getRunningTask = async () => {
|
const getRunningTask = async () => {
|
||||||
let taskType
|
let taskType
|
||||||
if (import.meta.env.VITE_INSPECTION_TYPE === 'inspection') {
|
if (import.meta.env.VITE_INSPECTION_TYPE = 'inspection') {
|
||||||
taskType = '1'
|
taskType = '1'
|
||||||
} else {
|
} else {
|
||||||
taskType = '2'
|
taskType = '2'
|
||||||
@ -154,18 +163,31 @@ const centerCanvasView = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let robotRefreshTimer
|
const alarmRecord = ref([])
|
||||||
|
const resultStatusOptions = [
|
||||||
|
{ label: '待处理', value: 'PENDING' },
|
||||||
|
{ label: '正常', value: 'NORMAL' },
|
||||||
|
{ label: '异常', value: 'ABNORMAL' },
|
||||||
|
{ label: '识别失败', value: 'RECOGNIZE_FAILED' }
|
||||||
|
]
|
||||||
|
const getAlarmRecord = async () => {
|
||||||
|
const res = await getInspectionResultList({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10
|
||||||
|
})
|
||||||
|
if (res.code === 200) {
|
||||||
|
alarmRecord.value = res.rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOptionLabel = (options, value) => {
|
||||||
|
return options.find(item => item.value === value)?.label || value || '-'
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getRobot()
|
getRobot()
|
||||||
getRunningTask()
|
getRunningTask()
|
||||||
robotRefreshTimer = window.setInterval(() => {
|
getAlarmRecord()
|
||||||
if (!document.hidden) getRobot()
|
|
||||||
}, 5000)
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.clearInterval(robotRefreshTimer)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -226,31 +248,6 @@ onUnmounted(() => {
|
|||||||
background: #0f83;
|
background: #0f83;
|
||||||
color: #0f8;
|
color: #0f8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unknown,
|
|
||||||
.offline,
|
|
||||||
.stopped {
|
|
||||||
background: rgba(148, 163, 184, 0.2);
|
|
||||||
color: #cbd5e1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.manual,
|
|
||||||
.running {
|
|
||||||
background: rgba(0, 212, 255, 0.18);
|
|
||||||
color: #00d4ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.charging,
|
|
||||||
.paused {
|
|
||||||
background: rgba(255, 179, 0, 0.2);
|
|
||||||
color: #ffb300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fault,
|
|
||||||
.emergency {
|
|
||||||
background: rgba(255, 77, 79, 0.2);
|
|
||||||
color: #ff6b6d;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-box {
|
.info-box {
|
||||||
@ -414,13 +411,45 @@ onUnmounted(() => {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.alarm-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
color: #FF6B6B;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: Inter;
|
font-family: Inter;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 0 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.NORMAL {
|
||||||
|
color: #00D4FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ABNORMAL {
|
||||||
|
color: #FF6B6B;
|
||||||
|
}
|
||||||
|
|
||||||
|
.PENDING {
|
||||||
|
color: #8899BB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.RECOGNIZE_FAILED {
|
||||||
|
color: #FF6B6B;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.alarm-info {
|
.alarm-info {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@ -185,7 +185,6 @@ import { computed, getCurrentInstance, onBeforeUnmount, onMounted, reactive, ref
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { addRobot, deleteRobot, getRobotDevices, getRobotList, getRobotStatus, updateRobot } from '@/api/inspection/robot'
|
import { addRobot, deleteRobot, getRobotDevices, getRobotList, getRobotStatus, updateRobot } from '@/api/inspection/robot'
|
||||||
import { getMapList } from '@/api/inspection/map'
|
import { getMapList } from '@/api/inspection/map'
|
||||||
import { agvRuntimeStatusLabel, agvRuntimeStatusType } from '@/utils/agvRuntimeStatus'
|
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const { robot_type } = proxy.useDict('robot_type')
|
const { robot_type } = proxy.useDict('robot_type')
|
||||||
@ -257,8 +256,8 @@ async function loadDevices(showLoading = true) {
|
|||||||
try { const res = await getRobotDevices(activeRobot.value.id); devices.value = res.data || [] } finally { deviceLoading.value = false }
|
try { const res = await getRobotDevices(activeRobot.value.id); devices.value = res.data || [] } finally { deviceLoading.value = false }
|
||||||
}
|
}
|
||||||
function endpointText(row) { return row.ipAddress && row.port ? `${row.ipAddress}:${row.port}` : '等待连接后自动获取' }
|
function endpointText(row) { return row.ipAddress && row.port ? `${row.ipAddress}:${row.port}` : '等待连接后自动获取' }
|
||||||
const runtimeStatusLabel = agvRuntimeStatusLabel
|
function runtimeStatusLabel(value) { return ({ 0: '在线', 1: '离线', 2: '充电中', 3: '巡检中' })[value] || '未知' }
|
||||||
const runtimeStatusType = agvRuntimeStatusType
|
function runtimeStatusType(value) { return ({ 0: 'success', 1: 'info', 2: 'warning', 3: 'primary' })[value] || 'info' }
|
||||||
function hasBattery(row) { return row.batteryLevel !== null && row.batteryLevel !== undefined && row.batteryLevel !== '' }
|
function hasBattery(row) { return row.batteryLevel !== null && row.batteryLevel !== undefined && row.batteryLevel !== '' }
|
||||||
function normalizeBattery(value) { return Math.max(0, Math.min(100, Math.round(Number(value) || 0))) }
|
function normalizeBattery(value) { return Math.max(0, Math.min(100, Math.round(Number(value) || 0))) }
|
||||||
function batteryColor(value) {
|
function batteryColor(value) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user