feat: 拦截跳转

This commit is contained in:
zhanghao 2026-06-30 17:32:54 +08:00
parent ab98000ab1
commit 2d12fc3f89
12 changed files with 329 additions and 69 deletions

3
components.d.ts vendored
View File

@ -17,6 +17,8 @@ declare module 'vue' {
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
@ -34,6 +36,7 @@ declare module 'vue' {
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTag: typeof import('element-plus/es')['ElTag']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
IPlayer: typeof import('./src/components/IPlayer/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']

View File

@ -15,6 +15,7 @@
"@element-plus/icons-vue": "^2.3.2",
"@grpc/grpc-js": "^1.14.4",
"@grpc/proto-loader": "^0.8.1",
"autofit.js": "^3.2.8",
"concurrently": "^10.0.3",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
@ -27,7 +28,8 @@
"urdf-loader": "^0.12.6",
"vue": "^3.5.38",
"vue-router": "^5.1.0",
"xacro-parser": "^0.3.11"
"xacro-parser": "^0.3.11",
"xgplayer": "^3.0.24"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.7",

130
pnpm-lock.yaml generated
View File

@ -17,6 +17,9 @@ importers:
'@grpc/proto-loader':
specifier: ^0.8.1
version: 0.8.1
autofit.js:
specifier: ^3.2.8
version: 3.2.8
concurrently:
specifier: ^10.0.3
version: 10.0.3
@ -56,6 +59,9 @@ importers:
xacro-parser:
specifier: ^0.3.11
version: 0.3.11
xgplayer:
specifier: ^3.0.24
version: 3.0.24(core-js@3.49.0)
devDependencies:
'@vitejs/plugin-vue':
specifier: ^6.0.7
@ -586,6 +592,9 @@ packages:
engines: {node: '>= 4.5.0'}
hasBin: true
autofit.js@3.2.8:
resolution: {integrity: sha512-albZNwDIXvcRneEDyZLW3uAIOH0cUQG/TnCGQ7jpfnL0gPn/+1ZNVRuEz3ZuzZvVkQ4HQRplGHjUeMRtPNxjLQ==}
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@ -723,6 +732,9 @@ packages:
resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
engines: {node: '>=0.10.0'}
core-js@3.49.0:
resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==}
cors@2.8.6:
resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
engines: {node: '>= 0.10'}
@ -769,6 +781,13 @@ packages:
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
d@1.0.2:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'}
danmu.js@1.2.1:
resolution: {integrity: sha512-evDEImUBo94c846fC92K//Dzll8jXnZ3zKmYlQHwMzmvw6IW2IyjWL3Ew2SqEAzuqauFnDkwJEgZauu3uW/p1Q==}
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@ -828,6 +847,9 @@ packages:
defu@6.1.7:
resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
delegate@3.2.0:
resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
@ -943,6 +965,17 @@ packages:
resolution: {integrity: sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g==}
engines: {node: '>= 0.4'}
es5-ext@0.10.64:
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
engines: {node: '>=0.10'}
es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
es6-symbol@3.1.4:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'}
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@ -958,6 +991,10 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
esniff@2.0.1:
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
engines: {node: '>=0.10'}
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
@ -968,6 +1005,12 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
expand-brackets@2.1.4:
resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==}
engines: {node: '>=0.10.0'}
@ -983,6 +1026,9 @@ packages:
exsolve@1.1.0:
resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==}
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
@ -1594,6 +1640,9 @@ packages:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'}
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-addon-api@7.1.1:
resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
@ -2100,6 +2149,9 @@ packages:
resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==}
engines: {node: '>= 18'}
type@2.7.3:
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
@ -2324,6 +2376,16 @@ packages:
xacro-parser@0.3.11:
resolution: {integrity: sha512-zyRzHmf6/BySLZQP77zp6iEtdryq1g7tWtfwj/28GOPyf9ijtPvouivOAeaA/yAu0/Bwh20DtA4x+BrYiV6qKQ==}
xgplayer-subtitles@3.0.24:
resolution: {integrity: sha512-yrHROepD9kTGWiTSxBjh+TGaK9orQOHQ1GUxWFOkQzO8BLl/pcIAqqJkHiAoP0j+eU8VdIhpb55oJRIkTTWPsA==}
peerDependencies:
core-js: '>=3.12.1'
xgplayer@3.0.24:
resolution: {integrity: sha512-rK3hoJ+1Pbl9PUCHgeJv1GnOQF28BKLQFTBxdvi0pHsibJeXaDUf51SLFcgNVAPN15aDYcjJgaSf7LQ0RfEFPQ==}
peerDependencies:
core-js: '>=3.12.1'
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@ -2811,6 +2873,8 @@ snapshots:
atob@2.1.2: {}
autofit.js@3.2.8: {}
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.1.0
@ -2976,6 +3040,8 @@ snapshots:
copy-descriptor@0.1.1: {}
core-js@3.49.0: {}
cors@2.8.6:
dependencies:
object-assign: 4.1.1
@ -3035,6 +3101,15 @@ snapshots:
csstype@3.2.3: {}
d@1.0.2:
dependencies:
es5-ext: 0.10.64
type: 2.7.3
danmu.js@1.2.1:
dependencies:
event-emitter: 0.3.5
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@ -3092,6 +3167,8 @@ snapshots:
defu@6.1.7: {}
delegate@3.2.0: {}
depd@2.0.0: {}
detect-libc@2.1.2: {}
@ -3278,6 +3355,24 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
es5-ext@0.10.64:
dependencies:
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esniff: 2.0.1
next-tick: 1.1.0
es6-iterator@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-symbol: 3.1.4
es6-symbol@3.1.4:
dependencies:
d: 1.0.2
ext: 1.7.0
escalade@3.2.0: {}
escape-html@1.0.3: {}
@ -3286,6 +3381,13 @@ snapshots:
escape-string-regexp@5.0.0: {}
esniff@2.0.1:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
event-emitter: 0.3.5
type: 2.7.3
estree-walker@2.0.2: {}
estree-walker@3.0.3:
@ -3294,6 +3396,13 @@ snapshots:
etag@1.8.1: {}
event-emitter@0.3.5:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
eventemitter3@4.0.7: {}
expand-brackets@2.1.4:
dependencies:
debug: 2.6.9
@ -3343,6 +3452,10 @@ snapshots:
exsolve@1.1.0: {}
ext@1.7.0:
dependencies:
type: 2.7.3
extend-shallow@2.0.1:
dependencies:
is-extendable: 0.1.1
@ -3945,6 +4058,8 @@ snapshots:
negotiator@1.0.0: {}
next-tick@1.1.0: {}
node-addon-api@7.1.1:
optional: true
@ -4558,6 +4673,8 @@ snapshots:
media-typer: 1.1.0
mime-types: 3.0.2
type@2.7.3: {}
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
@ -4837,6 +4954,19 @@ snapshots:
yaml: 2.9.0
yargs: 17.7.3
xgplayer-subtitles@3.0.24(core-js@3.49.0):
dependencies:
core-js: 3.49.0
eventemitter3: 4.0.7
xgplayer@3.0.24(core-js@3.49.0):
dependencies:
core-js: 3.49.0
danmu.js: 1.2.1
delegate: 3.2.0
eventemitter3: 4.0.7
xgplayer-subtitles: 3.0.24(core-js@3.49.0)
y18n@5.0.8: {}
yaml@2.9.0: {}

