场景从自己建的组件库中选择组件选中后渲染到页面的模块中。templatedivclassdashbordBoxdivclasstopBoxdivclasstLeftBox/divdivclasstMidBox/divdivclasstRightBox/div/divdivclassbtmBoxdivclassbLeftpclassiconBoxclickeditHandle(1)el-iconcolor#999size18Edit//el-icon/pcomponentv-ifmoduleData[1].key compMap[moduleData[1].key]:iscompMap[moduleData[1].key]//divdivclassbRightdivclassrTopBoxdivclassrwBoxpclassiconBoxclickeditHandle(2)el-iconcolor#999size18Edit//el-icon/pcomponentv-ifmoduleData[2].key compMap[moduleData[2].key]:iscompMap[moduleData[2].key]//divdivclassrcBoxpclassiconBoxclickeditHandle(3)el-iconcolor#999size18Edit//el-icon/p!-- BarChart refbarChartsChild/BarChart --componentv-ifmoduleData[3].key compMap[moduleData[3].key]:iscompMap[moduleData[3].key]//div/divdivclassrBtmBox/div/div/divel-dialogv-modelstate.comDialogtitle组件库v-ifstate.comDialogwidth90%stylemargin-top:4%divclasscomBoxdivclassxxBoxclickselectComp(msg)XxCom/XxCom/divdivclassrwBoxclickselectComp(task)RwCom/RwCom/divdivclasschartBoxclickselectComp(chart)BarChartrefbarChartsChild/BarChart/div!-- div classzbBox p值班表值班表值班表值班表值班表值班表值班表值班表/p /div --/div/el-dialog/div/templatescriptsetupimport{onMounted,reactive,ref,nextTick,watch,computed}fromvueimport*asechartsfromechartsimportBarChartfrom/components/chart/barChart.vueimportXxComfrom/components/text/xx.vueimportRwComfrom/components/text/rw.vueconstbarChartsChildref(null)// 组件映射key对应组件实例constcompMap{msg:XxCom,task:RwCom,chart:BarChart}// 记录当前正在操作的模块idletactiveModuleIdnullconststatereactive({comDialog:false,})// localStorage存储key全局唯一constSTORAGE_KEYmoduleCache// 默认初始化数据constdefaultModuleData{1:{key:},2:{key:},3:{key:},4:{key:}}// 读取本地缓存合并默认值letcacheStrlocalStorage.getItem(STORAGE_KEY)letcacheDatanulltry{if(cacheStr){cacheDataJSON.parse(cacheStr)}}catch(err){// 缓存损坏时清空防止页面报错localStorage.removeItem(STORAGE_KEY)cacheDatanull}// 合并缓存与默认配置保证4个模块一定存在constmoduleDatareactive({...defaultModuleData,// 兜底保证 1/2/3/4 一定存在key 默认空字符串...(cacheData||{})// 用本地缓存覆盖默认值有则替换无则保留默认})// 监听数据自动持久化watch(moduleData,(newVal){localStorage.setItem(STORAGE_KEY,JSON.stringify(newVal))},{deep:true})// 打开弹窗记录当前点击的模块编号consteditHandle(moduleId){activeModuleIdmoduleId state.comDialogtrue}// 弹窗选中组件赋值给对应模块constselectComp(compKey){if(!activeModuleId)return// 给当前操作模块赋值组件moduleData[activeModuleId].keycompKey// 关闭弹窗state.comDialogfalse}onMounted((){barChartsChild?.value?.initChart()//只用于弹框中图表初始化展示})/scriptstylelangscssscoped.dashbordBox{width:100%;height:100%;.topBox{width:100%;height:20%;//padding:.5% 1%;margin-bottom:1%;display:flex;justify-content:space-between;align-items:center;//flex-wrap:wrap;.tLeftBox{width:20%;height:100%;background-color:#fff;}.tMidBox{width:60%;height:100%;background-color:#fff;}.tRightBox{width:18%;height:100%;background-color:#fff;}}.btmBox{display:flex;justify-content:space-between;align-items:center;width:100%;height:78%;.bLeft{width:28%;height:100%;background-color:#fff;}.bRight{width:71%;height:100%;//background-color:pink;.rTopBox{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.2%;width:100%;height:75%;.rwBox{width:63.5%;height:100%;background-color:#fff;}.rcBox{position:relative;width:35%;height:100%;background-color:#fff;.iconBox{position:absolute;right:0;top:0;z-index:1;}}}.rBtmBox{width:100%;height:22.5%;background-color:#fff;}}}:deep(.el-dialog__body){height:82vh;}.comBox{display:flex;flex-wrap:wrap;gap:12px;/* 模块间距按需调整 */width:100%;height:100%;overflow:auto;.xxBox, .rwBox, .chartBox, .zbBox{width:24.4%;height:36%;background:#f5f7fa;border-radius:8px;padding:12px;overflow-y:auto;/* 内容超出时滚动 */}}}/style组件分页面chart组件templatedivrefbarChartclassbarChart/div/templatescriptsetupimport{ref,onMounted,reactive,onBeforeUnmount,nextTick}fromvueimport*asechartsfromecharts;constbarChartref(null)conststatereactive({myChart:null})constinitChart(res,type){// 如果实例已存在先销毁if(state.myChart){state.myChart.dispose()state.myChartnull}state.myChartecharts.init(barChart.value)// if (state.myChart null) {// state.myChart echarts.init(barChart.value)// }letoption{// title: {// text: 标题,// x: 2%,// y: 3%,// left:2%,// },tooltip:{trigger:axis,axisPointer:{type:shadow,},},grid:{top:16%,left:3%,right:4%,bottom:4%,containLabel:true,},xAxis:[{type:category,data:[名称1,名称2,名称3,名称4,名称5],axisTick:{alignWithLabel:true,},axisLabel:{// color: #65c0ff,rotate:26,formatter:(val){returnval.length5?val.substring(0,6)...:val}},},],yAxis:[{type:value,axisLabel:{// color: #65c0ff,},axisLine:{show:true,//纵轴刻度线},splitLine:{show:true,lineStyle:{type:dashed,color:#ccc,},},},],series:[{name:,type:bar,barWidth:36%,data:[10,52,200,334,490],itemStyle:{color:newecharts.graphic.LinearGradient(0,0,0,1,[{offset:0,color:#5f86ff},{offset:1,color:#a1b8ff}]),},},],}state.myChart.setOption(option)window.addEventListener(resize,(){state.myChart.resize()})}defineExpose({initChart})onMounted((){nextTick((){initChart()})})onBeforeUnmount((){window.removeEventListener(resize,(){state.myChart.resize()})if(state.myChart){state.myChart.dispose()state.myChartnull}})/scriptstylelangscssscoped.barChart{width:100%;height:100%;//min-height:300px;}/style2.xx组件templatedivclassxxContainer消息中心 消息中心 消息中心 消息中心 消息中心 消息中心/div/templatescriptsetupimport{ref,onMounted,reactive,}fromvueconststatereactive({})onMounted((){})/scriptstylelangscssscoped.xxContainer{width:100%;height:100%;}/stylerw组件template div classrwContainer 任务中心 任务中心 /div /template script setup import { ref, onMounted, reactive, } from vue const state reactive({ }) onMounted((){}) /script style langscss scoped .rwContainer { width: 100%; height: 100%; } /style