<template>
|
<div class="home-container">
|
<!-- 顶部导航 -->
|
<div class="top-nav">
|
<div class="nav-items">
|
<div class="nav-item mr-[8px]" :class="{ active: currentView === 'model' }" @click="handleChange('model')">模型</div>
|
<div class="nav-item mr-[8px]" :class="{ active: currentView === '720' }" @click="handleChange('720')">720全景</div>
|
<div class="nav-item" :class="{ active: currentView === 'project' }" @click="handleChange('project')">项目实况</div>
|
</div>
|
<div class="time-info">
|
<div class="time-info-item">
|
<i class="el-icon-date" style="color: #FFBF00;font-size: 20px;"></i>
|
<div class="text-white text-[16px] ml-[4px]">工程倒计时/天</div>
|
<div class="text-[#FFBF00] text-[24px] font-bold ml-[28px]">{{endDate}}</div>
|
</div>
|
<div class="time-line">
|
</div>
|
</div>
|
</div>
|
<div class="bottom-nav">
|
<div class="content-wrapper mb-[20px]">
|
<!-- 720菜单 -->
|
<div class="side-menu z-[100]" v-if="currentView === '720'">
|
<el-cascader popper-class="custom-dropdown" v-model="panoValue" :options="panoList" @change="handlePanoChange" :props="{ value: 'id',label: 'label',children: 'Children'}"/>
|
</div>
|
<!-- 项目实况-->
|
<div class="side-menu z-[100]" v-if="currentView === 'project'">
|
<el-cascader popper-class="custom-dropdown" v-model="liveValue" :options="liveList" @change="handleLiveChange" :props="{ value: 'id',label: 'label',children: 'JSCProjectMonitorList'}"/>
|
</div>
|
|
|
<!-- 主要内容区域 -->
|
<div class="main-content" :style="isFullScreen ? fullScreenStyle : ''" v-loading="isLoading">
|
<!-- 模型 / 720 -->
|
<div class="w-full h-full" :style="isFullScreen ? fullScreenStyle : 'width: 100%; height: 100%;'" v-if="currentView === '720' || currentView === 'model'">
|
<iframe id="model-iframe" class="content-frame w-full h-full" src="" frameborder="0" :style="isFullScreen ? fullScreenModelStyle : ''" v-if="currentView === 'model'"></iframe>
|
<iframe ref="panoiframe" id="panoviewpreview" class="pano-frame w-full h-full" :style="isFullScreen ? fullScreenPanoStyle : ''" v-if="currentView === '720'"></iframe>
|
</div>
|
<!-- 720全景图版本选择 -->
|
<!--<div class="w-full h-[120px] bg-[rgba(19,40,64,0.8)] absolute bottom-0 left-0 right-0 flex items-center py-[10px]" :style="isFullScreen ? 'z-index: 100; height:' : ''" v-if="currentView === '720'">
|
<div v-for="item in panoVersionList" :key="item.value" :style="isFullScreen ? 'z-index: 100;' : ''">
|
<div class="w-[160px] h-[100px] mr-[10px] ml-[10px] cursor-pointer border-[1px] border-[#3068A5] rounded-[2px]" @click="panoPreview(panoObj, item)">
|
<img :src="getItemImg(item)" alt="全景图" class="w-full h-full" />
|
</div>
|
</div>
|
</div>-->
|
|
<!-- 放大镜 -->
|
<div class="w-[80px] h-[80px] bg-[#008C99] absolute top-[-40px] right-[-40px] rounded-[50%] z-[100]" v-if="currentView === 'model' || currentView === '720'" @click="handleZoomOut">
|
<img src="../assets/images/backgrounds/zoomin.png" alt="放大" class="w-[16px] h-[16px] mt-[50px] ml-[15px] cursor-pointer" v-if="isFullScreen" />
|
<img src="../assets/images/backgrounds/zoomout.png" alt="缩小" class="w-[16px] h-[16px] mt-[50px] ml-[15px] cursor-pointer" v-else />
|
</div>
|
</div>
|
<!-- 项目 -->
|
<div class="w-full h-full" v-if="currentView === 'project'">
|
<video controls muted controlslist="nodownload" autoplay class="video-box" ref="videoElement" style="width: 100%; height: 100%; background-color: #000;"></video>
|
</div>
|
</div>
|
|
</div>
|
<div class="chart-content">
|
<div
|
class="w-full h-[4vh] mb-[1vh]" :style="{
|
backgroundImage: `url(${bottomImage})`,
|
backgroundRepeat: 'no-repeat',
|
backgroundPosition: 'center center',
|
backgroundSize: '100% 100%'
|
}">
|
</div>
|
<div class="chart-container" :style="sectionStyle">
|
<img src="../assets/images/backgrounds/shigongjinduchart.png" alt="施工进度" class="w-full h-full" />
|
</div>
|
</div>
|
</div>
|
|
</div>
|
</template>
|
|
<script>
|
import flvjs from 'flv.js'
|
import {
|
nextTick
|
} from 'vue'
|
import {
|
HomeAPI
|
} from "../api/home";
|
import {
|
getProjectId,
|
getToken,
|
getProjectEndDate
|
} from "../utils/getToken.js";
|
export default {
|
name: 'Home',
|
components: {},
|
props: {
|
selectedId: {
|
type: String,
|
default: "",
|
},
|
},
|
data() {
|
return {
|
liveValue:[],
|
playerStatus: '未就绪',
|
errorMessage:'',
|
flvPlayer:null,
|
videoSrc: "",
|
currentView: 'model',
|
chartOptions: {
|
id: 'shigongjinduChart',
|
options: {
|
title: {
|
text: '施工进度'
|
}
|
}
|
},
|
bottomImage: new URL('@/assets/images/titles/shigong.png',
|
import.meta.url).href,
|
isLoading: false,
|
panoVersionList: [],
|
isFullScreen: false,
|
fullScreenStyle: '',
|
fullScreenPanoStyle: '',
|
fullScreenModelStyle: '',
|
panoList: [{
|
value: 'zhinan',
|
label: '指南',
|
children: [{
|
value: 'shejiyuanze',
|
label: '设计原则'
|
}, {
|
value: 'daohang',
|
label: '导航'
|
}]
|
}, {
|
value: 'zujian',
|
label: '组件',
|
children: [{
|
value: 'basic',
|
label: 'Basic',
|
}, {
|
value: 'form',
|
label: 'Form',
|
}, {
|
value: 'data',
|
label: 'Data',
|
}, {
|
value: 'notice',
|
label: 'Notice',
|
}, {
|
value: 'navigation',
|
label: 'Navigation',
|
}, {
|
value: 'others',
|
label: 'Others',
|
}],
|
}],
|
panoValue: [],
|
liveList: [],
|
backgroundImage: new URL('@/assets/images/backgrounds/cover_bg.png',
|
import.meta.url).href,
|
endDate: 0,
|
}
|
},
|
computed: {
|
sectionStyle() {
|
return {
|
backgroundImage: `url(${this.backgroundImage})`,
|
backgroundRepeat: 'no-repeat',
|
backgroundPosition: 'center center',
|
backgroundSize: '100% 100%'
|
}
|
},
|
projectId() {
|
return getProjectId()
|
},
|
projectEndDate() {
|
return getProjectEndDate()
|
}
|
},
|
watch: {
|
projectEndDate:{
|
deep: true,
|
handler (newVal) {
|
console.log('newVal', newVal)
|
const date = new Date(newVal);
|
// 获取当前日期作为Date对象
|
const now = new Date();
|
// 计算两个日期的差异(毫秒)
|
const diffTime = Math.abs(now - date);
|
// 将毫秒转换为天数
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
this.endDate = diffDays
|
}
|
},
|
selectedId: {
|
handler(newVal) {
|
console.log("实况界面接收到的数据:", newVal);
|
// 处理数据变化的逻辑
|
this.getProjectLive(newVal);
|
},
|
deep: true, // 深度监听对象内部变化
|
immediate: true, // 立即执行一次
|
},
|
},
|
mounted() {
|
setTimeout(() => {
|
console.log('projectEndDate', getProjectEndDate())
|
this.modelShow()
|
}, 1000)
|
},
|
updated() {
|
if (this.$refs.panoiframe) {
|
// IE
|
if (this.$refs.panoiframe.attachEvent) {
|
this.$refs.panoiframe.attachEvent('onload', () => {
|
console.log('loading')
|
// 加载成功
|
this.isLoading = false;
|
});
|
} else {
|
this.$refs.panoiframe.onload = () => {
|
console.log('loading2')
|
// 加载成功
|
this.isLoading = false;
|
};
|
}
|
}
|
},
|
|
methods: {
|
getItemImg (item) {
|
return `${window.ProjectConfig.panoBaseUrl}/Panorama${this.panoObj.PbUrl}/vtour/panos/${item.PsScenename}.tiles/thumb.jpg`
|
},
|
handleZoomOut() {
|
console.log('放大')
|
this.isFullScreen = !this.isFullScreen
|
if (this.isFullScreen) {
|
const clientX = document.documentElement.clientWidth || document.body.clientWidth
|
const clientY = document.documentElement.clientHeight || document.body.clientHeight
|
this.fullScreenStyle = `width: ${clientX - 40}px; height: ${clientY - 120}px; margin:20px; position: fixed; top: 80px; left: 0;z-index: 100;background-color: #fff;overflow: hidden;`
|
if (this.currentView === '720') {
|
this.fullScreenPanoStyle = `width: 100%; height: 100%; z-index: 100; `
|
} else if(this.currentView === 'model'){
|
this.fullScreenModelStyle = `width: ${clientX - 40}px; height: ${clientY - 120}px; margin:20px; position: fixed; top: 80px; left: 0;z-index: 100;background-color: #fff;overflow: hidden;`
|
}
|
}
|
},
|
handleChange(view) {
|
this.isLoading = true
|
this.currentView = view
|
if (view === 'model') {
|
nextTick(() => {
|
this.modelShow()
|
})
|
} else if (view === '720') {
|
nextTick(() => {
|
this.panoShow()
|
})
|
} else if (view === 'project') {
|
nextTick(() => {
|
this.getProjectLive(this.selectedId)
|
})
|
}
|
},
|
handlePanoChange(value) {
|
console.log('value', value)
|
this.isLoading = true
|
this.panoList.forEach(item => {
|
if (item.LabelId === value[0]) {
|
item.Children.forEach(item2 => {
|
if (item2.PbGuid === value[1]) {
|
this.panoObj = item2
|
console.log('panoObj', this.panoObj)
|
this.getPanoPhase(item2)
|
}
|
})
|
}
|
})
|
},
|
modelShow() {
|
const iframe = document.getElementById('model-iframe')
|
const token = getToken()
|
const projectId = this.projectId
|
let ifrSrc = ''
|
console.log('模型中查看')
|
// ifrSrc = `${window.ProjectConfig.modelUrl}?token=${token}&projectId=${projectId}&isPreview=1&edit=false`
|
ifrSrc = window.ProjectConfig.modelUrl
|
iframe.src = ifrSrc
|
console.log('加载iframe地址', ifrSrc)
|
this.isLoading = false
|
},
|
panoShow() {
|
const data = {
|
projectId: this.projectId
|
}
|
HomeAPI.GetProjectPanoramaList(data).then(res => {
|
console.log('全景图', res)
|
if (res.Ret === 1) {
|
const result = res.Data
|
if (result.length > 0) {
|
result.forEach(element => {
|
element.id = element.LabelId
|
element.label = element.LabelName
|
element.Children.forEach(item => {
|
item.id = item.PbGuid
|
item.label = item.PbName
|
});
|
});
|
this.panoList = result
|
this.panoValue = [result[0].id, result[0].Children[0].id]
|
this.panoObj = result[0].Children[0]
|
this.getPanoPhase()
|
}
|
}
|
})
|
|
},
|
getPanoPhase() {
|
const data = {
|
pbguid: this.panoObj.PbGuid
|
}
|
HomeAPI.GetScenesByPbGuid(data).then(res => {
|
console.log('全景图阶段', res)
|
if (res.Ret === 1) {
|
this.panoVersionList = res.Data
|
this.panoPreview(this.panoObj, this.panoVersionList[0])
|
}
|
})
|
},
|
panoPreview(item, scene) {
|
// /LinkShare/PanoShare/:PanoId/:organizeId/:StartScene
|
// PanoId:全景图的id,organizeId:项目id,StartScene:初始场景id
|
const panoFrame = document.getElementById('panoviewpreview')
|
nextTick(() => {
|
if(panoFrame.src){
|
panoFrame.removeAttribute("src"); //先移除上一次的src地址
|
}
|
setTimeout(()=>{
|
let ifrSrc = ''
|
ifrSrc = `${window.ProjectConfig.panoUrl}/#/LinkShare/PanoShare/${scene.PbGuid}/${this.projectId}/${scene.PsScenename}`
|
panoFrame.setAttribute("src",ifrSrc);
|
}, 300)
|
|
})
|
// removepano('krpanoSWFObject')
|
// const basepath = `${window.ProjectConfig.panoUrl}/Panorama${item.PbUrl}/vtour/`
|
// const xmlurl = `${basepath}tour.xml?r=${(Math.random() * 100000 + 1)}`
|
// let setting = {}
|
// if (scene) {
|
// const scenename = 'scene_' + scene.PsScenename
|
// setting = {
|
// startscene: scenename
|
// }
|
// }
|
// this.$nextTick(() => {
|
// embedpano({
|
// xml: xmlurl,
|
// target: 'panoviewpreview',
|
// basepath,
|
// vars: setting,
|
// html5: 'auto',
|
// passQueryParameters: true,
|
// })
|
// })
|
},
|
sceneShow() {
|
const iframe = document.getElementById('scene-iframe')
|
let ifrSrc = ''
|
ifrSrc = window.ProjectConfig.sceneUrl
|
iframe.src = ifrSrc
|
this.isLoading = false
|
},
|
mounted() {
|
this.isLoading = true
|
this.modelShow()
|
},
|
/**
|
* 获取项目实况数据
|
* @param {string} bindId - 标段ID
|
*/
|
getProjectLive(bindId) {
|
const params = {
|
bindId,
|
};
|
HomeAPI.GetJSCProjectMonitor(params).then(res => {
|
if (res.Ret === 1) {
|
const result = res.Data
|
if (result.length > 0) {
|
console.log('实况数据', result);
|
result.forEach(element => {
|
element.id = element.BindId
|
element.label = element.BindName
|
element.JSCProjectMonitorList.forEach(item => {
|
item.id = item.MonitorUrl
|
item.label = item.MonitorName
|
});
|
});
|
}
|
this.isLoading = false
|
this.liveList = result
|
this.liveValue = [result[0].id, result[0].JSCProjectMonitorList[0].id]
|
this.videoSrc = this.liveList[0].JSCProjectMonitorList[0].MonitorUrl
|
this.loadVideo();
|
}
|
})
|
},
|
/**
|
* 处理实况的实时变化
|
* @param value
|
*/
|
handleLiveChange(value) {
|
console.log('实况变化', value);
|
this.videoSrc = value[1]
|
this.loadVideo();
|
},
|
// 检查FLV支持
|
checkFlvSupport() {
|
if (!flvjs.isSupported()) {
|
this.errorMessage = '当前浏览器不支持FLV播放'
|
this.playerStatus = '不支持'
|
return false
|
}
|
this.playerStatus = '已就绪'
|
return true
|
},
|
/**
|
* 销毁播放器实例
|
*/
|
destroyPlayer() {
|
if (this.flvPlayer) {
|
try {
|
this.flvPlayer.pause()
|
this.flvPlayer.unload()
|
this.flvPlayer.detachMediaElement()
|
this.flvPlayer.destroy()
|
this.flvPlayer = null
|
} catch (error) {
|
console.error('销毁播放器时出错:', error)
|
}
|
}
|
this.isReady = false
|
},
|
/**
|
* 加载视频
|
*/
|
loadVideo() {
|
if (!this.videoSrc.trim()) {
|
this.errorMessage = '请播放有效的视频URL'
|
return
|
}
|
|
if (!this.checkFlvSupport()) {
|
return
|
}
|
this.errorMessage = ''
|
this.playerStatus = '加载中...'
|
|
try {
|
// 销毁旧的播放器实例
|
this.destroyPlayer()
|
|
// 创建FLV播放器
|
this.flvPlayer = flvjs.createPlayer({
|
type: 'flv',
|
url: this.videoSrc,
|
isLive: false, // 如果是直播流,设置为true
|
cors: true,
|
withCredentials: false
|
}, {
|
enableWorker: false,
|
enableStashBuffer: true,
|
stashInitialSize: 128,
|
autoCleanupSourceBuffer: true
|
})
|
|
// 绑定事件监听器
|
// this.bindPlayerEvents()
|
|
// 绑定到video元素
|
this.flvPlayer.attachMediaElement(this.$refs.videoElement)
|
|
// 开始加载
|
this.flvPlayer.load()
|
|
} catch (error) {
|
console.error('加载视频失败:', error)
|
this.errorMessage = '视频加载失败: ' + error.message
|
this.playerStatus = '加载失败'
|
}
|
},
|
}
|
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.home-container {
|
display: flex;
|
flex-direction: column;
|
height: calc(100vh - 100px);
|
overflow: hidden;
|
}
|
|
.top-nav {
|
height: 5vh;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
color: white;
|
}
|
|
.bottom-nav {
|
flex: 1;
|
}
|
|
.nav-items {
|
display: flex;
|
gap: 20px;
|
}
|
|
.nav-item {
|
background: rgba(112, 119, 140, 0.3);
|
border-radius: 2px;
|
border: 1px solid rgba(112, 124, 140, 0.6);
|
padding: 5px 16px;
|
cursor: pointer;
|
}
|
|
.nav-item.active {
|
background: rgba(255, 191, 0, 0.2);
|
border-radius: 2px;
|
border: 1px solid #FFBF00;
|
}
|
|
.time-info {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
width: 200px;
|
}
|
|
.time-info-item {
|
display: flex;
|
align-items: center;
|
|
}
|
|
.time-line {
|
width: 200px;
|
height: 1px;
|
background: linear-gradient(270deg, rgba(255, 191, 0, 0) 0%, #FFBF00 100%);
|
}
|
|
.content-wrapper {
|
display: flex;
|
overflow: hidden;
|
position: relative;
|
height: 98%;
|
}
|
|
.chart-content {
|
width: 100%;
|
height: calc(100% - 52% - 20px);
|
}
|
|
.side-menu {
|
width: 160px;
|
color: white;
|
position: absolute;
|
top: 10px;
|
left: 10px;
|
right: auto;
|
bottom: auto;
|
|
::v-deep .el-cascader {
|
width: 100%;
|
height: 100%;
|
|
.el-cascader-node__label {
|
color: #fff;
|
}
|
|
.el-input .el-input__inner {
|
background: rgba(33, 72, 115, 0.9);
|
}
|
}
|
}
|
|
.menu-dropdown {
|
padding: 15px;
|
}
|
|
.menu-select {
|
width: 100%;
|
padding: 8px;
|
background-color: #0a1931;
|
color: white;
|
border: 1px solid #2a4d7d;
|
}
|
|
.menu-list {
|
border-top: 1px solid #2a4d7d;
|
}
|
|
.menu-item {
|
padding: 12px 20px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
cursor: pointer;
|
}
|
|
.menu-item:hover {
|
background-color: rgba(255, 255, 255, 0.1);
|
}
|
|
.arrow-icon {
|
border: solid white;
|
border-width: 0 2px 2px 0;
|
display: inline-block;
|
padding: 3px;
|
transform: rotate(-45deg);
|
}
|
|
.submenu {
|
background-color: #152b4a;
|
}
|
|
.submenu-item {
|
padding: 10px 30px;
|
font-size: 14px;
|
cursor: pointer;
|
}
|
|
.submenu-item:hover {
|
background-color: rgba(255, 255, 255, 0.1);
|
}
|
|
.main-content {
|
flex: 1;
|
background-color: #fff;
|
width: 100%;
|
height: 100%;
|
}
|
|
.content-header {
|
color: white;
|
margin-bottom: 20px;
|
}
|
|
.chart-container {
|
padding: 20px;
|
width: 100%;
|
height: calc(100% - 5vh);
|
}
|
|
.chart-legend {
|
display: flex;
|
gap: 20px;
|
margin-bottom: 20px;
|
color: white;
|
}
|
|
.legend-item {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
}
|
|
.dot {
|
width: 10px;
|
height: 10px;
|
border-radius: 50%;
|
}
|
|
.dot.blue {
|
background-color: #00ffff;
|
}
|
|
.dot.yellow {
|
background-color: #ffd700;
|
}
|
|
.chart-area {
|
height: 400px;
|
margin-bottom: 20px;
|
}
|
|
.chart-tabs {
|
display: flex;
|
gap: 10px;
|
}
|
|
.tab {
|
padding: 8px 16px;
|
color: white;
|
cursor: pointer;
|
border-radius: 4px;
|
}
|
|
.tab.active {
|
background-color: #2a4d7d;
|
}
|
</style><style lang="scss">
|
.custom-dropdown {
|
background-color: rgba(33, 72, 115, 0.9);
|
border-radius: 2px;
|
border: 1px solid #3068A5;
|
|
.el-cascader-menu {
|
color: #fff;
|
|
.el-cascader-node__label {
|
color: #fff;
|
}
|
}
|
|
.el-cascader .el-input .el-input__inner:focus,
|
.el-cascader .el-input.is-focus .el-input__inner {
|
height: 28px;
|
line-height: 28px;
|
}
|
|
.el-cascader .el-input .el-input__inner {
|
height: 28px;
|
line-height: 28px;
|
background: rgba(33, 72, 115, 0.9);
|
}
|
|
.el-input__icon {
|
line-height: 38px;
|
}
|
|
.el-cascader-node:not(.is-disabled):focus,
|
.el-cascader-node:not(.is-disabled):hover {
|
background: #3068A5;
|
}
|
|
.popper__arrow {
|
display: none;
|
}
|
|
.el-scrollbar__wrap {
|
overflow: hidden;
|
margin-bottom: 0px !important;
|
margin-right: 0px !important;
|
}
|
}
|
</style>
|