254 lines
8.1 KiB
Vue
254 lines
8.1 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="fh2-container">
|
|||
|
|
<div id="cockpit-header-container"></div>
|
|||
|
|
<div ref="Detail" class="project-details router-cockpit">
|
|||
|
|
<div id="project-app-container"></div>
|
|||
|
|
<div id="project-middle-container"></div>
|
|||
|
|
<div id="project-right-micro-app" class="right-micro-app">
|
|||
|
|
<div class="maps-micro-app">
|
|||
|
|
<div class="cockpit-left-border-container"></div>
|
|||
|
|
<div id="project-map-app-placeholder" class="map-app-placeholder">
|
|||
|
|
<div class="cockpit-dock-live-container"></div>
|
|||
|
|
<div id="map-app-global" class="map-app-container"></div>
|
|||
|
|
<div class="cockpit-bottom-border-container"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="project-right">
|
|||
|
|
<div id="cockpit-app-container"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
<script setup>
|
|||
|
|
import { computed, nextTick, onMounted, ref } from 'vue'
|
|||
|
|
// import { useStore } from 'vuex'
|
|||
|
|
|
|||
|
|
const Detail = ref(null)
|
|||
|
|
// const store = useStore()
|
|||
|
|
// const data = computed(() => store.state.mapStore.uavs.data)
|
|||
|
|
const ip = '198.16.74.210'
|
|||
|
|
|
|||
|
|
onMounted(() => {
|
|||
|
|
// ******* 接入步骤 4 - START:使用组件前初始化配置(具体配置参数请按实际替换) *******
|
|||
|
|
if(window.FH2) {
|
|||
|
|
window.FH2.initConfig({
|
|||
|
|
serverUrl: `http://${ip}:30812`,
|
|||
|
|
wssUrl: `ws://${ip}:30812/duplex/web`,
|
|||
|
|
hostUrl: `http://${ip}`,
|
|||
|
|
prjId: '4bd996b8-5201-4e5d-82b1-6879be360c20', // 项目 id,按实际传入
|
|||
|
|
projectToken: 'eyJhbGciOiJIUzUxMiIsImNyaXQiOlsidHlwIiwiYWxnIiwia2lkIl0sImtpZCI6IjU3YmQyNmEwLTYyMDktNGE5My1hNjg4LWY4NzUyYmU1ZDE5MSIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiIiwiZXhwIjoyMDc1OTQ3NzIyLCJuYmYiOjE3NjA0MTQ5MjIsIm9yZ2FuaXphdGlvbl91dWlkIjoiOWRmMjlmYTgtNGI5OS00MThlLWJhMmQtMGY5ZWY5ZWVlMzkyIiwicHJvamVjdF91dWlkIjoiIiwic3ViIjoiZmgyIiwidXNlcl9pZCI6IjE3NjA0MTQxMDkzNTcwMDI0MjkifQ.DC_aS37W2fkqOjCtfvysDfhTn-4XVn3_IrXBnPD9rICGyrIBKBG3oPldeW_pqele5H_gCn1EgM0KXcbDgvq-dw' // 组织密钥,按实际传入
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// ******* 接入步骤 5 - START:加载组件,传入航线ID *******
|
|||
|
|
window.FH2.loadCockpit('cockpit-app-container', {
|
|||
|
|
gateway_sn: data.value.gatewaySn, // 网关 sn,按实际传入
|
|||
|
|
drone_sn: data.value.droneSn // 飞机 sn,按实际传入
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
// // 使用轮询方式等待内容加载完成后再滚动
|
|||
|
|
// waitForContentAndScroll()
|
|||
|
|
})
|
|||
|
|
const waitForContentAndScroll = () => {
|
|||
|
|
let attempts = 0
|
|||
|
|
let previousScrollWidth = 0
|
|||
|
|
let stableCount = 0
|
|||
|
|
const maxAttempts = 30
|
|||
|
|
const checkAndScroll = () => {
|
|||
|
|
attempts++
|
|||
|
|
|
|||
|
|
if (Detail.value) {
|
|||
|
|
// 检查目标容器是否已加载内容
|
|||
|
|
const mapContainer = document.getElementById('map-app-global')
|
|||
|
|
|
|||
|
|
// 判断内容是否加载完成
|
|||
|
|
const isContentLoaded = mapContainer && mapContainer.children.length > 0
|
|||
|
|
// console.log('Content loaded:', isContentLoaded, mapContainer)
|
|||
|
|
// 获取当前尺寸
|
|||
|
|
const currentScrollWidth = Detail.value.scrollWidth
|
|||
|
|
const clientWidth = Detail.value.clientWidth
|
|||
|
|
|
|||
|
|
// console.log('Size check:', {
|
|||
|
|
// attempt: attempts,
|
|||
|
|
// scrollWidth: currentScrollWidth,
|
|||
|
|
// clientWidth: clientWidth,
|
|||
|
|
// isContentLoaded: isContentLoaded
|
|||
|
|
// })
|
|||
|
|
|
|||
|
|
// 检查尺寸是否稳定(连续几次尺寸相同)
|
|||
|
|
if (currentScrollWidth === previousScrollWidth && currentScrollWidth > clientWidth) {
|
|||
|
|
stableCount++
|
|||
|
|
} else {
|
|||
|
|
stableCount = 0
|
|||
|
|
}
|
|||
|
|
previousScrollWidth = currentScrollWidth
|
|||
|
|
// 当内容加载完成且尺寸稳定,或者达到最大尝试次数时执行滚动
|
|||
|
|
if (isContentLoaded && stableCount >= 2 && currentScrollWidth > clientWidth ||
|
|||
|
|
attempts >= maxAttempts) {
|
|||
|
|
|
|||
|
|
// 强制重新计算布局
|
|||
|
|
forceLayoutRecalculation(() => {
|
|||
|
|
executeScroll()
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
// 内容未加载完成或尺寸不稳定,继续等待
|
|||
|
|
setTimeout(checkAndScroll, 300)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 开始检查
|
|||
|
|
setTimeout(checkAndScroll, 300)
|
|||
|
|
}
|
|||
|
|
const forceLayoutRecalculation = (callback) => {
|
|||
|
|
if (!Detail.value) {
|
|||
|
|
if (callback) {
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法1: 强制重排
|
|||
|
|
Detail.value.style.display = 'none'
|
|||
|
|
void Detail.value.offsetHeight // 强制重排
|
|||
|
|
Detail.value.style.display = 'flex'
|
|||
|
|
|
|||
|
|
// 方法2: 临时修改overflow触发重新计算
|
|||
|
|
const originalOverflow = Detail.value.style.overflow
|
|||
|
|
Detail.value.style.overflow = 'hidden'
|
|||
|
|
void Detail.value.offsetWidth
|
|||
|
|
Detail.value.style.overflow = originalOverflow
|
|||
|
|
|
|||
|
|
setTimeout(() => {
|
|||
|
|
if (callback) {
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
}, 100)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const executeScroll = () => {
|
|||
|
|
if (!Detail.value) {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 重新获取准确的尺寸
|
|||
|
|
const scrollWidth = Detail.value.scrollWidth
|
|||
|
|
const clientWidth = Detail.value.clientWidth
|
|||
|
|
const maxScroll = scrollWidth - clientWidth
|
|||
|
|
|
|||
|
|
// console.log('Final size calculation:', {
|
|||
|
|
// scrollWidth,
|
|||
|
|
// clientWidth,
|
|||
|
|
// maxScroll
|
|||
|
|
// })
|
|||
|
|
|
|||
|
|
if (maxScroll > 0) {
|
|||
|
|
const targetPosition = 1388
|
|||
|
|
const scrollPosition = targetPosition > maxScroll ? maxScroll : targetPosition
|
|||
|
|
|
|||
|
|
// 修复:正确处理 scrollPosition 为 0 的情况
|
|||
|
|
const finalPosition = typeof scrollPosition === 'number' ? scrollPosition : 645
|
|||
|
|
|
|||
|
|
// 激活滚动机制后再执行滚动
|
|||
|
|
activateScrollMechanism(() => {
|
|||
|
|
Detail.value.scrollTo({
|
|||
|
|
left: finalPosition,
|
|||
|
|
behavior: 'smooth'
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// console.log('Scrolled to position:', finalPosition,
|
|||
|
|
// 'Max scroll:', maxScroll,
|
|||
|
|
// 'Container width:', clientWidth,
|
|||
|
|
// 'Scroll width:', scrollWidth)
|
|||
|
|
})
|
|||
|
|
} else {
|
|||
|
|
// console.log('No scrollable content, but content is loaded')
|
|||
|
|
// 即使没有滚动内容,也尝试激活滚动机制
|
|||
|
|
activateScrollMechanism(() => {
|
|||
|
|
Detail.value.scrollTo({
|
|||
|
|
left: 645,
|
|||
|
|
behavior: 'smooth'
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const activateScrollMechanism = (callback) => {
|
|||
|
|
if (!Detail.value) {
|
|||
|
|
if (callback) {
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 预激活滚动机制
|
|||
|
|
Detail.value.scrollTo({ left: 1, behavior: 'instant' })
|
|||
|
|
|
|||
|
|
setTimeout(() => {
|
|||
|
|
Detail.value.scrollTo({ left: 0, behavior: 'instant' })
|
|||
|
|
|
|||
|
|
setTimeout(() => {
|
|||
|
|
if (callback) {
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
}, 50)
|
|||
|
|
}, 20)
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
<style lang="scss">
|
|||
|
|
.fh2-container {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
height: 100%;
|
|||
|
|
width: 100%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#project-app-container>div, #cockpit-app-container>div,
|
|||
|
|
.map-app-container>div {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.project-details {
|
|||
|
|
position: relative;
|
|||
|
|
width: 100%;
|
|||
|
|
display: flex;
|
|||
|
|
flex: 1;
|
|||
|
|
overflow: scroll;
|
|||
|
|
// &::-webkit-scrollbar {display: none;}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.project-details .right-micro-app {
|
|||
|
|
position: relative;
|
|||
|
|
display: flex;
|
|||
|
|
flex: 1;
|
|||
|
|
width: 1388px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.project-details .right-micro-app .maps-micro-app {
|
|||
|
|
display: flex;
|
|||
|
|
flex: 1;
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.project-details .right-micro-app .map-app-placeholder {
|
|||
|
|
flex: 1;
|
|||
|
|
position: relative;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.project-details .right-micro-app .map-app-container {
|
|||
|
|
height: 100%;
|
|||
|
|
width: 100%;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<style>
|
|||
|
|
.cockpit-app-ant-modal-root{
|
|||
|
|
position: relative;
|
|||
|
|
z-index: 9999;
|
|||
|
|
}
|
|||
|
|
.cockpit-app-ant-popover{
|
|||
|
|
z-index: 9999 !important;
|
|||
|
|
}
|
|||
|
|
</style>
|