343 lines
10 KiB
Vue
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>
|