<template>
<!-- 八大主题右侧 -->
<div id="indicatorPanel" style="width: 100%;height: 100%;">
<!-- 左侧导航 -->
<div class="left-div" v-if="!isExpand">
<div :class="getDivStyle('title', index)" v-for="(item,index) in useList" :key="item.name || index" @click="handleChange(index)">
<div class="text-title">
{{ item.name }}
</div>
</div>
</div>
<!-- 右侧内容:指标卡片 -->
<div :class="isExpand ? 'right-div right-div-width2' : 'right-div right-div-width1'">
<div style="width: 70%; height: 6%;" class="div-title">
<el-image
v-if="title"
style="width: 17px; height: 24px; margin-right: 5px;"
:src="require('@/src/images/gdGridMap/homePage/eightMajorThemes/location.png')"
fit="contain">
</el-image>
<span>{{ title }}</span>
</div>
<div class="div-expand">
<el-link type="info" @click="handleExpand">
{{ title ? (isExpand ? '收起 >>' : '展开全部 <<') : '' }}
</el-link>
</div>
<div :style="'width: 100%; height: 1%;' + (title && !isExpand ? 'border-top: 1px dashed #a6a9ad;' : '')"></div>
<div class="theme-content" @scroll="handleScroll">
<div :id="'theme_'+index" v-for="(item, index) in loadList" :key="item.name || index" style="width: 100%;">
<div class="cardNameClass" v-if="isExpand">
{{ item.name }}
</div>
<theme-items :items="getCard(item.cardList)" :ref="'themeItemsRef'+index" :year-month="yearMonth"></theme-items>
</div>
</div>
</div>
</div>
</template>
<script>
import {myMixins} from "../../mixins/myMixins";
import {targetCardData} from "../../themecard/targetCardData"
import themeItems from "../../themecard/ThemeItems";
export default {
mixins: [myMixins],
name: 'eightMajorThemesRight',
components: {
themeItems
},
props:{
yearMonth: { // 年月
type: String,
default: '202508'
}
},
data() {
return {
isExpand: false, // 展开全部
activeName: 0, //默认展开面板
title: '',
nodeBm: '',
themeList: [
{
name: '供电质量',
cardList: [
{cardName: '', name: 'powerQualityCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '基础管理',
cardList: [
{cardName: '', name: 'baseManageCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '诉求处置',
cardList: [
{cardName: '', name: 'appealHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '停电处置',
cardList: [
{cardName: '', name: 'outageHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '外部协同',
cardList: [
{cardName: '', name: 'externalCollaborationCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '网格建设',
cardList: [
{cardName: '', name: 'gridConstructCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '业务受理',
cardList: [
{cardName: '', name: 'businessAcceptanceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
},
{
name: '主动服务',
cardList: [
{cardName: '', name: 'activeServiceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]},
]
}
],
useList: [],
loadList: [],
observer: null,
isManualScroll: false, // 是否正在手动点击跳转
}
},
mounted() {
window.addEventListener('resize', () => {
for (const key in this.loadList) {
let themeItemsRefName = 'themeItemsRef' + key;
if (this.$refs[themeItemsRefName]) {
setTimeout(() => this.$refs[themeItemsRefName][0].$emit("resize"), 500);
}
}
})
},
watch: {
loadList: {
handler(newValue, oldValue) {
this.$nextTick(() => this.observeTheme());
},
immediate: true, // 创建时立即执行一次 handler 回调
deep: true //深度监听 loadList 内部嵌套属性的变化
},
},
methods: {
/* 数据来源,必须与myMixins方法同名 */
changeData(val) {
this.title = val.nodeMc
this.$nextTick(() => {
this.useList = JSON.parse(JSON.stringify(this.themeList));
this.loadList = this.useList;
});
if (this.nodeBm != val.nodeBm) { //地址切换面板滚到顶部
this.nodeBm = val.nodeBm;
if (!val.roll) {
this.handleChange(0);
}
}
},
handleChange(val, name) {
/* if (this.loadList.length != this.useList.length) {
if (val > this.activeName) {
this.loadList = this.useList.slice(0, val + 1);
}
} */
this.activeName = val;
this.isManualScroll = true; // 标记为手动操作,防止 Observer 干扰
this.$nextTick(() => {
let mainContainer = $('.theme-content')
let scrollToContainer = mainContainer.find('#theme_' + val);
if (name) {
scrollToContainer = mainContainer.find('#' + name);
}
mainContainer.animate({
scrollTop: scrollToContainer.offset().top - mainContainer.offset().top + mainContainer.scrollTop()
}, 1000);
// 手动滚动结束后,清除标志(防抖)
setTimeout(() => {
this.isManualScroll = false;
}, 1000); // 与滚动动画时间一致
})
},
getDivStyle(style, index) {
if (style == "title") {
return index === this.activeName ? 'theme-title title-highlight' : 'theme-title';
}
},
/* 展开全部 */
handleExpand() {
this.isExpand = !this.isExpand;
this.$store.state.isExpand = this.isExpand;
},
handleScroll(event) {
const {scrollTop, clientHeight, scrollHeight} = event.target;
if (scrollTop + clientHeight >= scrollHeight) {
/* if (this.loadList.length != this.useList.length) {
this.loadList = this.useList.slice(0, this.activeName + 2);
} */
}
},
getCard(cardList) {
let list = cardList.filter(item => item.level.includes(parseInt(this.$store.state.indicatorData.nodeJbdm)));
list.forEach(item => {
let find = targetCardData().targetCardArr.find(it => it.name == item.name);
item.id = find.id;
if (!item.hasOwnProperty('space')) {
item.space = find.space;
}
if (!item.hasOwnProperty('isShow')) {
item.isShow = true;
}
});
return list;
},
/* 滚动监听,用于动态更新 activeName */
observeTheme() {
// (0) 清理之前的观察器(避免重复创建)
if (this.observer) {
this.observer.disconnect();
}
// (1)配置观察器选项
const options = {
root: document.querySelector('.theme-content'), // 观察的根元素(滚动容器)
rootMargin: "0px", // 根元素的外边距(无扩展)
threshold: 0.5, // 触发回调的交叉比例阈值(50%可见)
};
// (2)收集目标元素
let sections = [];
for (let i = 0; i < this.loadList.length; i++) {
sections.push(document.querySelector('#theme_' + i));
}
sections = sections.filter(item => item != null); // 过滤无效元素
// (3)回调函数
const callback = (entries, observer) => {
if (this.isManualScroll) return; // 手动滚动时不更新
//entries:代表观察到的目标元素的集合。 observer:代表观察者对象。
entries.forEach((entry) => {
if (entry.isIntersecting) { // 判断目标元素是否进入视口
const target = entry.target; // 获取当前目标元素
let index = sections.findIndex((section) => section === target);
this.activeName = index;
}
});
};
// (4)创建观察器并监听元素
/* let thresholds = Array(sections.length).fill(0.5);
sections.forEach((value, index) => {
options.threshold = thresholds[index];
this.observer = new IntersectionObserver(callback, options);
this.observer.observe(value);
}); */
this.observer = new IntersectionObserver(callback, options);
sections.forEach(value => this.observer.observe(value));
},
}
}
</script>
<style scoped>
#indicatorPanel {
display: flex;
}
.left-div {
height: 100%;
width: 10%;
}
.theme-title {
height: 12.2%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background: #E6EDFE;
border-radius: 10px;
border: 1px snow solid;
}
.theme-title:hover {
cursor: pointer;
}
.title-highlight {
background: #ADCFFD !important;
}
.text-title {
width: 0.1875rem;
color: #192C7D;
font-size: 0.18rem;
font-weight: bold;
}
.right-div-width1 {
width: 82%; /* 100%-左侧10%-左右内边距4%*2 */
}
.right-div-width2 {
width: 96%; /* 100%-上下内边距2%*2 */
}
.right-div {
height: 98%;
box-shadow: 0 0 10px gainsboro;
border-radius: 10px;
background-color: white !important;
overflow: hidden;
padding: 2% 4%;
text-align: center;
position: relative;
}
.div-title, .div-expand {
display: flex;
align-items: center; /* 上下居中 */
}
.div-title span {
text-align: left;
color: #354387;
font-size: 0.3rem;
font-weight: bold;
}
.div-expand {
position: absolute;
top: .25rem;
right: .4rem;
}
.div-expand .el-link {
font-size: 12px !important;
}
.theme-content {
width: 100%;
height: 93%;
overflow-y: scroll;
overflow-x: hidden;
}
.cardNameClass {
width: 30%;
color: #354387;
font-size: .25rem;
font-weight: bold;
border-bottom: solid 1px #354387;
padding-left: .2rem;
text-align: left;
}
</style>这是我的代码,主要问题出在theme_2和theme_4,因为echart图过多,内容很长
最新发布