整体代码完善

This commit is contained in:
BianLzhaoMin 2025-06-27 11:23:33 +08:00
parent c51c2437fa
commit 260dc6b942
22 changed files with 1241 additions and 942 deletions

View File

@ -2,29 +2,50 @@
* 缓存对象管理
* 防止对象过多
*/
import StorageS from 'storages-js';
import StorageS from 'storages-js'
/**
* 所有实例
* 公共管理
* */
const allStorage = {};
const allStorage = {}
function createS(key, value) {
if (!allStorage[key]) {
allStorage[key] = new StorageS(key, value, { modelName: 'local' });
allStorage[key] = new StorageS(key, value, { modelName: 'local' })
}
return allStorage[key];
return allStorage[key]
}
/** 保存用户的基本信息 */
const userStorage = (value) => {
return createS('user-container', value);
};
return createS('user-container', value)
}
const fullScreenStorage = (value) => {
return createS('full-screen-container', value);
};
return createS('full-screen-container', value)
}
/** 保存公共的 token 信息 */
const userTokenStorage = (value) => {
return createS('token-container', value)
}
/** 保存机器人的信息 */
const userRobotStorage = (value) => {
return createS('robot-container', value)
}
/** 保存地图信息 */
const userMapStorage = (value) => {
return createS('map-container', value)
}
/** 保存机器人实时点位信息 */
const userRobotPointsStorage = (value) => {
return createS('robot-points-container', value)
}
export default {
userStorage,
fullScreenStorage,
};
userTokenStorage,
userRobotStorage,
userMapStorage,
userRobotPointsStorage,
}

View File

