zn-admin-vue3-wcs/src/views/mapPage/realTimeMap/components/indexPage.vue
2025-02-14 11:44:55 +08:00

343 lines
10 KiB
Vue

<template>
<div class="affix-container">
<el-affix target=".affix-container" :offset="80">
<div class="affix-container-top">
<el-scrollbar>
<div class="scrollbar-flex-content">
<el-dropdown
placement="bottom"
v-for="(item, index) in list"
:key="index"
style="border: none"
>
<div class="scrollbar-demo-item">
{{ item.floor }}
</div>
<template #dropdown v-if="item.children && item.children.length">
<el-dropdown-menu style="width: 100px">
<el-dropdown-item
v-for="(p, i) in item.children"
:key="i"
@click="getMapData(p)"
>{{ p.area }}</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-scrollbar>
</div>
</el-affix>
<div class="indexpage-container" v-if="imgUrl">
<div class="indexpage-container-box">
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
<div class="indexpage-container-box-point">
<div
class="indexpage-container-box-point-item"
v-for="(item, index) in pointList"
:key="index"
:style="{ left: item.locationX * radio + 'px', top: item.locationY * radio + 'px' }"
>
<div
class="indexpage-container-box-point-item-inner"
v-if="item.showData"
:style="{
width: item.showData.locationWide * radio + 'px',
height: item.showData.locationDeep * radio + 'px'
}"
>
<div v-if="item.type == 2" style="width: 100%; height: 100%">
<el-popover
placement="top-start"
trigger="hover"
width="auto"
>
<template #reference>
<img :src="item.imgUrl" alt="" style="width: 100%; height: 100%" @dblclick="storeClick(item)"/>
</template>
<div class="indexpage-container-box-point-item-inner-popover">
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div class="indexpage-container-box-point-item-inner-popover-name">
库位名:
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.locationNo || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div class="indexpage-container-box-point-item-inner-popover-name">
所属线库:
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.laneName || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div class="indexpage-container-box-point-item-inner-popover-name">
所属区域:
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.areaName || '' }}
</div>
</div>
<!-- <div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div class="indexpage-container-box-point-item-inner-popover-name">
状态:
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.locationUseStatus == 0 ? '空闲' : '占用' }}
</div>
</div> -->
</div>
</el-popover>
</div>
<div v-else style="width: 100%; height: 100%">
<img :src="item.imgUrl" alt="" style="width: 100%; height: 100%" />
</div>
</div>
<div v-else style="width: 10px; height: 10px; border-radius: 50%; background: red">
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, defineComponent, reactive, nextTick, onMounted, onBeforeUnmount } from 'vue'
import * as MapApi from '@/api/map/map'
import WebSocketClient from '../webSocket.js'
import storeDialog from './storeDialog.vue'
const imgUrl = ref('')
const socketClient = ref(null)
const emit = defineEmits(['transmitMapId'])
const list = ref([])
const nowObject = ref(null)
//获取地图区域
const getList = async () => {
let data = await MapApi.getPositionMapGetMap()
let mapList = []
for (let key in data) {
mapList.push({
floor: key,
children: data[key]
})
}
list.value = mapList
console.log(list.value, data)
//默认取第一个
if (data[1][0]) {
getMapData(data[1][0])
}
}
//库位双击
const storeClick = async (item) => {
console.log(item)
let storeData = await MapApi.houseLocationGetByMapItemId({
mapId: item.positionMapId,
mapItemId: item.id
})
console.log(storeData)
}
const pointList = ref([])
const getPositionMapListFun = async (positionMapId) => {
// console.log(positionMapId)
let data = await MapApi.getPositionMapItemList({ positionMapId: positionMapId })
// console.log(data)
if (data && data.length > 0) {
data.forEach((item) => {
// console.log(JSON.parse(item.dataJson))
item.formattedData = JSON.parse(item.dataJson)
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null
item.imgUrl = formatteTypeImg(item.type)
})
}
console.log(data)
pointList.value = data
}
const formatteTypeImg = (type) => {
switch (type) {
case 1:
return ''
case 2:
return 'https://api.znkjfw.com/admin-api/infra/file/4/get/库位库存_png_179_1739326653035.png'
case 3:
return 'https://api.znkjfw.com/admin-api/infra/file/4/get/设备点_png_179_1739327151877.png'
case 4:
return 'https://api.znkjfw.com/admin-api/infra/file/4/get/停车场-01_png_179_1739326933020.png'
case 5:
return 'https://api.znkjfw.com/admin-api/infra/file/4/get/区域_png_179_1739327151876.png'
case 6:
return 'https://api.znkjfw.com/admin-api/infra/file/4/get/等待点_png_179_1739326991439.png'
default:
return ''
}
}
const replaceHttpWithWs = (str) => {
return str.replace(/^http/, 'ws')
}
// 连接websocket
const linkWebSocket = (url) => {
socketClient.value = new WebSocketClient(url)
if (socketClient.value) {
// 监听消息
socketClient.value.onMessage((message) => {
console.log('收到消息:', message)
})
}
}
// 发送websocket消息
const sendMessage = () => {
socketClient.value.send('Hello, WebSocket!')
}
// 断开连接
const disconnect = () => {
socketClient.value.disconnect()
}
//获取扫描图
const getMapData = async (item) => {
nowObject.value = JSON.parse(JSON.stringify(item))
let websoketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${nowObject.value.floor}&area=${nowObject.value.area}`
console.log(websoketUrl)
linkWebSocket(websoketUrl)
getPositionMapListFun(nowObject.value.id)
emit('transmitMapInfo', {
id: item.id,
floor: item.floor,
area: item.area
})
let data = await MapApi.getPositionMapdDwnloadPngBase64({
floor: item.floor,
area: item.area
})
imgUrl.value = data
computedRatio()
}
const radio = ref(1)
const computedRatio = () => {
nextTick(() => {
if (imgUrl.value) {
let width = getElementWidthByClass('indexpage-container')
getImageWidth(imgUrl.value).then((res) => {
// console.log(res)
let ratioVal = width / res
radio.value = ratioVal
if (pointList.value.length) {
pointList.value.forEach((item) => {
item.radio = radio.value
})
}
})
// console.log(width)
}
})
}
const getImageWidth = (imageUrl) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = function () {
resolve(img.width)
}
img.onerror = function () {
reject(new Error('图片加载失败'))
}
img.src = imageUrl
})
}
const getElementWidthByClass = (className) => {
const element = document.querySelector(`.${className}`)
if (element) {
// return window.getComputedStyle(element).width
const widthWithUnit = window.getComputedStyle(element).width
return widthWithUnit.slice(0, -2)
}
return null
}
onMounted(() => {
getList()
window.addEventListener('resize', computedRatio)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', computedRatio)
})
</script>
<style lang="scss" scoped>
.affix-container {
width: 100%;
}
.indexpage-container {
width: 100%;
position: relative;
}
.indexpage-container .affix-container-top {
width: 100%;
height: 80px;
background-color: #fff;
border-bottom: 1px solid #f5f5f5;
}
.indexpage-container-box-point {
width: 100%;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
.indexpage-container-box-point-item {
position: absolute;
cursor: pointer;
}
.scrollbar-flex-content {
padding: 2px 6px;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.scrollbar-demo-item {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 90px;
height: 30px;
margin: 10px 6px;
text-align: center;
border-radius: 4px;
background: var(--el-color-primary-light-9);
color: var(--el-color-primary);
position: relative;
}
.scrollbar-demo-item {
cursor: pointer;
border: none;
}
:focus-visible {
outline: none;
}
.indexpage-container-box {
width: 100%;
position: relative;
}
.indexpage-container-box-img {
width: 100%;
height: auto;
}
.indexpage-container-box-point-item-inner-popover-item{
display: flex;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0D162A;
}
</style>