View File

@ -56,6 +56,7 @@ const init = () => {
.xgplayer {
height: 100% !important;
padding-top: 0 !important;
}
}
</style>

View File

@ -1,11 +1,12 @@
import { createRouter, createWebHistory } from 'vue-router'
// 页面组件
import Home from '@/views/Home.vue'
import Address from '@/views/Address.vue'
const routes = [
{
path: '/',
redirect: '/home'
path: '/',e: 'Address',
component: Address
},
{
path: '/home',

82
src/views/Address.vue Normal file
View File

@ -0,0 +1,82 @@
<template>
<div class="page-container">
<div class="title">设备连接登录</div>
<div class="secondaryTitle">请输入IP和端口连接后进入上位机页面</div>
<div class="form">
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto">
<el-form-item label="" prop="ip">
<el-input v-model="ruleForm.ip" style="width: 240px" placeholder="请输入IP" >
<template #append>
<el-button @click="testConnect"></el-button>
</template>
</el-input>
<!-- <el-button @click="testConnect"></el-button> -->
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { getCurrentMapName } from '@/api/agv.js'
import { useRobotStore } from '@/stores/robot'
const router = useRouter()
const robotStore = useRobotStore()
const ruleFormRef = ref()
const ruleForm = ref({
ip: '',
port: 80
})
const rules = ref({
ip: [
{ required: true, message: '请输入机器人IP和端口', trigger: 'blur' }
],
})
const testConnect = async () => {
const valid = await ruleFormRef.value.validate();
if (valid) {
const result = await getCurrentMapName({
ip: robotStore.ip,
deviceId: VITE_DEVICE_ID,
})
if (result.code === 200) {
router.push({
path: '/home',
query: {
mapName: result.data.current_map
}
})
}
}
}
</script>
<style lang="scss" scoped>
.page-container {
width: 100%;
height: 100%;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
.title {
font-size: 40px;
font-weight: bold;
color: #000;
}
.secondaryTitle {
font-size: 14px;
color: #8f8f8f;
}
}
</style>

View File

@ -3,6 +3,7 @@
<el-container>
<el-header>
<div class="header-container">
<div class="back" @click="back">&lt;&nbsp;返回</div>
<div class="left">
<div class="date">
<div>{{ currentTime }}</div>
@ -16,14 +17,15 @@
<div class="btn-container">
<button class="nav-btn" :class="{ active: activePage === 'chassis' }" @click="handleBtn('chassis')">底盘控制</button>
<button class="nav-btn" :class="{ active: activePage === 'mechanicalArm' }" @click="handleBtn('mechanicalArm')">机械臂控制</button>
<button class="nav-btn" :class="{ active: activePage === 'manualTakeover' }" @click="handleBtn('manualTakeover')">相机</button>
<button class="nav-btn" :class="{ active: activePage === 'camera' }" @click="handleBtn('camera')">相机</button>
</div>
</div>
</div>
</el-header>
<el-main>
<Chassis v-if="activePage === 'chassis'" />
<Chassis :mapName="mapName" v-if="activePage === 'chassis'" />
<MechanicalArm v-if="activePage === 'mechanicalArm'" />
<Camera v-if="activePage === 'camera'" />
</el-main>
</el-container>
</div>
@ -31,6 +33,14 @@
<script setup>
import Chassis from './chassis/Chassis.vue';
import MechanicalArm from './arm/MechanicalArm.vue';
import Camera from './camera/index.vue'
import { useRoute, useRouter } from 'vue-router';
import autofit from 'autofit.js'
autofit.init()
const router = useRouter()
const route = useRoute()
const currentTime = ref('')
const weekText = ref('')
@ -63,15 +73,21 @@ const animateBinary = () => {
const activePage = ref('chassis')
const handleBtn = (page) => {
activePage.value = page
// emits("activePage", page);
}
const back = () => {
router.back()
}
const mapName = ref('')
let clockTimer, binaryTimer;
onMounted(() => {
updateClock();
clockTimer = setInterval(updateClock, 1000);
animateBinary()
binaryTimer = setInterval(animateBinary, 400);
mapName.value = route.query.mapName
})
onUnmounted(() => {
@ -100,6 +116,13 @@ onUnmounted(() => {
gap: 20px;
margin: 0 20px;
.back {
display: flex;
align-items: center;
justify-content: center;
color: #00c2ff;
cursor: pointer;
}
.left {
flex: 1;
@ -172,7 +195,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
font-family: 'Orbitron', monospace;
font-size: 10px;
font-size: 14px;
color: #00c2ff4d;
letter-spacing: 2px;
white-space: nowrap;

View File

@ -268,6 +268,11 @@ onMounted(() => {
border-radius: 5px;
background: #0a0b10;
&:hover {
border-color: #2a3f7a;
background: rgba(59, 130, 246, 0.031372549);
}
label {
width: 120px;
font-size: 16px;

View File

@ -13,6 +13,18 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { XacroAdapter } from '@/adapters/XacroAdapter.js'
import { fileNameMap } from './config'
const props = defineProps({
filePath: {
type: String,
default: '/inspection/elfin10/'
},
fileName: {
type: String,
default: 'elfin10.urdf.xacro'
}
})
const viewerContainer = ref(null);
@ -26,41 +38,32 @@ const initScene = () => {
const container = viewerContainer.value;
const width = container.clientWidth || 800;
const height = container.clientHeight || 600;
scene = new THREE.Scene();
scene.background = new THREE.Color('#060a12');
camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
camera.position.set(2, 2, 3);
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 1000);
camera.position.set(0, 0, 4);
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(width, height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
container.appendChild(renderer.domElement);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.1;
controls.target.set(0, 0.5, 0);
controls.update();
const ambient = new THREE.AmbientLight(0x404060, 0.6);
const ambient = new THREE.AmbientLight(0xffffff, 0.6)
scene.add(ambient);
const main = new THREE.DirectionalLight(0xffffff, 1.0);
main.position.set(5, 10, 7);
main.castShadow = true;
scene.add(main);
const fill = new THREE.DirectionalLight(0x8888ff, 0.4);
fill.position.set(-5, 0, 5);
scene.add(fill);
const rim = new THREE.DirectionalLight(0xffffff, 0.3);
rim.position.set(0, -5, 5);
scene.add(rim);
// const grid = new THREE.GridHelper(3, 20, 0x444466, 0x333355);
// grid.position.y = -0.5;
// scene.add(grid);
};
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position.set(5, 10, 7);
directionalLight.castShadow = true;
scene.add(directionalLight);
};
// ============ ============
const updateJoint = (jointName, angle) => {
@ -94,28 +97,16 @@ const resetJoints = () => {
const fileMap = new Map()
const loadFiles = async () => {
const fileNames = [
'elfin10.urdf.xacro',
'elfin10_gazebo.xacro',
'elfin10_transmission.xacro',
'meshes/elfin10/elfin_base.STL',
'meshes/elfin10/elfin_end_link.STL',
'meshes/elfin10/elfin_link1.STL',
'meshes/elfin10/elfin_link2.STL',
'meshes/elfin10/elfin_link3.STL',
'meshes/elfin10/elfin_link4.STL',
'meshes/elfin10/elfin_link5.STL',
'meshes/elfin10/elfin_link6.STL'
]
const fileNames = fileNameMap[props.filePath]
const fetchPromises = fileNames.map(async (name) => {
const url = `/inspection/elfin10/${name}`
const url = `${props.filePath}${name}`
const response = await fetch(url)
const blob = await response.blob()
return new File([blob], name, { type: blob.type })
})
const fileList = await Promise.all(fetchPromises)
fileList.forEach(item => {
fileMap.set('elfin10/' + item.name, item);
fileMap.set(props.filePath + item.name, item);
})
}
@ -123,19 +114,21 @@ const currentModel = ref()
let robotInstance = null; // URDFRobot
const loadRobot = async () => {
const xacroUrl = `/inspection/elfin10/elfin10.urdf.xacro`;
const xacroUrl = `${props.filePath}${props.fileName}`;
const response = await fetch(xacroUrl);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const xacroContent = await response.text();
const file = fileMap.get('elfin10/elfin10.urdf.xacro')
const model = await XacroAdapter.parse(xacroContent, file.name, fileMap, file);
const robot = model.threeObject; // URDFRobot
const file = fileMap.get(xacroUrl)
let model
if (props.fileName.split('.').pop() === 'xacro') {
model = await XacroAdapter.parse(xacroContent, file.name, fileMap, file);
}
const robot = model.threeObject;
//
scene.add(robot); // robot.scene robot
scene.add(robot);
robot.rotation.x = -Math.PI / 2;
currentModel.value = model

15
src/views/arm/config.js Normal file
View File

@ -0,0 +1,15 @@
export const fileNameMap = {
'/inspection/elfin10/': [
'elfin10.urdf.xacro',
'elfin10_gazebo.xacro',
'elfin10_transmission.xacro',
'meshes/elfin10/elfin_base.STL',
'meshes/elfin10/elfin_end_link.STL',
'meshes/elfin10/elfin_link1.STL',
'meshes/elfin10/elfin_link2.STL',
'meshes/elfin10/elfin_link3.STL',
'meshes/elfin10/elfin_link4.STL',
'meshes/elfin10/elfin_link5.STL',
'meshes/elfin10/elfin_link6.STL'
]
}

View File

@ -0,0 +1,14 @@
<template>
<div class="page-container">
<IPlayer />
</div>
</template>
<script setup>
import IPlayer from '@/components/IPlayer/index.vue'
</script>
<style lang="scss" scoped>
.page-container {
width: 100%;
height: 100%;
}
</style>

View File

@ -131,9 +131,16 @@
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
import { ZoomIn, ZoomOut, Location } from '@element-plus/icons-vue'
import { useRobotStore } from '@/stores/robot'
import { getCurrentMapName, moveRobot, stopRobot } from '@/api/agv.js'
import { moveRobot, stopRobot } from '@/api/agv.js'
import MapCanvas from './MapCanvas.vue'
const props = defineProps({
mapName: {
type: String,
default: ''
}
})
const VITE_DEVICE_ID = import.meta.env.VITE_DEVICE_ID
const robotStore = useRobotStore()
@ -193,22 +200,6 @@ function onRelease() {
})
}
const mapName = ref('')
const getRobotCurrentMapName = async () => {
const result = await getCurrentMapName({
ip: robotStore.ip,
deviceId: VITE_DEVICE_ID,
})
if (result.code === 200) {
mapName.value = result.data.current_map
}
}
onMounted(() => {
getRobotCurrentMapName()
})
onBeforeUnmount(() => { })
</script>
<style lang="scss" scoped>