@ -8,3 +8,8 @@ export const getTokenApi = (data) => {
export const getDeviceInfoApi = (data) => {
return service.post('/api/robot/sbdUser/getDeviceList', data)
}
// 操作机器人行动接口
export const handleRobotActionApi = (data) => {
return service.post('/api/robot/instruct/sedXml', data)
}

View File

@ -68,6 +68,6 @@ const onHandleCloseModal = () => {
.modal-content {
flex: 1;
// height: calc(100% - 40px);
height: calc(100% - 40px);
}
</style>

View File

@ -2,17 +2,18 @@
<!-- 视频播放器 Flv格式视频 -->
<video
:id="videoId"
class="video-player"
autoplay
controls
muted
@timeupdate="progress($event)"
style="width: 100%; height: 100%; border-radius: 12px"
style="border-radius: 12px"
/>
</template>
<script setup>
import flv from 'flv.js'
import { ref, watch, nextTick } from 'vue'
import { ref, watch, nextTick, onBeforeUnmount } from 'vue'
let flvPlayerList = []
let replayCount = 0
@ -105,11 +106,15 @@ const progress = (e) => {
}
}
onBeforeUnmount(() => {
stopvideo()
})
watch(
() => dfp.cameraNode,
() => {
errorMsg.value = ''
console.log(dfp.cameraNode, 'dfp.cameraNode')
if (dfp.cameraNode.steamURL) {
playUrl.value =
dfp.cameraNode.steamURL +
@ -119,9 +124,6 @@ watch(
dfp.cameraNode.idx +
'&stream=' +
dfp.cameraNode.stream
// console.log(dfp.cameraNode.steamURL, 'playUrl.value')
console.log(playUrl.value, 'playUrl.value')
playvideo()
} else {
stopvideo()
@ -133,10 +135,10 @@ watch(
</script>
<style scoped>
#video {
.video-player {
width: 100%;
height: 100%;
object-fit: fill;
background-color: black;
}
</style>

View File

@ -1,3 +0,0 @@
import { getTokenApi } from '@/api/home'
export function useScale(appRef) {}

View File

@ -4,10 +4,13 @@
*/
import axios from 'axios'
import { userDataStore } from '@/store/user'
// import { useMessage } from 'naive-ui'
import router from '@/router'
import { createDiscreteApi } from 'naive-ui'
const { message } = createDiscreteApi(['message'])
let baseApiURL = import.meta.env.VITE_APP_baseApiURL //api原始链接
const timeout = 13000 //api请求超时时间
const timeout = 10000 //api请求超时时间
export const service = axios.create({
//可创建多个 axios实例
@ -66,8 +69,9 @@ service.interceptors.response.use(
return Promise.reject(data)
}
},
() => {
(error) => {
//数据请求发生错误
message.error('请求发生错误,请稍后再试')
return Promise.reject({
msg: '请求发生错误,请稍后再试',
})

61
src/store/robot.js Normal file
View File

@ -0,0 +1,61 @@
/** 机器人数据 */
import { defineStore } from 'pinia'
import allStorage from '@/action/storageManage'
export const useRobotDataStore = defineStore('useRobotDataStore', {
state: () => {
const userTokenStorage = allStorage.userTokenStorage() // 获取缓存
const userStorage = allStorage.userRobotStorage() // 获取缓存
const userMapStorage = allStorage.userMapStorage() // 获取缓存
const userRobotPointsStorage = allStorage.userRobotPointsStorage() // 获取缓存
let tokenInfo = userTokenStorage.value
if (typeof tokenInfo !== 'object') {
tokenInfo = {}
}
let robotInfo = userStorage.value
if (typeof robotInfo !== 'object') {
robotInfo = {}
}
let mapInfo = userMapStorage.value
if (typeof mapInfo !== 'object') {
mapInfo = {}
}
let robotPoints = userRobotPointsStorage.value
if (typeof robotPoints !== 'object') {
robotPoints = {}
}
return {
tokenInfo: tokenInfo || {}, // 设备token
robotInfo: robotInfo || {}, // 机器人信息
mapInfo: mapInfo || {}, // 地图信息
robotPoints: {}, // 机器人点位信息
}
},
getters: {},
actions: {
setTokenInfo(value) {
this.tokenInfo = value || {}
/** 存入缓存 */
const tokenStorage = allStorage.userTokenStorage()
tokenStorage.value = value
},
setRobotInfo(value) {
this.robotInfo = value || {}
/** 存入缓存 */
const robotStorage = allStorage.userRobotStorage()
robotStorage.value = value
},
setMapInfo(value) {
this.mapInfo = value || {}
/** 存入缓存 */
const mapStorage = allStorage.userMapStorage()
mapStorage.value = value
},
setRobotPoints(value) {
this.robotPoints = value || {}
},
},
})

View File

@ -85,4 +85,16 @@
.n-form-item .n-form-item-label {
color: #fff;
}
.n-base-select-menu .n-base-select-option.n-base-select-option--selected.n-base-select-option--pending::before {
background-color: #072148;
}
.n-base-select-menu .n-base-select-option.n-base-select-option--pending::before {
background-color: #2f5789;
}
.n-base-selection:not(.n-base-selection--disabled).n-base-selection--active .n-base-selection-label {
background-color: #1d3861
}

87
src/utils/getRobotInfo.js Normal file
View File

@ -0,0 +1,87 @@
import { initLoginApi } from '@/utils/initLogin'
import { getDeviceInfoApi, handleRobotActionApi } from '@/api/home'
import { useRobotDataStore } from '@/store/robot'
const robotData = useRobotDataStore()
// 获取机器人token
export const getRobotTokenFn = async () => {
if (!robotData.tokenInfo.deviceToken) {
const loginParams = {
address: '112.31.70.193',
port: '9988',
user: 'bns3',
password: 'Bns@admin**',
epid: 'system',
bfix: 1,
}
const res = await initLoginApi(loginParams)
robotData.setTokenInfo({
deviceToken: res.data.token,
})
return res.data.token
} else {
return robotData.tokenInfo.deviceToken
}
}
// 获取设备信息
export const getRobotDeviceListFn = async () => {
if (!robotData.robotInfo.puId) {
const { data: res } = await getDeviceInfoApi()
if (res?.data?.length > 0) {
const deviceInfo = res.data[0]
robotData.setRobotInfo({
devName: deviceInfo.devName,
puId: deviceInfo.puId,
})
return {
devName: deviceInfo.devName,
puId: deviceInfo.puId,
}
}
} else {
return robotData.robotInfo
}
}
// 获取地图信息
export const getRobotMapInfoFn = async (puId) => {
if (!robotData.mapInfo.mapBase64) {
const { data: res } = await handleRobotActionApi({
puId,
type: 4,
})
if (res.code === 200) {
const { Data, Height, Width } = res.data
const mapInfo = {
mapBase64: 'data:image/png;base64,' + Data,
mapWidth: Width,
mapHeight: Height,
}
robotData.setMapInfo(mapInfo)
return mapInfo
}
} else {
return robotData.mapInfo
}
}
// 获取机器人实时定位信息
export const getRobotPointsInfoFn = async (puId) => {
if (!robotData.robotPoints.Robot_x && !robotData.robotPoints.Robot_y) {
const { data: res } = await handleRobotActionApi({
puId,
type: 2,
})
if (res.code === 200) {
const pointsInfo = {
Robot_x: res?.data?.Robot_x,
Robot_y: res?.data?.Robot_y,
}
robotData.setRobotPoints(pointsInfo)
return pointsInfo
}
} else {
return robotData.robotPoints
}
}

View File

@ -2,17 +2,15 @@
<!-- 中一 ---- 自巡检视角 -->
<div class="center-one child-container">
<div class="view-title" v-if="!fullScreenVisible">自巡检视角</div>
<div class="video-container">
<!-- <video controls style="width: 100%; height: 100%; border-radius: 12px" autoplay>
<source src="@/assets/video/测试.mp4" type="video/mp4" autoplay />
</video> -->
<FlvPlayer :cameraNode="cameraNode_2" :videoId="props.videoId" />
<div class="video-container" ref="videoContainerRef">
<FlvPlayer :cameraNode="cameraNode_2" :videoId="props.videoId" ref="flvPlayerRef" />
</div>
</div>
</template>
<script setup>
import FlvPlayer from '@/components/FlvPlayer/index.vue'
import { nextTick } from 'vue'
const props = defineProps({
cameraNode_2: {
type: Object,
@ -20,13 +18,33 @@ const props = defineProps({
},
videoId: {
type: String,
default: 'video-5',
default: '',
},
fullScreenVisible: {
type: Boolean,
default: false,
},
})
const videoContainerRef = ref(null)
const flvPlayerRef = ref(null)
watch(
() => props.fullScreenVisible,
(newVal) => {
if (!newVal) {
nextTick(() => {
console.log(
flvPlayerRef.value,
'newValnewValnewValnewValnewValnewValnewValnewValnewValnewValnewVal',
)
})
}
},
{
immediate: true,
},
)
</script>
<style lang="scss" scoped>
@ -50,6 +68,7 @@ const props = defineProps({
}
> .video-container {
width: 100%;
flex: 1; /* 新增:占据剩余空间 */
min-height: 0; /* 新增:允许内容压缩 */
position: relative; /* 新增为video定位提供基准 */
@ -59,8 +78,8 @@ const props = defineProps({
position: absolute; /* 新增:绝对定位填满容器 */
top: 0;
left: 0;
width: 100%;
height: 100%;
bottom: 0;
right: 0;
object-fit: cover; /* 保持视频比例 */
}
}

View File

@ -6,14 +6,19 @@
<div class="more-btn" @click="onHandleMore">更多</div>
</n-flex>
<div class="marquee-outer">
<div class="marquee-outer" ref="marqueeOuterRef">
<div class="marquee-container" ref="marqueeContainer">
<div class="marquee-track" :style="{ width: trackWidth }">
<div class="marquee-item" v-for="item in items" :key="item.id">
<div
class="marquee-item"
v-for="item in items"
:key="item.id"
:style="{ width: imgWidth + 'px' }"
>
<n-image
width="100%"
:width="imgWidth"
:height="imgHeight"
:src="item.image"
object-fit="cover"
class="item-image"
/>
<div class="marquee-item-title">途径点{{ item.id }}</div>
@ -23,9 +28,16 @@
</div>
</div>
<!-- 克隆元素实现无缝循环 -->
<div class="marquee-item" v-for="item in items" :key="`clone-${item.id}`">
<div
class="marquee-item"
v-for="item in items"
:key="`clone-${item.id}`"
v-if="items.length > 4"
:style="{ width: imgWidth + 'px' }"
>
<n-image
width="100%"
:width="imgWidth"
:height="imgHeight"
:src="item.image"
object-fit="cover"
class="item-image"
@ -84,12 +96,18 @@
</n-form>
<!-- 内容区域 -->
<div class="table-container">
<div class="table-container" ref="tableContainerRef">
<!-- 分页 -->
<div v-for="item in 7" :key="item" class="table-item">
<div
v-for="item in 7"
:key="item"
class="table-item"
:style="{ width: tableItemWidth + 'px' }"
>
<n-image
width="100%"
:width="tableItemWidth"
height="170"
object-fit="cover"
class="item-image"
src="https://img1.baidu.com/it/u=3294211986,2810142789&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
@ -114,10 +132,12 @@
</n-modal>
</template>
<script setup>
<script setup scoped>
import TitleBackground from '@/components/TitleBackground/index.vue'
import { ref, onMounted, onUnmounted } from 'vue'
import imgSrc from '@/assets/demo.png'
const morePanelVisible = ref(false)
const searchForm = ref({})
const marqueeContainer = ref(null)
@ -126,7 +146,11 @@ const imageHeight = ref('0px')
const itemMargin = 10 // 10px
const page = ref(1)
const pageSize = ref(10)
const itemCount = ref(100)
const imgHeight = ref(0)
const imgWidth = ref(0)
const tableItemWidth = ref(0)
const marqueeOuterRef = ref(null)
const tableContainerRef = ref(null)
//
const items = ref([
@ -134,7 +158,7 @@ const items = ref([
id: 1,
time: '14:23:56',
status: 'arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
image: imgSrc,
},
{
id: 2,
@ -143,44 +167,26 @@ const items = ref([
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
{
id: 3,
time: '16:45:33',
id: 1,
time: '14:23:56',
status: 'arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
image: imgSrc,
},
{
id: 4,
time: '17:30:11',
id: 2,
time: '15:10:22',
status: 'not-arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
{
id: 5,
time: '18:15:44',
id: 1,
time: '14:23:56',
status: 'arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
image: imgSrc,
},
{
id: 6,
time: '19:20:05',
status: 'not-arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
{
id: 7,
time: '19:20:05',
status: 'not-arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
{
id: 8,
time: '19:20:05',
status: 'not-arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
{
id: 9,
time: '19:20:05',
id: 2,
time: '15:10:22',
status: 'not-arrived',
image: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
},
@ -215,11 +221,25 @@ const setupMarquee = () => {
//
const onHandleMore = () => {
morePanelVisible.value = true
nextTick(() => {
// setupMarquee()
const tableContainer = tableContainerRef.value
tableItemWidth.value = (tableContainer.clientWidth - 40) / 4
console.log(tableContainer.clientWidth, 'tableContainer')
})
}
onMounted(() => {
setupMarquee()
window.addEventListener('resize', setupMarquee)
nextTick(() => {
const container = marqueeContainer.value
imgWidth.value = (container.clientWidth - 40) / 4
imgHeight.value = `${container.clientHeight * 0.68}`
})
})
onUnmounted(() => {
@ -242,6 +262,7 @@ onUnmounted(() => {
.marquee-outer {
flex: 1;
width: 100%;
overflow: hidden;
margin-top: 12px;
}
@ -281,13 +302,13 @@ onUnmounted(() => {
flex-shrink: 0;
/* 确保Naive UI的n-image组件完全填充 */
:deep(.n-image) {
.n-image {
width: 100%;
display: block;
img {
width: 100%;
height: v-bind(imageHeight);
height: v-bind(imgHeight);
object-fit: cover;
}
}
@ -346,7 +367,7 @@ onUnmounted(() => {
.more-panel-card {
width: 80%;
height: 80vh;
// height: 80vh;
background: url('@/assets/home-imgs/modal-bg.png') no-repeat center center;
background-size: 100% 100%;
}
@ -358,15 +379,15 @@ onUnmounted(() => {
}
.table-container {
height: 75%;
// height: 75%;
display: flex;
flex-wrap: wrap;
color: #fff;
.table-item {
flex-shrink: 0;
width: calc((100% - 30px) / 4);
height: calc((100% - 20px) / 2);
// width: calc((100% - 30px) / 4);
// height: calc((100% - 20px) / 2);
margin-right: 10px;
margin-bottom: 10px;
border-radius: 5px;
@ -376,23 +397,23 @@ onUnmounted(() => {
justify-content: space-between;
overflow: hidden;
.item-image {
// width: 100%;
height: 150px;
flex-shrink: 0;
// .item-image {
// // width: 100%;
// height: 150px;
// flex-shrink: 0;
/* 确保Naive UI的n-image组件完全填充 */
:deep(.n-image) {
// width: 100%;
display: block;
// /* Naive UIn-image */
// :deep(.n-image) {
// // width: 100%;
// display: block;
img {
// width: 100%;
// height: v-bind(imageHeight);
object-fit: cover;
}
}
}
// img {
// // width: 100%;
// // height: v-bind(imageHeight);
// object-fit: cover;
// }
// }
// }
.table-item-title {
width: 100%;

View File

@ -3,25 +3,25 @@
<div class="control-deck child-container">
<!-- 第一行 -->
<n-grid :cols="10">
<n-grid-item :span="4">
<n-grid-item :span="5">
<div class="row-1-item">摄像头</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="3" v-if="false">
<div class="row-1-item">升降杆</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="5">
<div class="row-1-item">底盘</div>
</n-grid-item>
</n-grid>
<!-- 第二行 -->
<n-grid :cols="10">
<n-grid-item :span="4">
<n-grid-item :span="5">
<div class="row-2-item">
<div>速度</div>
<div>30</div>
</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="3" v-if="false">
<div class="row-2-item">
<div>高度</div>
<div>
@ -29,7 +29,7 @@
</div>
</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="5">
<div class="row-2-item">
<div>速度</div>
<div>30</div>
@ -38,7 +38,7 @@
</n-grid>
<!-- 第三行 -->
<n-grid :cols="10">
<n-grid-item :span="4">
<n-grid-item :span="5">
<div class="row-3-item-1">
<!-- 上下左右控制按钮 -->
<img
@ -98,7 +98,7 @@
</div>
</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="3" v-if="false">
<div class="row-3-item-2" ref="container">
<!-- 上下滑动调节 -->
<span
@ -109,19 +109,40 @@
/>
</div>
</n-grid-item>
<n-grid-item :span="3">
<n-grid-item :span="5">
<div class="row-3-item-3">
<!-- 上下左右控制按钮 -->
<img class="arrow-top" src="@/assets/home-imgs/control-2-arrow.png" alt="" />
<img class="arrow-right" src="@/assets/home-imgs/control-2-arrow.png" alt="" />
<img class="arrow-bottom" src="@/assets/home-imgs/control-2-arrow.png" alt="" />
<img class="arrow-left" src="@/assets/home-imgs/control-2-arrow.png" alt="" />
<img
@click="handleChangeRobot('5')"
class="arrow-top"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('8')"
class="arrow-right"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('6')"
class="arrow-bottom"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('7')"
class="arrow-left"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<div class="row-3-item-1-center">
<img
class="center-icon"
src="@/assets/home-imgs/control-2-start.png"
alt=""
@click="handleChangeRobot('9')"
/>
</div>
</div>
@ -240,7 +261,7 @@
<!-- 第六行 -->
<n-grid :cols="10" class="row-6">
<n-grid-item :span="4">
<div class="row-6-item">回桩充电</div>
<div class="row-6-item" @click="handleChangeRobot(10)">回桩充电</div>
</n-grid-item>
<n-grid-item :span="3">
<div class="row-6-item-1">
@ -255,7 +276,13 @@
import { ref, onMounted } from 'vue'
import { changeDeviceCameraApi, stopDeviceCameraApi } from '@/utils/initLogin'
import { handleRobotActionApi } from '@/api/home'
import { useRobotDataStore } from '@/store/robot'
import { useMessage } from 'naive-ui'
import { debounce } from 'lodash'
const robotData = useRobotDataStore()
const message = useMessage()
const upDownHeight = ref(30)
const container = ref(null)
const draggable = ref(null)
@ -320,10 +347,10 @@ const stopDrag = () => {
}
onMounted(() => {
const containerHeight = container.value.offsetHeight
const draggableHeight = draggable.value.offsetHeight
const maxTop = containerHeight - draggableHeight - 20
currentTop.value = maxTop * (1 - upDownHeight.value / 100)
// const containerHeight = container.value.offsetHeight
// const draggableHeight = draggable.value.offsetHeight
// const maxTop = containerHeight - draggableHeight - 20
// currentTop.value = maxTop * (1 - upDownHeight.value / 100)
})
const handleChange1 = (e) => {
@ -345,18 +372,26 @@ const formatTooltip = (value) => {
return `${value}%`
}
const handleChangeCamera = async (direction) => {
//
const handleChangeCamera = debounce(async (motion) => {
if (!robotData.robotInfo?.puId) {
message.error('当前机器人未连接', {
duration: 1000,
})
return
}
// console.log(direction)
const res = await changeDeviceCameraApi({
token: localStorage.getItem('token'),
puid: '201115200268437643',
idx: 1,
motion: direction,
motion,
})
console.log(res, '调整位置---')
}
}, 1000)
//
const handleStopCamera = async () => {
const res = await stopDeviceCameraApi({
token: localStorage.getItem('token'),
@ -366,6 +401,32 @@ const handleStopCamera = async () => {
console.log(res, '停止位置---')
}
//
const handleChangeRobot = debounce(async (type) => {
// type 5 6 退 7 8
if (!robotData.robotInfo?.puId) {
message.error('当前机器人未连接', {
duration: 1000,
})
return
}
const params = {
puId: robotData.robotInfo?.puId,
type,
}
console.log(params, 'params---')
const res = await handleRobotActionApi(params)
console.log(res, '操控机器人---')
}, 1000)
//
const handleStopRobot = async () => {
console.log('停止机器人')
}
</script>
<style lang="scss" scoped>
.control-deck {

View File

@ -31,36 +31,46 @@
</div>
</div>
<!-- 预置位配置 -->
<!-- 预置位配置弹框 -->
<n-modal v-model:show="presetSettingVisible">
<PresetSetting
v-if="showModal === 1"
@onHandleCloseModal="onHandleCloseModal"
@onHandleAddMarker="onHandleAddMarker"
:presetSettingVisible="presetSettingVisible"
/>
<InspectionTask
v-if="showModal === 2"
@onHandleCloseModal="onHandleCloseModal"
@onHandleAddInspectionTask="onHandleAddInspectionTask"
/>
<div>
<PresetSetting
:markerInfoNew="markerInfoNew"
v-if="presetSettingVisible"
@onHandleAddMarker="onHandleAddMarker"
@onHandleCloseModal="onHandleCloseSettingModal"
/>
</div>
</n-modal>
<!-- 新增巡视任务 -->
<n-modal v-model:show="addInspectionTaskVisible">
<AddOrEditForm
v-if="addInspectionTaskVisible"
@onHandleCloseModalInner="onHandleCloseModalInner"
/>
</n-modal>
<!-- 新增预置点位 -->
<n-modal v-model:show="addMarkerVisible">
<AddOrEditMarkerForm
v-if="addMarkerVisible"
:markerInfo="markerInfo"
@onHandleCloseAddModal="onHandleCloseAddModal"
/>
<div>
<AddOrEditMarkerForm
v-if="addMarkerVisible"
:markerInfo="markerInfo"
@onHandleConfirm="onHandleConfirm"
@onHandleCloseAddMarkerModal="onHandleCloseAddMarkerModal"
/>
</div>
</n-modal>
<n-modal v-model:show="inspectionTaskVisible">
<div>
<InspectionTask
v-if="inspectionTaskVisible"
@onHandleCloseModal="onHandleCloseInspectionModal"
@onHandleAddInspectionTask="onHandleAddInspectionTask"
/>
</div>
</n-modal>
<n-modal v-model:show="addInspectionTaskVisible">
<div>
<AddOrEditForm
v-if="addInspectionTaskVisible"
@onHandleCloseModalInner="onHandleCloseModalInner"
/>
</div>
</n-modal>
</template>
@ -72,11 +82,12 @@ import AddOrEditForm from './modal-content/add-or-edit-form.vue'
import AddOrEditMarkerForm from './modal-content/add-or-edit-marker-form.vue'
import FlvPlayer from '@/components/FlvPlayer/index.vue'
const presetSettingVisible = ref(false)
const addInspectionTaskVisible = ref(false)
const addMarkerVisible = ref(false)
const showModal = ref(1)
const presetSettingVisible = ref(false) //
const addMarkerVisible = ref(false) //
const inspectionTaskVisible = ref(false) //
const addInspectionTaskVisible = ref(false) //
const markerInfo = ref({}) //
const markerInfoNew = ref({}) //
const props = defineProps({
fullScreenVisible: {
@ -103,70 +114,80 @@ const emits = defineEmits([
'onHandleChangeView',
])
//
// ----------------------------
// 1
const onHandlePresetSetting = () => {
showModal.value = 1
presetSettingVisible.value = true
}
//
const onHandleCloseModal = () => {
showModal.value = null
presetSettingVisible.value = false
}
//
// 2
const onHandleInspectionTask = () => {
showModal.value = 2
presetSettingVisible.value = true
inspectionTaskVisible.value = true
}
//
const onHandleAddInspectionTask = () => {
addInspectionTaskVisible.value = true
}
//
const onHandleCloseModalInner = () => {
addInspectionTaskVisible.value = false
}
//
const onHandleAddMarker = (info) => {
markerInfo.value = info
addMarkerVisible.value = true
}
//
const onHandleCloseAddModal = () => {
addMarkerVisible.value = false
}
//
// 3
const onHandleOperationPanel = () => {
emits('onHandleOperationPanel', true)
}
//
// 4
const onHandleOpenFullScreen = () => {
emits('onHandleFullScreenToggle', true)
}
// 退
// 退 5
const onHandleBackFullScreen = () => {
emits('onHandleFullScreenToggle', false)
}
//
// 6
const onHandleChangeView = () => {
emits('onHandleChangeView')
}
//
const onHandleCloseSettingModal = () => {
presetSettingVisible.value = false
}
//
const onHandleConfirm = (info) => {
markerInfoNew.value = info
addMarkerVisible.value = false
}
//
const onHandleAddInspectionTask = () => {
addInspectionTaskVisible.value = true
}
//
const onHandleCloseInspectionModal = () => {
inspectionTaskVisible.value = false
}
//
const onHandleCloseModalInner = () => {
addInspectionTaskVisible.value = false
}
//
const onHandleAddMarker = (info) => {
markerInfo.value = info
addMarkerVisible.value = true
}
//
const onHandleCloseAddMarkerModal = () => {
addMarkerVisible.value = false
}
</script>
<style lang="scss" scoped>
.left-one {
display: flex; /* 新增 */
flex-direction: column; /* 新增 */
height: 100%; /* 确保容器有高度 */
// height: 100%; /* */
.btns {
// width: 90px;

View File

@ -5,20 +5,17 @@
<div class="map-container" ref="mapContainerRef">
<svg ref="svgMapRef" class="svg-map-container" :width="svgWidth" :height="svgHeight">
<!-- 图片宽高 100% 跟随 SVG -->
<image
href="@/assets/demo.png"
:href="mapInfo.mapBase64"
width="100%"
height="100%"
preserveAspectRatio="none"
/>
<!-- 标记的点位 -->
<circle
v-for="(point, index) in devicePoints"
:key="index"
:cx="point.x * scale + offsetX / scale"
:cy="point.y * scale + offsetY / scale"
:cx="point.x * xScale"
:cy="point.y * yScale"
r="8"
fill="red"
/>
@ -28,23 +25,54 @@
</template>
<script setup>
import { ref, nextTick } from 'vue'
import { ref, nextTick, onMounted } from 'vue'
import TitleBackground from '@/components/TitleBackground/index.vue'
const mapTitle = ref('巡检地图')
const svgWidth = ref(0)
const svgHeight = ref(0)
const devicePoints = ref([{ x: 100, y: 100 }])
const scale = ref(1)
const offsetX = ref(0)
const offsetY = ref(0)
import { getRobotDeviceListFn, getRobotMapInfoFn, getRobotPointsInfoFn } from '@/utils/getRobotInfo'
const mapTitle = ref('巡检地图') //
const svgMapRef = ref(null) // svg
const svgWidth = ref(0) // svg
const svgHeight = ref(0) // svg
const xScale = ref(1) // x
const yScale = ref(1) // y
const devicePoints = ref([]) //
const mapInfo = ref({}) //
// map-containersvg
const mapContainerRef = ref(null)
onMounted(() => {
//
const calculateScale = (x, y) => {
const widthRatio = svgWidth.value / x
const heightRatio = svgHeight.value / y
xScale.value = widthRatio
yScale.value = heightRatio
}
//
const markPoints = (Robot_x, Robot_y) => {
console.log(Robot_x, Robot_y, 'Robot_x, Robot_y')
const svgRect = svgMapRef.value.getBoundingClientRect()
const clientY = svgHeight.value - yScale.value * Robot_y + svgRect.top
const logicalY1 = (clientY - svgRect.top) / yScale.value
devicePoints.value.push({ x: Robot_x, y: logicalY1 })
}
onMounted(async () => {
nextTick(() => {
svgWidth.value = mapContainerRef.value.clientWidth
svgHeight.value = mapContainerRef.value.clientHeight
})
//
const deviceInfo = await getRobotDeviceListFn()
//
mapInfo.value = await getRobotMapInfoFn(deviceInfo?.puId)
//
calculateScale(mapInfo.value?.mapWidth, mapInfo.value?.mapHeight)
//
const pointsInfo = await getRobotPointsInfoFn(deviceInfo?.puId)
//
markPoints(pointsInfo?.Robot_x, pointsInfo?.Robot_y)
})
</script>
@ -56,17 +84,12 @@ onMounted(() => {
.map-container {
flex: 1;
border-radius: 12px;
background-color: #000;
// background-color: #000;
position: relative;
.svg-map-container {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
// overflow: hidden;
}
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<!-- 新增或编辑弹框 -->
<DialogModal
:width="`80%`"
:width="`80vw`"
:modalTitle="addOrEditTitle"
@onHandleCloseModal="onHandleCloseModalInner"
>

View File

@ -2,108 +2,159 @@
<DialogModal
@onHandleCloseModal="onHandleCloseAddModal"
:modalTitle="`${markerParams.type}预置点位`"
:width="`50%`"
:width="`120vh`"
:height="`90vh`"
>
<n-form
ref="addOrEditFormRef"
size="small"
label-placement="left"
style="margin-top: 10px"
label-width="140"
>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="点位序号:">
<span style="color: #fff">
{{ markerParams.markerIndex + 1 }}
</span>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="点位名称:" prop="markerName">
<n-input
v-model:value="markerParams.markerName"
placeholder="点位名称"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<div style="display: flex; flex-direction: column; height: 100%">
<n-form
ref="addOrEditFormRef"
size="small"
label-placement="left"
style="margin-top: 10px"
label-width="140"
>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="点位序号:">
<span style="color: #fff">
{{ markerParams.markerIndex + 1 }}
</span>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="点位名称:" prop="markerName">
<n-input
v-model:value="markerParams.markerName"
placeholder="点位名称"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="6">
<n-form-item label="位置:"> </n-form-item>
</n-gi>
<n-gi :span="9">
<n-form-item label="x" prop="markerX">
<n-input
v-model:value="markerParams.markerX"
placeholder="x坐标"
clearable
/>
</n-form-item>
</n-gi>
<n-gi :span="9">
<n-form-item label="y" prop="markerY">
<n-input
v-model:value="markerParams.markerY"
placeholder="y坐标"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="角度:" prop="markerAngle">
<n-input
v-model:value="markerParams.markerAngle"
placeholder="角度"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="6">
<n-form-item label="位置:"> </n-form-item>
</n-gi>
<n-gi :span="9">
<n-form-item label="x" prop="xCount">
<n-input
type="text"
clearable
placeholder="x坐标"
:allow-input="onlyAllowNumber"
v-model:value.trim="markerParams.xCount"
/>
</n-form-item>
</n-gi>
<n-gi :span="9">
<n-form-item label="y" prop="yCount">
<n-input
clearable
type="text"
placeholder="y坐标"
:allow-input="onlyAllowNumber"
v-model:value.trim="markerParams.yCount"
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="角度:" prop="markerAngle">
<n-input
v-model:value="markerParams.markerAngle"
placeholder="角度"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="摄像头预置位:" prop="markerPreset">
<n-input
v-model:value="markerParams.markerPreset"
placeholder="摄像头预置位"
clearable
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-form-item label="摄像头预置位:" prop="markerPreset">
<!-- <n-input
v-model:value="markerParams.markerPreset"
placeholder="摄像头预置位"
clearable
/> -->
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-flex justify="end">
<n-button type="info" style="margin-right: 10px"> 确认 </n-button>
<n-button type="info"> 取消 </n-button>
</n-flex>
</n-gi>
</n-grid>
</n-form>
<n-select
:options="presetOptions"
placeholder="请选择摄像头预置位"
v-model:value="markerParams.markerPreset"
/>
</n-form-item>
</n-gi>
</n-grid>
<n-grid x-gap="24" :cols="24">
<n-gi :span="24">
<n-flex justify="end">
<n-button
type="info"
style="margin-right: 10px"
@click="onHandleConfirm"
>
确认
</n-button>
<n-button color="#6E90A9" @click="onHandleCloseAddModal">
取消
</n-button>
</n-flex>
</n-gi>
</n-grid>
</n-form>
<n-flex justify="space-between" style="flex: 1; margin-top: 10px">
<div class="left-box" style="width: 49%">
<!-- 放置video -->
<FlvPlayer />
</div>
<div class="right-box" style="width: 46%">
<!-- 放置操控面板 -->
<ControlDeck :deviceToken="deviceToken" :deviceInfo="deviceInfo" />
</div>
</n-flex>
</div>
</DialogModal>
</template>
<script setup>
import DialogModal from '@/components/DialogModal/index.vue'
import { watch } from 'vue'
import FlvPlayer from '@/components/FlvPlayer/index.vue'
import ControlDeck from './control-deck.vue'
import { watch, ref, onMounted } from 'vue'
import { getRobotTokenFn, getRobotDeviceListFn } from '@/utils/getRobotInfo'
const emits = defineEmits(['onHandleCloseAddModal'])
const deviceToken = ref('')
const deviceInfo = ref({})
const emits = defineEmits(['onHandleCloseAddMarkerModal', 'onHandleConfirm'])
const presetOptions = ref([
{
label: '正前',
value: 1,
},
{
label: '正右',
value: 2,
},
])
const markerParams = ref({
type: '新增', // /
markerIndex: '', //
markerX: '', // x
markerY: '', // y
markerY1: '', // y1
markerName: '', //
markerAngle: '', //
markerPreset: '', //
xCount: '', //
yCount: '', //
})
const props = defineProps({
markerInfo: {
@ -112,22 +163,37 @@ const props = defineProps({
},
})
const onHandleCloseAddModal = () => {
emits('onHandleCloseAddModal')
emits('onHandleCloseAddMarkerModal')
}
//
const onHandleConfirm = () => {
emits('onHandleConfirm', markerParams.value)
}
const onlyAllowNumber = (value) => !value || /^\d+$/.test(value)
watch(
() => props.markerInfo,
(newVal) => {
markerParams.value.type = newVal?.type
markerParams.value.markerIndex = newVal?.markerIndex
markerParams.value.markerX = Math.floor(newVal?.markerX)
markerParams.value.markerY = Math.floor(newVal?.markerY)
markerParams.value.markerX = Math.ceil(newVal?.markerX).toString()
markerParams.value.markerY = Math.ceil(newVal?.markerY).toString()
markerParams.value.markerY1 = newVal?.markerY1
markerParams.value.markerName = newVal?.markerName
markerParams.value.markerAngle = newVal?.markerAngle
markerParams.value.markerPreset = newVal?.markerPreset
markerParams.value.xCount = Math.ceil(newVal?.xCount).toString()
markerParams.value.yCount = Math.ceil(newVal?.yCount).toString()
},
{
immediate: true,
},
)
onMounted(async () => {
deviceToken.value = await getRobotTokenFn()
deviceInfo.value = await getRobotDeviceListFn()
})
</script>

View File

@ -0,0 +1,352 @@
<template>
<!-- 机器人操控面板 -->
<div class="control-deck">
<!-- 第一行 -->
<n-grid :cols="24">
<n-grid-item :span="12">
<div class="row-3-item-1">
<!-- 上下左右控制按钮 -->
<img
class="arrow-top hand-direction"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
@click="handleChangeCamera('TurnUp')"
/>
<img
class="arrow-right hand-direction"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
@click="handleChangeCamera('TurnRight')"
/>
<img
class="arrow-bottom hand-direction"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
@click="handleChangeCamera('TurnDown')"
/>
<img
class="arrow-left hand-direction"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
@click="handleChangeCamera('TurnLeft')"
/>
<!-- 中间的按钮 -->
<div class="row-3-item-1-center" @click="handleStopCamera">
<img
alt=""
class="center-icon"
:src="isStopLeft ? startImg : stopImg"
@click="handleChangeRobot('9')"
/>
</div>
<!-- 描述文字 -->
<div class="text-top description-text">正前</div>
<div class="text-bottom description-text">正后</div>
<div class="text-left description-text">正左</div>
<div class="text-right description-text">正右</div>
<!-- 增加减少按钮 -->
<div class="add-reduce-btn">
<span>缩放</span>
<img
style="margin-left: 20px; transform: rotate(-90deg)"
src="@/assets/home-imgs/control-2-add.png"
@click="handleChangeCamera('ZoomIn')"
/>
<img
style="margin-left: 50px; transform: rotate(-90deg)"
src="@/assets/home-imgs/control-2-reduce.png"
@click="handleChangeCamera('ZoomOut')"
/>
</div>
</div>
</n-grid-item>
<n-grid-item :span="12">
<div class="row-3-item-3">
<!-- 上下左右控制按钮 -->
<img
@click="handleChangeRobot('5')"
class="arrow-top"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('8')"
class="arrow-right"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('6')"
class="arrow-bottom"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<img
@click="handleChangeRobot('7')"
class="arrow-left"
src="@/assets/home-imgs/control-2-arrow.png"
alt=""
/>
<div class="row-3-item-1-center">
<img
class="center-icon"
:src="isStopRight ? startImg : stopImg"
@click="handleChangeRobot('9')"
/>
</div>
</div>
</n-grid-item>
</n-grid>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { changeDeviceCameraApi, stopDeviceCameraApi } from '@/utils/initLogin'
import { handleRobotActionApi } from '@/api/home'
import { useRobotDataStore } from '@/store/robot'
import { useMessage } from 'naive-ui'
import { debounce } from 'lodash'
import stopImg from '@/assets/home-imgs/control-2-stop.png'
import startImg from '@/assets/home-imgs/control-2-start.png'
const robotData = useRobotDataStore()
const message = useMessage()
const isStopLeft = ref(false)
const isStopRight = ref(false)
const props = defineProps({
deviceToken: {
type: String,
default: '',
},
deviceInfo: {
type: Object,
default: () => {},
},
})
//
const handleChangeCamera = debounce(async (motion) => {
if (!robotData.robotInfo?.puId) {
message.error('当前机器人未连接', {
duration: 1000,
})
return
}
const res = await changeDeviceCameraApi({
token: props.deviceToken,
puid: props.deviceInfo.puId,
idx: 1,
motion,
})
console.log(res, '调整上方的摄像头位置---')
}, 1000)
//
const handleStopCamera = async () => {
const res = await stopDeviceCameraApi({
token: props.deviceToken,
puid: props.deviceInfo.puId,
idx: 1,
})
console.log(res, '停止位置---')
}
//
const handleChangeRobot = debounce(async (type) => {
// type 5 6 退 7 8 9
if (!robotData.robotInfo?.puId) {
message.error('当前机器人未连接', {
duration: 1000,
})
return
}
const params = {
puId: robotData.robotInfo?.puId,
type,
}
const { data: res } = await handleRobotActionApi(params)
if (res.code == 200) {
if (type == '9') {
isStopRight.value = false
} else {
isStopRight.value = true
}
}
}, 600)
onMounted(async () => {})
</script>
<style lang="scss" scoped>
.control-deck {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
background-color: rgba(0, 112, 190, 0.3);
color: #fff;
}
.row-3-item-1 {
margin-right: 20px !important;
}
.row-3-item-1,
.row-3-item-3 {
width: 120px;
height: 120px;
margin: 40px auto 0;
position: relative;
background: url('@/assets/home-imgs/control-2-round.png') no-repeat center center;
background-size: 100% 100%;
> img {
width: 24px;
height: 26px;
cursor: pointer;
object-fit: contain;
}
.arrow-top {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%) rotate(-90deg);
}
.arrow-right {
position: absolute;
top: 50%;
right: 8px;
transform: translateY(-50%);
}
.arrow-bottom {
position: absolute;
bottom: 6px;
left: 50%;
transform: translateX(-50%) rotate(90deg);
}
.arrow-left {
position: absolute;
top: 50%;
left: 8px;
transform: translateY(-50%) rotate(-180deg);
}
.row-3-item-1-center {
width: 18px;
height: 18px;
position: absolute;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
transform: translate(-50%, -50%) rotate(45deg);
border: 2px solid #7fc0ff;
border-radius: 4px;
background-color: #2f78bf;
cursor: pointer;
> img {
width: 9px;
height: 9px;
object-fit: contain;
transform: rotate(-45deg);
}
}
//
.description-text {
position: absolute;
font-size: 12px;
}
.text-top {
left: 50%;
top: -40px;
transform: translateX(-50%);
}
.text-bottom {
left: 50%;
bottom: -40px;
transform: translateX(-50%);
}
.text-top,
.text-bottom {
width: 36px;
height: 22px;
border: 1px solid #7fc0ff;
border-radius: 4px;
text-align: center;
line-height: 22px;
}
.text-left {
left: -40px;
top: 50%;
transform: translateY(-50%);
}
.text-right {
right: -40px;
top: 50%;
transform: translateY(-50%);
}
.text-left,
.text-right {
height: 36px;
width: 22px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #7fc0ff;
border-radius: 4px;
// 使
writing-mode: vertical-rl;
text-orientation: upright;
}
.add-reduce-btn {
position: absolute;
right: 0;
top: -100px;
// height: 100px;
display: flex;
justify-content: space-between;
align-items: center;
// 90
span {
font-size: 13px;
width: 40px;
text-align: center;
color: #7fc0ff;
}
img {
width: 20px;
height: 5%;
object-fit: contain;
cursor: pointer;
}
}
}
.row-3-item-3 {
width: 130px;
height: 130px;
margin: 38px auto 0 !important;
> img {
width: 24px;
height: 26px;
cursor: pointer;
object-fit: contain;
}
}
</style>

View File

@ -4,7 +4,7 @@
@onHandleCloseModal="onHandleCloseModal"
:modalTitle="modalTitle"
:height="`90vh`"
:width="`90%`"
:width="`90vw`"
>
<!-- 巡视任务-->
<div class="inspection-task-container" ref="inspectionTaskContainer">

View File

@ -3,7 +3,7 @@
<DialogModal
@onHandleCloseModal="onHandleCloseModal"
:modalTitle="modalTitle"
:width="`70%`"
:width="`90vw`"
style="position: relative"
>
<!-- 平面图操作区域 -->
@ -11,6 +11,7 @@
class="plane-map-container"
ref="planeMapContainer"
:class="{ 'can-drag': canDrag() }"
:style="{ height: INITIAL_HEIGHT + 'px' }"
@mousemove="handleMouseMove"
>
<svg
@ -18,15 +19,15 @@
class="svg-map-container"
:width="svgWidth"
:height="svgHeight"
@wheel="handleWheel"
@wheel.passive="handleWheel"
@click="handleMapClick"
:style="{ transform: `translate(${offsetX}px, ${offsetY}px)` }"
>
<!-- 图片宽高 100% 跟随 SVG -->
<image
href="@/assets/demo.png"
width="100%"
height="100%"
:href="mapInfo.mapBase64"
preserveAspectRatio="none"
/>
@ -34,8 +35,8 @@
<circle
v-for="(point, index) in devicePoints"
:key="index"
:cx="point.x * scale + offsetX / scale"
:cy="point.y1 * scale + offsetY / scale"
:cx="point.markerX * scale + offsetX / scale"
:cy="point.markerY1 * scale + offsetY / scale"
r="8"
fill="red"
@click="handlePointClick(point, index)"
@ -46,7 +47,7 @@
<div v-if="showTooltip && mousePosition" class="coord-tooltip" :style="tooltipStyle">
<!-- 数据向下取整 -->
X: {{ Math.floor(mousePosition.x) }}, Y: {{ Math.floor(mousePosition.y) }}
X: {{ Math.floor(mousePosition.x) * 2 }}, Y: {{ Math.floor(mousePosition.y) * 2 }}
</div>
<div v-if="showContextMenu" class="context-menu" :style="contextMenuStyle" @click.stop>
@ -77,46 +78,34 @@
<script setup>
import DialogModal from '@/components/DialogModal/index.vue'
import { refThrottled, useMouseInElement } from '@vueuse/core'
import { ref, onMounted, nextTick, watch, onBeforeUnmount } from 'vue'
import { NIcon, useMessage } from 'naive-ui'
import { ref, onMounted, watch, onBeforeUnmount } from 'vue'
import { NIcon } from 'naive-ui'
import { throttle } from 'lodash'
import { TrashSharp, AddCircleOutline, RemoveCircleOutline } from '@vicons/ionicons5'
import demoImg from '@/assets/demo.png'
import { AddCircleOutline, RemoveCircleOutline } from '@vicons/ionicons5'
import { getRobotDeviceListFn, getRobotMapInfoFn } from '@/utils/getRobotInfo'
const itemRefs = ref([])
const setItemRef = (el, index) => {
if (el) {
itemRefs.value[index] = el
}
}
const emits = defineEmits(['onHandleCloseModal', 'onHandleAddMarker'])
const modalTitle = ref('预置位配置')
const mousePosition = ref(null)
const devicePoints = ref([])
const isPointClickStatus = ref(true)
const showAddModal = ref(false)
//
const showContextMenu = ref(false)
const contextMenuStyle = ref({})
const selectedPointIndex = ref(-1)
//
const containerSize = ref({ width: 0, height: 0 })
const planeMapContainer = ref(null)
const svgMapRef = ref(null)
const tooltipStyle = ref({})
const modalTitle = ref('预置位配置') //
const mousePosition = ref(null) //
const devicePoints = ref([]) //
const isPointClickStatus = ref(true) //
const mapInfo = ref({}) //
// SVG
const INITIAL_WIDTH = 800
const INITIAL_HEIGHT = 500
const INITIAL_WIDTH = ref(0)
const INITIAL_HEIGHT = ref(0)
// SVG
const svgWidth = ref(INITIAL_WIDTH)
const svgHeight = ref(INITIAL_HEIGHT)
const svgWidth = ref(INITIAL_WIDTH.value)
const svgHeight = ref(INITIAL_HEIGHT.value)
//
const isDragging = ref(false) //
const offsetX = ref(0) // X
const offsetY = ref(0) // Y
const startX = ref(0) // X
const startY = ref(0) // Y
const maxOffsetX1 = ref(0) // X
const maxOffsetY1 = ref(0) // Y
//
const scale = ref(1.0)
@ -126,6 +115,34 @@ const MIN_SCALE = 0.5 // 最小缩放比例
const MAX_SCALE = 3 //
const SCALE_STEP = 0.1 //
//
const showContextMenu = ref(false) //
const contextMenuStyle = ref({}) //
const selectedPointIndex = ref(-1) //
//
const planeMapContainer = ref(null) //
const svgMapRef = ref(null) // svg
const tooltipStyle = ref({}) //
const itemRefs = ref([]) //
const emits = defineEmits(['onHandleCloseModal', 'onHandleAddMarker']) // emits
// props
const props = defineProps({
markerInfoNew: {
type: Object,
default: () => {},
},
})
//
const setItemRef = (el, index) => {
if (el) {
itemRefs.value[index] = el
}
}
//
const adjustOffsetOnZoom = (e, newScale) => {
const container = planeMapContainer.value
@ -146,6 +163,7 @@ const adjustOffsetOnZoom = (e, newScale) => {
enforceBoundaries() //
}
//
const zoom = (direction, e = { clientX: 0, clientY: 0 }) => {
const delta = direction === 'in' ? SCALE_STEP : -SCALE_STEP
const newScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, scale.value + delta))
@ -158,19 +176,25 @@ const zoom = (direction, e = { clientX: 0, clientY: 0 }) => {
}
}
//
//
const zoomIn = (e) => zoom('in', e)
//
const zoomOut = (e) => zoom('out', e)
//
const handleWheel = (e) => {
e.preventDefault()
zoom(e.deltaY > 0 ? 'out' : 'in', e)
requestAnimationFrame(() => {
e.preventDefault() //
zoom(e.deltaY > 0 ? 'out' : 'in', e)
})
}
// SVG
const updateSvgSize = () => {
const oldScale = scale.value
svgWidth.value = INITIAL_WIDTH * scale.value
svgHeight.value = INITIAL_HEIGHT * scale.value
svgWidth.value = INITIAL_WIDTH.value * scale.value
svgHeight.value = INITIAL_HEIGHT.value * scale.value
//
if (oldScale !== 0) {
@ -182,6 +206,7 @@ const updateSvgSize = () => {
enforceBoundaries()
}
//
const enforceBoundaries = () => {
const { maxOffsetX, maxOffsetY } = getMaxOffset()
@ -198,13 +223,6 @@ const enforceBoundaries = () => {
}
}
//
const isDragging = ref(false)
const offsetX = ref(0)
const offsetY = ref(0)
const startX = ref(0)
const startY = ref(0)
//
const startDrag = (e) => {
if (!canDrag()) return //
@ -215,9 +233,6 @@ const startDrag = (e) => {
document.addEventListener('mouseup', stopDrag)
}
const maxOffsetX1 = ref(0)
const maxOffsetY1 = ref(0)
//
const handleDrag = (e) => {
if (!isDragging.value) return
@ -256,13 +271,7 @@ const stopDrag = () => {
document.removeEventListener('mouseup', stopDrag)
}
const props = defineProps({
presetSettingVisible: {
type: Boolean,
default: false,
},
})
//
const canDrag = () => {
const parentWidth = planeMapContainer.value?.clientWidth || 0
const parentHeight = planeMapContainer.value?.clientHeight || 0
@ -279,18 +288,8 @@ const getMaxOffset = () => {
}
}
//
const getLogicalPosition = (clientX, clientY) => {
// const svgRect = svgMapRef.value.getBoundingClientRect()
// // SVG
// const logicalX = (clientX - svgRect.left - offsetX.value) / scale.value
// const logicalY = (clientY - svgRect.top - offsetY.value) / scale.value
// return {
// x: Math.max(0, Math.min(INITIAL_WIDTH, logicalX)),
// y: Math.max(0, Math.min(INITIAL_HEIGHT, logicalY)),
// }
const svgRect = svgMapRef.value.getBoundingClientRect()
// SVG
@ -302,9 +301,9 @@ const getLogicalPosition = (clientX, clientY) => {
const logicalY1 = (clientY - svgRect.top - offsetY.value) / scale.value
return {
x: Math.max(0, Math.min(INITIAL_WIDTH, logicalX)),
y: Math.max(0, Math.min(INITIAL_HEIGHT, logicalY)),
y1: Math.max(0, Math.min(INITIAL_HEIGHT, logicalY1)),
x: Math.max(0, Math.min(INITIAL_WIDTH.value, logicalX)),
y: Math.max(0, Math.min(INITIAL_HEIGHT.value, logicalY)),
y1: Math.max(0, Math.min(INITIAL_HEIGHT.value, logicalY1)),
}
}
@ -407,9 +406,15 @@ const handleModifyPoint = () => {
//
const markerInfo = {
type: '修改',
xCount: point.xCount,
yCount: point.yCount,
markerIndex: selectedPointIndex.value,
markerX: point.x,
markerY: point.y,
markerX: point.markerX,
markerY: point.markerY,
markerY1: point.markerY1,
markerName: point.markerName,
markerAngle: point.markerAngle,
markerPreset: point.markerPreset,
}
emits('onHandleAddMarker', markerInfo)
}
@ -424,23 +429,19 @@ const handleDeletePoint = () => {
closeContextMenu()
}
//
onMounted(() => {
document.addEventListener('click', handleClickOutsideMenu)
})
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutsideMenu)
})
//
const addDevicePoint = (x, y, y1) => {
if (isPointClickStatus.value) return
devicePoints.value.push({
x: x, //
y: y, //
y1: y1, //
xCount: x * 2, //
yCount: y * 2, //
markerX: x, //
markerY: y, //
markerY1: y1, //
id: Date.now(),
markerName: '',
markerAngle: '', //
markerPreset: '', //
})
}
@ -448,9 +449,15 @@ const addDevicePoint = (x, y, y1) => {
const handlePointClick = (point, index) => {
const markerInfo = {
type: '新增',
xCount: point.xCount, //
yCount: point.yCount, //
markerIndex: index,
markerX: point.x,
markerY: point.y,
markerX: point.markerX,
markerY: point.markerY,
markerY1: point.markerY1,
markerName: point.markerName,
markerAngle: point.markerAngle,
markerPreset: point.markerPreset,
}
emits('onHandleAddMarker', markerInfo)
}
@ -460,16 +467,65 @@ const onHandleCloseModal = () => {
emits('onHandleCloseModal')
}
//
const onHandleCloseAddModal = () => {
showAddModal.value = false
}
//
onMounted(async () => {
document.addEventListener('click', handleClickOutsideMenu)
const svg = svgMapRef.value
svg.addEventListener('wheel', handleWheel, { passive: false }) //
const deviceInfo = await getRobotDeviceListFn()
//
mapInfo.value = await getRobotMapInfoFn(deviceInfo?.puId)
})
onBeforeUnmount(() => {
document.removeEventListener('click', handleClickOutsideMenu)
})
watch(
() => props.markerInfoNew,
(newVal) => {
//
if (Object.keys(newVal).length > 0) {
const svgRect = svgMapRef.value.getBoundingClientRect()
const clientY =
svgHeight.value - scale.value * (newVal.yCount / 2) + svgRect.top + offsetY.value
const logicalY1 = (clientY - svgRect.top - offsetY.value) / scale.value
devicePoints.value[newVal.markerIndex].markerX = newVal.xCount / 2
devicePoints.value[newVal.markerIndex].markerY = newVal.markerY
devicePoints.value[newVal.markerIndex].markerY1 = logicalY1
devicePoints.value[newVal.markerIndex].markerName = newVal.markerName
devicePoints.value[newVal.markerIndex].markerAngle = newVal.markerAngle
devicePoints.value[newVal.markerIndex].markerPreset = newVal.markerPreset
devicePoints.value[newVal.markerIndex].xCount = newVal.xCount
devicePoints.value[newVal.markerIndex].yCount = newVal.yCount
}
},
{
immediate: true,
},
)
watch(
//
() => mapInfo.value,
(newVal) => {
if (newVal.mapWidth && newVal.mapHeight) {
INITIAL_WIDTH.value = Math.ceil(newVal.mapWidth / 2)
INITIAL_HEIGHT.value = Math.ceil(newVal.mapHeight / 2)
svgWidth.value = INITIAL_WIDTH.value
svgHeight.value = INITIAL_HEIGHT.value
}
},
)
</script>
<style lang="scss" scoped>
.plane-map-container {
width: 100%;
height: 70vh;
// height: 80vh;
max-height: 85vh;
overflow: auto;
//
&::-webkit-scrollbar {

View File

@ -1,258 +0,0 @@
<template>
<!-- 预置位配置 -->
<DialogModal @onHandleCloseModal="onHandleCloseModal" :modalTitle="modalTitle" :height="`90vh`">
<!-- 平面图操作区域 -->
<div class="plane-map-container" ref="planeMapContainer">
<svg
ref="svgMap"
class="floor-plan"
@click="handleMapClick"
preserveAspectRatio="xMidYMid meet"
:viewBox="`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`"
>
<!-- 平面图背景 -->
<image
v-if="imgLoaded"
:href="demoImg"
:width="viewBox.width"
:height="viewBox.height"
preserveAspectRatio="xMidYMid slice"
style="object-fit: cover"
/>
<!-- 动态渲染标记点 -->
<circle
v-for="(point, index) in points"
:key="index"
:cx="point.x"
:cy="point.y"
r="8"
fill="red"
@click.stop="selectPoint(index)"
@mousedown="startDrag(index, $event)"
/>
<!-- 动态渲染连线 -->
<line
v-for="(line, index) in lines"
:key="'line-' + index"
:x1="line.start.x"
:y1="line.start.y"
:x2="line.end.x"
:y2="line.end.y"
stroke="blue"
stroke-width="2"
/>
</svg>
<div class="map-control-container">
<n-button type="info" @click="handleZoomIn">放大</n-button>
<n-button type="info" @click="handleZoomOut">缩小</n-button>
</div>
</div>
</DialogModal>
</template>
<script setup>
import DialogModal from '@/components/DialogModal/index.vue'
import { refThrottled, useMouseInElement } from '@vueuse/core'
import { ref, onMounted, nextTick, watch } from 'vue'
// import { CashOutline as CashIcon } from '@vicons/ionicons5'
import { NIcon } from 'naive-ui'
import demoImg from '@/assets/demo.png'
const emits = defineEmits(['onHandleCloseModal'])
const modalTitle = ref('预置位配置')
const svgMap = refThrottled(null)
const points = ref([])
const lines = ref([])
const imgLoaded = ref(false)
const imgNaturalSize = ref({ width: 0, height: 0 })
const props = defineProps({
presetSettingVisible: {
type: Boolean,
default: false,
},
})
// viewBox
const viewBox = ref({
x: 0,
y: 0,
width: 0,
height: 0,
})
//
const containerSize = ref({ width: 0, height: 0 })
const planeMapContainer = ref(null)
//
const onHandleCloseModal = () => {
emits('onHandleCloseModal')
}
//
const startDrag = (index, e) => {
e.preventDefault()
const { x: startX, y: startY } = points.value[index]
const onMove = (moveEvent) => {
const rect = svgMap.value.getBoundingClientRect()
points.value[index] = {
x: moveEvent.clientX - rect.left,
y: moveEvent.clientY - rect.top,
}
}
const onUp = () => {
window.removeEventListener('mousemove', onMove)
window.removeEventListener('mouseup', onUp)
}
window.addEventListener('mousemove', onMove)
window.addEventListener('mouseup', onUp)
}
// 线
const connectPoints = () => {
if (points.value.length >= 2) {
lines.value.push({
start: points.value[0],
end: points.value[1],
})
}
}
onMounted(() => {
//
nextTick(() => {
const resizeObserver = new ResizeObserver((entries) => {
if (entries[0]) {
containerSize.value = {
width: entries[0].contentRect.width,
height: entries[0].contentRect.height,
}
}
})
if (planeMapContainer.value) {
resizeObserver.observe(planeMapContainer.value)
}
})
})
//
const handleMapClick = (e) => {
if (!svgMap.value) return
const pt = svgMap.value.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const svgPt = pt.matrixTransform(svgMap.value.getScreenCTM().inverse())
points.value.push({
x: svgPt.x,
y: svgPt.y,
})
}
watch(
() => props.presetSettingVisible,
(newVal) => {
if (newVal) {
nextTick(() => {
loadImage()
})
}
},
{
immediate: true,
},
)
const initMapSize = () => {
if (!planeMapContainer.value) return
containerSize.value = {
width: planeMapContainer.value.clientWidth,
height: planeMapContainer.value.clientHeight,
}
// viewBox
viewBox.value.width = containerSize.value.width
viewBox.value.height = containerSize.value.height
}
//
const loadImage = () => {
const img = new Image()
img.onload = () => {
imgNaturalSize.value = {
width: img.naturalWidth,
height: img.naturalHeight,
}
imgLoaded.value = true
adjustViewBox()
}
img.onerror = () => {
console.error('图片加载失败,请检查路径:', demoImg)
}
img.src = demoImg // 使
}
// viewBox
const adjustViewBox = () => {
if (!planeMapContainer.value || !imgNaturalSize.value.width) return
const container = planeMapContainer.value
const containerRatio = container.clientWidth / container.clientHeight
const imgRatio = imgNaturalSize.value.width / imgNaturalSize.value.height
if (containerRatio > imgRatio) {
//
viewBox.value = {
x: (imgNaturalSize.value.width - imgNaturalSize.value.height * containerRatio) / 2,
y: 0,
width: imgNaturalSize.value.height * containerRatio,
height: imgNaturalSize.value.height,
}
} else {
//
viewBox.value = {
x: 0,
y: (imgNaturalSize.value.height - imgNaturalSize.value.width / containerRatio) / 2,
width: imgNaturalSize.value.width,
height: imgNaturalSize.value.width / containerRatio,
}
}
}
//
const handleZoomIn = () => {
viewBox.value.width = viewBox.value.width * 1.1
viewBox.value.height = viewBox.value.height * 1.1
}
//
const handleZoomOut = () => {
viewBox.value.width = viewBox.value.width * 0.9
viewBox.value.height = viewBox.value.height * 0.9
}
</script>
<style lang="scss" scoped>
.plane-map-container {
width: 100%;
height: 100%;
position: relative;
.map-control-container {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 10px;
}
}
</style>

View File

@ -1,212 +0,0 @@
<template>
<!-- 预置位配置 -->
<DialogModal @onHandleCloseModal="onHandleCloseModal" :modalTitle="modalTitle" :height="`90vh`">
<!-- 平面图操作区域 -->
<div class="plane-map-container"></div>
</DialogModal>
</template>
<script setup>
import DialogModal from '@/components/DialogModal/index.vue'
import { refThrottled, useMouseInElement } from '@vueuse/core'
import { ref, onMounted, nextTick, watch } from 'vue'
// import { CashOutline as CashIcon } from '@vicons/ionicons5'
import { NIcon } from 'naive-ui'
import demoImg from '@/assets/demo.png'
const emits = defineEmits(['onHandleCloseModal'])
const modalTitle = ref('预置位配置')
const svgMap = refThrottled(null)
const points = ref([])
const lines = ref([])
const imgLoaded = ref(false)
const imgNaturalSize = ref({ width: 0, height: 0 })
const props = defineProps({
presetSettingVisible: {
type: Boolean,
default: false,
},
})
// viewBox
const viewBox = ref({
x: 0,
y: 0,
width: 0,
height: 0,
})
//
const containerSize = ref({ width: 0, height: 0 })
const planeMapContainer = ref(null)
//
const onHandleCloseModal = () => {
emits('onHandleCloseModal')
}
//
const startDrag = (index, e) => {
e.preventDefault()
const { x: startX, y: startY } = points.value[index]
const onMove = (moveEvent) => {
const rect = svgMap.value.getBoundingClientRect()
points.value[index] = {
x: moveEvent.clientX - rect.left,
y: moveEvent.clientY - rect.top,
}
}
const onUp = () => {
window.removeEventListener('mousemove', onMove)
window.removeEventListener('mouseup', onUp)
}
window.addEventListener('mousemove', onMove)
window.addEventListener('mouseup', onUp)
}
// 线
const connectPoints = () => {
if (points.value.length >= 2) {
lines.value.push({
start: points.value[0],
end: points.value[1],
})
}
}
onMounted(() => {
//
nextTick(() => {
const resizeObserver = new ResizeObserver((entries) => {
if (entries[0]) {
containerSize.value = {
width: entries[0].contentRect.width,
height: entries[0].contentRect.height,
}
}
})
if (planeMapContainer.value) {
resizeObserver.observe(planeMapContainer.value)
}
})
})
//
const handleMapClick = (e) => {
if (!svgMap.value) return
const pt = svgMap.value.createSVGPoint()
pt.x = e.clientX
pt.y = e.clientY
const svgPt = pt.matrixTransform(svgMap.value.getScreenCTM().inverse())
points.value.push({
x: svgPt.x,
y: svgPt.y,
})
}
watch(
() => props.presetSettingVisible,
(newVal) => {
if (newVal) {
nextTick(() => {
loadImage()
})
}
},
{
immediate: true,
},
)
const initMapSize = () => {
if (!planeMapContainer.value) return
containerSize.value = {
width: planeMapContainer.value.clientWidth,
height: planeMapContainer.value.clientHeight,
}
// viewBox
viewBox.value.width = containerSize.value.width
viewBox.value.height = containerSize.value.height
}
//
const loadImage = () => {
const img = new Image()
img.onload = () => {
imgNaturalSize.value = {
width: img.naturalWidth,
height: img.naturalHeight,
}
imgLoaded.value = true
adjustViewBox()
}
img.onerror = () => {
console.error('图片加载失败,请检查路径:', demoImg)
}
img.src = demoImg // 使
}
// viewBox
const adjustViewBox = () => {
if (!planeMapContainer.value || !imgNaturalSize.value.width) return
const container = planeMapContainer.value
const containerRatio = container.clientWidth / container.clientHeight
const imgRatio = imgNaturalSize.value.width / imgNaturalSize.value.height
if (containerRatio > imgRatio) {
//
viewBox.value = {
x: (imgNaturalSize.value.width - imgNaturalSize.value.height * containerRatio) / 2,
y: 0,
width: imgNaturalSize.value.height * containerRatio,
height: imgNaturalSize.value.height,
}
} else {
//
viewBox.value = {
x: 0,
y: (imgNaturalSize.value.height - imgNaturalSize.value.width / containerRatio) / 2,
width: imgNaturalSize.value.width,
height: imgNaturalSize.value.width / containerRatio,
}
}
}
const handleZoomIn = () => {
console.log('放大')
viewBox.value.width = viewBox.value.width * 1.1
viewBox.value.height = viewBox.value.height * 1.1
}
const handleZoomOut = () => {
console.log('缩小')
viewBox.value.width = viewBox.value.width * 0.9
viewBox.value.height = viewBox.value.height * 0.9
}
</script>
<style lang="scss" scoped>
.plane-map-container {
width: 100%;
height: 100%;
position: relative;
background-color: pink;
// .map-control-container {
// position: absolute;
// top: 10px;
// right: 10px;
// z-index: 1000;
// display: flex;
// flex-direction: column;
// gap: 10px;
// }
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="viewport-container">
<!-- 非全屏状态 -->
<div ref="appRef" class="app-container">
<!-- 机器人首页 -->
@ -9,52 +9,52 @@
<!-- 左一 -->
<div
:style="{
gridColumn: fullScreenVisible ? '1 / 9' : '1 / 4',
gridRow: fullScreenVisible ? '1 / 13' : '1 / 7',
gridColumn: fullScreenVisibleNew ? '1 / 9' : '1 / 4',
gridRow: fullScreenVisibleNew ? '1 / 13' : '1 / 7',
}"
>
<LeftOne
:videoId="'video-1'"
:cameraNode="cameraNode_1"
:fullScreenVisible="fullScreenVisible"
:fullScreenVisible="fullScreenVisibleNew"
@onHandleChangeView="onHandleChangeView"
@onHandleOperationPanel="onHandleOperationPanel"
@onHandleFullScreenToggle="onHandleFullScreenToggleL"
@onHandleFullScreenToggle="onHandleFullScreenToggle"
/>
</div>
<!-- 左二 -->
<div class="robot-2" v-if="!fullScreenVisible">
<div class="robot-2" v-if="!fullScreenVisibleNew">
<LeftTwo />
</div>
<!-- 中一 -->
<div
:style="{
gridColumn: fullScreenVisible ? '9 / 13' : '4 / 10',
gridRow: fullScreenVisible ? '1 / 6' : '1 / 8',
gridColumn: fullScreenVisibleNew ? '9 / 13' : '4 / 10',
gridRow: fullScreenVisibleNew ? '1 / 6' : '1 / 8',
}"
>
<CenterOne
:videoId="'video-2'"
:cameraNode_2="cameraNode_2"
:fullScreenVisible="fullScreenVisible"
:fullScreenVisible="fullScreenVisibleNew"
/>
</div>
<!-- 中二 -->
<div class="robot-4" v-if="!fullScreenVisible">
<div class="robot-4" v-if="!fullScreenVisibleNew">
<CenterTwo />
</div>
<!-- 右一 -->
<div class="robot-5" v-if="!fullScreenVisible">
<div class="robot-5" v-if="!fullScreenVisibleNew">
<RightOne />
</div>
<!-- 右二 -->
<div class="robot-6" v-if="!fullScreenVisible">
<div class="robot-6" v-if="!fullScreenVisibleNew">
<RightTwo />
</div>
<div class="robot-7" v-if="fullScreenVisible">
<div class="robot-7" v-if="fullScreenVisibleNew">
<ControlDeck />
</div>
</div>
@ -77,28 +77,28 @@
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { initLoginApi, getDeviceUrlApi } from '@/utils/initLogin'
import { getTokenApi, getDeviceInfoApi } from '@/api/home'
import { ref, onMounted } from 'vue'
import { getDeviceUrlApi } from '@/utils/initLogin'
import { getTokenApi } from '@/api/home'
import { useScale } from '@/hooks/useScale' // Hook
import { userDataStore } from '@/store/user'
import LeftOne from './components/left-one.vue'
import LeftTwo from './components/left-two.vue'
import CenterOne from './components/center-one.vue'
import CenterTwo from './components/center-two.vue'
import RightOne from './components/right-one.vue'
import RightTwo from './components/right-two/index.vue'
import ControlDeck from './components/control-deck.vue'
import { userDataStore } from '@/store/user' //
import LeftOne from './components/left-one.vue' //
import LeftTwo from './components/left-two.vue' //
import CenterOne from './components/center-one.vue' //
import CenterTwo from './components/center-two.vue' //
import RightOne from './components/right-one.vue' //
import RightTwo from './components/right-two/index.vue' //
import ControlDeck from './components/control-deck.vue' //
import { getRobotTokenFn, getRobotDeviceListFn } from '@/utils/getRobotInfo' //
const userData = userDataStore()
const appRef = ref(null) // DOM
const fullScreenVisible = ref(false) //
// 使 useScale Hook setup()
const fullScreenVisibleNew = ref(false) //
const { baseWidth, baseHeight, scale } = useScale(appRef)
const cameraNode_1 = ref({
puid: '201115200268437643',
puid: '',
idx: 0,
stream: 0,
name: '',
@ -107,7 +107,7 @@ const cameraNode_1 = ref({
steamURL: '',
})
const cameraNode_2 = ref({
puid: '201115200268437643',
puid: '',
idx: 1,
stream: 0,
name: '',
@ -123,8 +123,8 @@ const onHandleOperationPanel = (visible) => {
operationPanelVisible.value = visible
}
//
const onHandleFullScreenToggleL = (visible) => {
fullScreenVisible.value = visible
const onHandleFullScreenToggle = (visible) => {
fullScreenVisibleNew.value = visible
}
//
const onHandleChangeView = () => {
@ -136,43 +136,17 @@ const onHandleChangeView = () => {
cameraNode_2.value.steamURL = temp
}
const loginParams = ref({
// - IP
address: '60.168.132.97',
port: '49988',
// -
user: 'admin',
// -
password: 'Aa123456',
// - ID
epid: 'YDJFXK',
// -
bfix: 0,
})
//
const initLoginData = async () => {
initLoginApi(loginParams.value).then((res) => {
console.log(res, 'res设备---')
// token 使
userData.setDeviceToken(res?.data?.token)
// getDeviceData()
})
}
//
const getDeviceData = async (puId) => {
// //
const getDeviceData = async (puId, deviceToken) => {
const { data: res } = await getDeviceUrlApi({
token: userData?.deviceToken,
token: deviceToken,
puid: puId,
idx: 0,
stream: 0,
type: 'HTTP-FLV',
})
const { data: res2 } = await getDeviceUrlApi({
token: userData?.deviceToken,
token: deviceToken,
puid: puId,
idx: 1,
stream: 0,
@ -183,40 +157,27 @@ const getDeviceData = async (puId) => {
cameraNode_2.value.steamURL = res2?.streamUrl
}
initLoginData()
// token
const getTokenData = async () => {
const { data: res } = await getTokenApi({
getTokenApi({
username: 'admin',
password: 'admin123',
})
// console.log(res, 'token')
// token 使
userData.setUserInfo({
token: res?.token,
}).then((res) => {
// token 使
userData.setUserInfo({
token: res?.data?.token,
})
})
}
getTokenData()
getTokenData() // token
//
const getDeviceInfoData = async () => {
const { data: res } = await getDeviceInfoApi()
console.log(res, 'deviceInfo')
onMounted(async () => {
const deviceToken = await getRobotTokenFn() // token
const deviceInfo = await getRobotDeviceListFn() //
//
if (res?.data && res?.data?.length > 0) {
const deviceInfo = res.data[0]
cameraNode_1.value.name = deviceInfo.devName
cameraNode_2.value.name = deviceInfo.devName
getDeviceData(deviceInfo.puId)
}
}
getDeviceInfoData()
getDeviceData(deviceInfo.puId, deviceToken) // Url
})
</script>
<style lang="scss">