feat: 调整登录界面
This commit is contained in:
parent
10a62c51d2
commit
0c52f8b909
3
.env
3
.env
@ -7,3 +7,6 @@ VITE_SERVICE_PORT=5175
|
||||
# /home/cmvr/zh/mkcert 目录中的证书文件名
|
||||
HTTPS_CERT_FILENAME=192.168.0.224+2.pem
|
||||
HTTPS_KEY_FILENAME=192.168.0.224+2-key.pem
|
||||
|
||||
VITE_VIDEO_SERVER_HOST=http://192.168.0.224
|
||||
VITE_TERMINAL_ID=c2f8a06826baf03843925c1a2a13bcfd
|
||||
2
components.d.ts
vendored
2
components.d.ts
vendored
@ -20,7 +20,9 @@ declare module 'vue' {
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
|
||||
@ -226,7 +226,7 @@ app.post('/api/agv/getCurrentMap', async (req, res) => {
|
||||
|
||||
// 机器人运动控制
|
||||
app.post('/api/agv/moveRobot', async (req, res) => {
|
||||
const grpcClient = setVelocity(req.body.ip)
|
||||
const grpcClient = createAGVGrpcClient(req.body.ip)
|
||||
const request = {
|
||||
header: {
|
||||
device_id: req.body.deviceId || 'agv_src1100'
|
||||
|
||||
@ -4,6 +4,7 @@ import { defineStore } from 'pinia'
|
||||
export const useRobotStore = defineStore('robot', {
|
||||
state: () => ({
|
||||
ip: '192.168.0.28:50052',
|
||||
robotType: 'inspection',
|
||||
agvDeviceId:'src1100',
|
||||
almDeviceId: 'huayan_arm',
|
||||
spkDeviceId: 'spk1',
|
||||
@ -32,6 +33,9 @@ export const useRobotStore = defineStore('robot', {
|
||||
setIp(str) {
|
||||
this.ip = str
|
||||
},
|
||||
setRobotType(str) {
|
||||
this.robotType = str
|
||||
},
|
||||
setAgvDeviceId(str) {
|
||||
this.agvDeviceId = str
|
||||
},
|
||||
|
||||
@ -9,7 +9,13 @@
|
||||
<el-form-item label="IP和端口" prop="ip">
|
||||
<el-input v-model="ruleForm.ip" placeholder="请输入IP和端口" />
|
||||
</el-form-item>
|
||||
<el-form-item label="底盘设备ID" prop="agvDeviceId">
|
||||
<el-form-item label="机器人类型" prop="robotType">
|
||||
<el-select v-model="ruleForm.robotType" placeholder="请选择机器人类型">
|
||||
<el-option label="巡检机器人" value="inspection"></el-option>
|
||||
<el-option label="讲解机器人" value="explanation"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="底盘设备ID" prop="agvDeviceId">
|
||||
<el-input v-model="ruleForm.agvDeviceId" placeholder="请输入底盘设备ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="机械臂设备ID" prop="almDeviceId">
|
||||
@ -23,7 +29,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="相机设备ID" prop="cameraDeviceId">
|
||||
<el-input v-model="ruleForm.cameraDeviceId" placeholder="请输入相机设备ID" />
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
<el-button :loading="loading" @click="testConnect" class="connect">进入上位机控制页面</el-button>
|
||||
</div>
|
||||
@ -46,32 +52,36 @@ const loading = ref(false)
|
||||
const ruleFormRef = ref()
|
||||
const ruleForm = ref({
|
||||
ip: '',
|
||||
agvDeviceId:'src1100',
|
||||
almDeviceId: 'huayan_arm',
|
||||
spkDeviceId: 'spk1',
|
||||
micDeviceId: 'mic1',
|
||||
cameraDeviceId: 'real_cam1'
|
||||
robotType: 'inspection',
|
||||
// agvDeviceId:'src1100',
|
||||
// almDeviceId: 'huayan_arm',
|
||||
// spkDeviceId: 'spk1',
|
||||
// micDeviceId: 'mic1',
|
||||
// cameraDeviceId: 'real_cam1'
|
||||
})
|
||||
|
||||
const rules = ref({
|
||||
ip: [
|
||||
{ required: true, message: '请输入机器人IP和端口', trigger: 'blur' }
|
||||
],
|
||||
agvDeviceId: [
|
||||
{ required: true, message: '请输入底盘设备ID', trigger: 'blur' }
|
||||
],
|
||||
almDeviceId: [
|
||||
{ required: true, message: '请输入机械臂设备ID', trigger: 'blur' }
|
||||
],
|
||||
spkDeviceId: [
|
||||
{ required: true, message: '请输入扬声器设备ID', trigger: 'blur' }
|
||||
],
|
||||
micDeviceId: [
|
||||
{ required: true, message: '请输入麦克风设备ID', trigger: 'blur' }
|
||||
],
|
||||
cameraDeviceId: [
|
||||
{ required: true, message: '请输入相机设备ID', trigger: 'blur' }
|
||||
robotType: [
|
||||
{ required: true, message: '请选择机器人类型', trigger: 'blur' }
|
||||
],
|
||||
// agvDeviceId: [
|
||||
// { required: true, message: '请输入底盘设备ID', trigger: 'blur' }
|
||||
// ],
|
||||
// almDeviceId: [
|
||||
// { required: true, message: '请输入机械臂设备ID', trigger: 'blur' }
|
||||
// ],
|
||||
// spkDeviceId: [
|
||||
// { required: true, message: '请输入扬声器设备ID', trigger: 'blur' }
|
||||
// ],
|
||||
// micDeviceId: [
|
||||
// { required: true, message: '请输入麦克风设备ID', trigger: 'blur' }
|
||||
// ],
|
||||
// cameraDeviceId: [
|
||||
// { required: true, message: '请输入相机设备ID', trigger: 'blur' }
|
||||
// ],
|
||||
})
|
||||
|
||||
const testConnect = async () => {
|
||||
@ -79,16 +89,26 @@ const testConnect = async () => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
robotStore.setIp(ruleForm.value.ip)
|
||||
robotStore.setAgvDeviceId(ruleForm.value.agvDeviceId)
|
||||
robotStore.setAlmDeviceId(ruleForm.value.almDeviceId)
|
||||
robotStore.setSpkDeviceId(ruleForm.value.spkDeviceId)
|
||||
robotStore.setMicDeviceId(ruleForm.value.micDeviceId)
|
||||
robotStore.setCameraDeviceId(ruleForm.value.cameraDeviceId)
|
||||
robotStore.setRobotType(ruleForm.value.robotType)
|
||||
if (ruleForm.value.robotType === 'inspection') {
|
||||
robotStore.setAgvDeviceId('src1100')
|
||||
robotStore.setAlmDeviceId('huayan_arm')
|
||||
robotStore.setSpkDeviceId('spk1')
|
||||
robotStore.setMicDeviceId('mic1')
|
||||
robotStore.setCameraDeviceId('real_cam1')
|
||||
} else if (ruleForm.value.robotType === 'explanation') {
|
||||
robotStore.setAgvDeviceId('src1100')
|
||||
robotStore.setAlmDeviceId('huayan_arm')
|
||||
robotStore.setSpkDeviceId('spk1')
|
||||
robotStore.setMicDeviceId('mic1')
|
||||
robotStore.setCameraDeviceId('real_cam1')
|
||||
}
|
||||
|
||||
// const result = await getRuntimeState({
|
||||
// ip: robotStore.ip,
|
||||
// deviceId: ruleForm.value.agvDeviceId
|
||||
// })
|
||||
// loading.value = false
|
||||
loading.value = false
|
||||
// if (result.code === 200) {
|
||||
// robotStore.setPosition(result.data.pose)
|
||||
// robotStore.setBattery(result.data.battery)
|
||||
@ -150,12 +170,23 @@ const testConnect = async () => {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
height: 40px;
|
||||
// 避免 iPad Safari 聚焦小字号输入框时自动缩放页面。
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
:deep(.el-select__wrapper) {
|
||||
height: 40px;
|
||||
// 避免 iPad Safari 聚焦小字号输入框时自动缩放页面。
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.connect {
|
||||
width: 340px;
|
||||
height: 50px;
|
||||
|
||||
@ -97,16 +97,16 @@
|
||||
<div class="axis-label x">X</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">前后平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('x', '-', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('x', '+', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -119,16 +119,16 @@
|
||||
<div class="axis-label y">Y</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">左右平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('y', '-', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('y', '+', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -141,16 +141,16 @@
|
||||
<div class="axis-label z">Z</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">上下平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('z', '-', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('z', '+', 'end'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -177,16 +177,16 @@
|
||||
<div class="axis-label x">X</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">前后平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('x', '-', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('x', '+', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -199,16 +199,16 @@
|
||||
<div class="axis-label y">Y</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">左右平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('y', '-', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('y', '+', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -221,16 +221,16 @@
|
||||
<div class="axis-label z">Z</div>
|
||||
<div class="axis-slider-wrap">
|
||||
<div class="axis-name">上下平移</div>
|
||||
<div>
|
||||
<div class="axis-control-buttons">
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('z', '-', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<el-button class="press-control" type="primary" circle @pointerdown="startPointerControl($event, () => move('z', '+', 'posture'))"
|
||||
@pointerup="endPointerControl" @pointercancel="endPointerControl">
|
||||
<el-icon size="24">
|
||||
<el-icon size="32">
|
||||
<CirclePlus />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
@ -254,7 +254,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import UrdfView from './UrdfView.vue'
|
||||
import { getPoseApi, getJointStateApi, moveJApi, torqueOnApi, speedJApi, stopMotionApi, speedLApi } from '@/api/arm'
|
||||
import { Remove, CirclePlus } from '@element-plus/icons-vue'
|
||||
@ -497,6 +497,9 @@ onUnmounted(() => {
|
||||
touch-action: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
min-width: 48px;
|
||||
min-height: 48px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
// 主体三栏布局
|
||||
@ -589,6 +592,19 @@ onUnmounted(() => {
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: $color-background-base;
|
||||
box-shadow: 0 0 0 1px $color-accent-border inset;
|
||||
min-height: 48px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__prepend),
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.press-control {
|
||||
width: 52px;
|
||||
min-height: 48px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -610,10 +626,10 @@ onUnmounted(() => {
|
||||
border-left: 1px solid $color-accent-border;
|
||||
|
||||
.controller {
|
||||
margin-bottom: 60px;
|
||||
margin-bottom: 48px;
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@ -628,6 +644,7 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 68px;
|
||||
padding: 10px 14px;
|
||||
background: $color-background-base;
|
||||
border: 1px solid $color-accent-border;
|
||||
@ -640,13 +657,13 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.axis-label {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@ -671,11 +688,37 @@ onUnmounted(() => {
|
||||
|
||||
|
||||
.axis-slider-wrap {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
|
||||
.axis-name {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
z-index: 1;
|
||||
font-size: 16px;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.axis-control-buttons {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
|
||||
.press-control {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -683,6 +726,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
.speed-container {
|
||||
min-height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@ -690,6 +734,7 @@ onUnmounted(() => {
|
||||
.label,
|
||||
.proportion {
|
||||
width: 100px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -698,6 +743,15 @@ onUnmounted(() => {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
:deep(.el-slider) {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
:deep(.el-slider__button) {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.speed-tooltip {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 7px);
|
||||
|
||||
@ -14,15 +14,20 @@ import VoiceConversation from './VoiceConversation.vue';
|
||||
import { computed } from 'vue';
|
||||
import { useRobotStore } from '@/stores/robot';
|
||||
|
||||
const VIDEO_SERVER_HOST = import.meta.env.VITE_VIDEO_SERVER_HOST || 'http://localhost:8080/'
|
||||
const TerminalId = import.meta.env.VITE_TERMINAL_ID || 'c2f8a06826baf03843925c1a2a13bcfd'
|
||||
|
||||
const robotStore = useRobotStore()
|
||||
const videoUrl = computed(() => {
|
||||
if (!robotStore.ip || !robotStore.cameraDeviceId) return ''
|
||||
const params = new URLSearchParams({
|
||||
ip: robotStore.ip,
|
||||
deviceId: robotStore.cameraDeviceId
|
||||
})
|
||||
return `/api/camera/video?${params}`
|
||||
})
|
||||
const videoUrl = `${VIDEO_SERVER_HOST}/api/edge/camera/rgb-stream/public?terminalId=${TerminalId}&deviceId=${robotStore.cameraDeviceId}`
|
||||
|
||||
// const videoUrl = computed(() => {
|
||||
// if (!robotStore.ip || !robotStore.cameraDeviceId) return ''
|
||||
// const params = new URLSearchParams({
|
||||
// ip: robotStore.ip,
|
||||
// deviceId: robotStore.cameraDeviceId
|
||||
// })
|
||||
// return `/api/camera/video?${params}`
|
||||
// })
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.page-container {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user