静态大屏组件
This commit is contained in:
1328
src/views/bigscreenDesigner/viewer/components/static.vue
Normal file
1328
src/views/bigscreenDesigner/viewer/components/static.vue
Normal file
File diff suppressed because it is too large
Load Diff
260
src/views/bigscreenDesigner/viewer/static.vue
Normal file
260
src/views/bigscreenDesigner/viewer/static.vue
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<!--
|
||||||
|
* @Descripttion: 大屏设计器 -- 预览
|
||||||
|
* @Author: Devli
|
||||||
|
* @Date: 2021-3-13 11:04:24
|
||||||
|
* @Last Modified by: Raod
|
||||||
|
* @Last Modified time: 2022-5-6 11:04:24
|
||||||
|
!-->
|
||||||
|
<template>
|
||||||
|
<div class="layout">
|
||||||
|
<div :style="bigScreenStyle" class="drillDrownViewLayout">
|
||||||
|
<!-- 关键优化 1: v-if 包裹整个渲染区域,避免空数据时渲染 -->
|
||||||
|
<template v-if="dataLoaded">
|
||||||
|
<!-- 关键优化 2: 分批渲染,避免一次性创建过多 DOM 节点 -->
|
||||||
|
<static-content :screenData="screenData"></static-content>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<el-dialog :title="''" class="dialogDrillDrown dialogDrillDrownView" :visible.sync="visiableDrillView">
|
||||||
|
<drill-drown-view :screenData="screenData"></drill-drown-view>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import staticContent from "./components/static";
|
||||||
|
import DrillDrownView from "./drillDrownView";
|
||||||
|
|
||||||
|
import { detailDashboard } from "@/api/bigscreen";
|
||||||
|
export default {
|
||||||
|
name: "Login",
|
||||||
|
components: {
|
||||||
|
staticContent,
|
||||||
|
DrillDrownView
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bigScreenStyle: {},
|
||||||
|
dashboard:{},
|
||||||
|
widgets: [],
|
||||||
|
screenData:{
|
||||||
|
dashboard: { },
|
||||||
|
widgets: []
|
||||||
|
},
|
||||||
|
visiableDrillView:false,
|
||||||
|
dataLoaded: false, // 数据加载标志
|
||||||
|
refreshTimer: null, // 定时刷新定时器
|
||||||
|
renderBatches: [], // 分批渲染的批次
|
||||||
|
batchSize: 10, // 每批渲染的组件数量 (轻量级)
|
||||||
|
renderTimer: null, // 分批渲染定时器
|
||||||
|
renderedCount: 0 // 已渲染的组件数量
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getData();
|
||||||
|
window.onresize=this.Debounce(this.setScale,500);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
console.log('[Viewer] beforeDestroy 开始清理资源');
|
||||||
|
|
||||||
|
// 1. 清除定时刷新定时器
|
||||||
|
if (this.refreshTimer) {
|
||||||
|
clearTimeout(this.refreshTimer);
|
||||||
|
this.refreshTimer = null;
|
||||||
|
console.log('[Viewer] 已清除定时刷新定时器');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 清除分批渲染定时器
|
||||||
|
if (this.renderTimer) {
|
||||||
|
clearTimeout(this.renderTimer);
|
||||||
|
this.renderTimer = null;
|
||||||
|
console.log('[Viewer] 已清除分批渲染定时器');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 清空大型数据引用,释放内存
|
||||||
|
this.widgets = [];
|
||||||
|
this.renderBatches = [];
|
||||||
|
this.dashboard = {};
|
||||||
|
this.screenData = { dashboard: {}, widgets: [] };
|
||||||
|
|
||||||
|
// 4. 移除 window 事件监听
|
||||||
|
if (window.onresize) {
|
||||||
|
window.onresize = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[Viewer] 资源清理完成');
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
oepnTheDrillView(val){
|
||||||
|
this.screenData=val
|
||||||
|
this.visiableDrillView=true
|
||||||
|
},
|
||||||
|
async getData() {
|
||||||
|
try {
|
||||||
|
const reportCode = 'demotest';
|
||||||
|
const { code, data } = await detailDashboard(reportCode);
|
||||||
|
console.log(data)
|
||||||
|
if (code != 200) {
|
||||||
|
console.error('[Viewer] 获取大屏数据失败:', code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dashboard = data.dashboard || {};
|
||||||
|
const equipment = document.body.clientWidth;
|
||||||
|
const ratioEquipment = equipment / data.dashboard.width;
|
||||||
|
const ratioEquipmentHeight = window.innerHeight / data.dashboard.height;
|
||||||
|
this.bigScreenStyle = {
|
||||||
|
width: data.dashboard.width + "px",
|
||||||
|
height: data.dashboard.height + "px",
|
||||||
|
"background-color": data.dashboard.backgroundColor,
|
||||||
|
"background-image": "url(" + data.dashboard.backgroundImage + ")",
|
||||||
|
"background-position": "0% 0%",
|
||||||
|
"background-size": "100% 100%",
|
||||||
|
"background-repeat": "initial",
|
||||||
|
"background-attachment": "initial",
|
||||||
|
"background-origin": "initial",
|
||||||
|
"background-clip": "initial",
|
||||||
|
transform: `scale(${ratioEquipment}, ${ratioEquipmentHeight})`,
|
||||||
|
"transform-origin": "0 0"
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关键优化:冻结组件数据,避免 Vue 的响应式系统占用大量内存
|
||||||
|
const frozenWidgets = Object.freeze(data.dashboard.widgets.map((item, index) => {
|
||||||
|
item.value.widgetId = item.value.setup.widgetId;
|
||||||
|
item.value.widgetCode = item.value.setup.widgetCode;
|
||||||
|
if (item.value.setup.componentLinkage && item.value.setup.componentLinkage.length) {
|
||||||
|
this.$store.commit('SET_ALL_COMPONENT_LINKAGE', {
|
||||||
|
index,
|
||||||
|
widgetId: item.value.widgetId,
|
||||||
|
linkageArr: item.value.setup.componentLinkage
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 赋值给 widgets 用于分批渲染
|
||||||
|
this.widgets = frozenWidgets;
|
||||||
|
|
||||||
|
console.log(`[Viewer] 数据加载完成,共 ${this.widgets.length} 个组件,开始分批渲染`);
|
||||||
|
|
||||||
|
// 标记数据已加载
|
||||||
|
this.dataLoaded = true;
|
||||||
|
|
||||||
|
// 开始分批渲染组件
|
||||||
|
this.startBatchRender();
|
||||||
|
|
||||||
|
// 定时刷新 - 保存定时器引用以便清理
|
||||||
|
if(data.dashboard.refreshSeconds > 0) {
|
||||||
|
this.refreshTimer = setTimeout(() => {
|
||||||
|
console.log('[Viewer] 定时刷新触发');
|
||||||
|
window.location.reload();
|
||||||
|
}, data.dashboard.refreshSeconds * 1000);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Viewer] 获取数据异常:', error);
|
||||||
|
this.dataLoaded = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Debounce:(fn,t)=>{
|
||||||
|
const delay=t||500;
|
||||||
|
let timer=null;
|
||||||
|
return(...args)=>{
|
||||||
|
if(timer){
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
const context=this
|
||||||
|
timer=setTimeout(()=>{
|
||||||
|
fn.apply(context,args);
|
||||||
|
},delay);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setScale(){
|
||||||
|
const scale=this.getScale();
|
||||||
|
// this.bigScreenStyle.transform='scale('+scale.scalex+','+scale.scaley+')'
|
||||||
|
this.bigScreenStyle.transform = `scale(${scale.scalex},${scale.scaley})`
|
||||||
|
},
|
||||||
|
getScale(){
|
||||||
|
let width = this.dashboard.width
|
||||||
|
let height = this.dashboard.height
|
||||||
|
// 固定宽度比例
|
||||||
|
const scalex = window.innerWidth / width
|
||||||
|
// // 高度按相同比例缩放,但允许超出屏幕高度
|
||||||
|
// const scaley = scalex
|
||||||
|
// 高度按屏幕高度比例
|
||||||
|
const scaley = window.innerHeight / height
|
||||||
|
|
||||||
|
return {
|
||||||
|
scalex,
|
||||||
|
scaley
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 分批渲染组件,避免一次性创建过多 DOM 节点导致页面卡顿
|
||||||
|
*/
|
||||||
|
startBatchRender() {
|
||||||
|
this.renderedCount = 0;
|
||||||
|
this.renderBatches = [];
|
||||||
|
|
||||||
|
const renderNextBatch = () => {
|
||||||
|
if (this.renderedCount >= this.widgets.length) {
|
||||||
|
console.log('[Viewer] 所有组件渲染完成,总数:', this.widgets.length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算本批次要渲染的组件
|
||||||
|
const start = this.renderedCount;
|
||||||
|
const end = Math.min(start + this.batchSize, this.widgets.length);
|
||||||
|
|
||||||
|
// 使用 slice 创建新批次,避免引用原数组
|
||||||
|
const batch = Object.freeze(this.widgets.slice(start, end));
|
||||||
|
|
||||||
|
// 添加到渲染批次
|
||||||
|
this.renderBatches.push(batch);
|
||||||
|
this.renderedCount = end;
|
||||||
|
|
||||||
|
console.log(`[Viewer] 渲染第 ${this.renderBatches.length} 批,组件 ${start}-${end-1}`);
|
||||||
|
|
||||||
|
// 继续渲染下一批
|
||||||
|
if (this.renderedCount < this.widgets.length) {
|
||||||
|
this.renderTimer = setTimeout(renderNextBatch, 100); // 每批间隔 100ms
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 开始渲染第一批
|
||||||
|
renderNextBatch();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.layout {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.dialogDrillDrownView .el-dialog{
|
||||||
|
width:auto;
|
||||||
|
margin-top:0 !important;
|
||||||
|
transform: scale(0.6, 0.6);
|
||||||
|
.el-dialog__body{
|
||||||
|
padding:0;
|
||||||
|
max-height:calc(100vh - 34px);
|
||||||
|
overflow:auto;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none; /* 隐藏滚动条 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-dialog__header .el-dialog__headerbtn{
|
||||||
|
top: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bottom-text {
|
||||||
|
width: 100%;
|
||||||
|
color: #a0a0a0;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 16px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user