<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">
|
<Gantt />
|
</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";
|
import Gantt from "@/components/Gantt.vue";
|
export default {
|
name: "Home",
|
components: { Gantt },
|
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>
|