基础信息完善

This commit is contained in:
王兴凯 2026-05-13 08:46:08 +08:00
commit 2a424cc3d6
9 changed files with 7123 additions and 5169 deletions

View File

@ -944,6 +944,351 @@ const BasicColumns: Array<any> = [
}
];
// 水温基础信息
const wtPointColumns: Array<any> = [
{
name: '基本属性',
visible: false,
ruleTips: '',
type: '',
url: ''
},
{
name: '测站名称',
filed: 'stnm',
visible: true,
type: 'input',
url: '',
},
{
name: '测站类型',
filed: 'sttpName',
visible: true,
type: 'select',
url: '',
},
{
name: '站址',
filed: 'addvcdName',
visible: true,
type: 'input',
url: '',
},
{
name: '所属流域',
filed: 'hbrvcdName',
visible: true,
type: 'select',
url: '',
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '建成日期',
filed: 'jcdt',
visible: true,
type: 'date',
format: 'YYYY-MM-DD',
url: '',
},
{
name: '监测方式',
filed: 'mwayName',
visible: true,
type: 'select',
url: '',
},
{
name: '所属电站',
filed: 'ennm',
visible: true,
type: 'select',
url: '',
},
{
name: '',
filed: '',
visible: true,
type: '',
url: '',
},
];
//水质基础信息
const FhWpPointColumns: Array<any> = [
{
name: '基本属性',
visible: false,
ruleTips: '',
type: '',
url: ''
},
{
name: '测站名称',
filed: 'stnm',
visible: true,
type: 'input',
url: '',
},
{
name: '测站类型',
filed: 'sttpName',
visible: true,
type: 'select',
url: '',
},
{
name: '站址',
filed: 'addvcdName',
visible: true,
type: 'input',
url: '',
},
{
name: '所属流域',
filed: 'hbrvcdName',
visible: true,
type: 'select',
url: '',
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '类别',
filed: 'dtinTypeName',
visible: true,
type: 'select',
url: '',
},
{
name: '水质要求',
filed: 'wwqtgName',
visible: true,
type: 'select',
url: '',
},
{
name: '监测方式',
filed: 'mwayName',
visible: true,
type: 'select',
url: '',
},
{
name: '',
filed: '',
visible: true,
type: '',
url: '',
},
];
//栖息地基础信息 fh_point
const FhPointColumns: Array<any> = [
{
name: '基本属性',
visible: false,
ruleTips: '',
type: '',
url: ''
},
{
name: '栖息地名称',
filed: 'stnm',
visible: true,
type: 'input',
url: '',
},
{
name: '站址',
filed: 'stlc',
visible: true,
type: 'input',
url: '',
},
{
name: '所属流域',
filed: 'baseName',
visible: true,
type: 'select',
url: '',
},
{
name: '保护对象',
filed: 'protobj',
visible: true,
type: 'select',
url: '',
},
{
name: '保护范围',
filed: 'qxdbhfw',
visible: true,
type: 'input',
url: '',
},
{
name: '保护总长度(km)',
filed: 'qxdbhcd',
visible: true,
type: 'number',
toFixed: 2,
url: '',
},
{
name: '保护核心长度(km)',
filed: 'qxdbhhxcd',
visible: true,
type: 'number',
toFixed: 2,
url: '',
},
{
name: '保护外围长度',
filed: 'qxdbhwwcd',
visible: true,
type: 'number',
toFixed: 2,
url: '',
},
{
name: '保护面积(km²)',
filed: 'qxdbhmj',
visible: true,
type: 'number',
toFixed: 2,
url: '',
},
{
name: '保护河流',
filed: 'bhhl',
visible: true,
type: 'select',
url: '',
},
{
name: '保护河段',
filed: 'bhhd',
visible: true,
type: 'select',
url: '',
},
{
name: '保护措施',
filed: 'prottyp',
visible: true,
type: 'select',
url: '',
},
{
name: '保护方式',
filed: 'protmthd',
visible: true,
type: 'select',
url: '',
},
{
name: '投资(亿元)',
filed: 'inv',
visible: true,
type: 'number',
url: '',
},
];
//栖息地流量 基础信息 fh_zq_point
const FhZQPointColumns: Array<any> = [
{
name: '测站名称',
filed: 'stnm',
visible: true,
type: 'input',
url: '',
},
{
name: '测站类型',
filed: 'sttpName',
visible: true,
type: 'select',
url: '',
},
{
name: '站址',
filed: 'stlc',
visible: true,
type: 'input',
url: '',
},
{
name: '所属流域',
filed: 'baseName',
visible: true,
type: 'select',
url: '',
},
{
name: '经度(°)',
filed: 'lgtd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '纬度(°)',
filed: 'lttd',
visible: true,
type: 'number',
toFixed: 6,
url: '',
},
{
name: '建成日期',
filed: 'jcdt',
visible: true,
type: 'date',
format: 'YYYY-MM-DD',
url: '',
},
{
name: '监测方式',
filed: 'mwayName',
visible: true,
type: 'select',
url: '',
},
];
//阶段属性
const basicFilterColumns: Array<any> = [
{
@ -1651,6 +1996,10 @@ const NormalColumns: Array<any> = [];
export {
BasicColumns,
wtPointColumns,
FhWpPointColumns,
FhPointColumns,
FhZQPointColumns,
basicFilterColumns,
tabsWithTwoColumns,
tableColumns1,

File diff suppressed because it is too large Load Diff

View File

@ -87,6 +87,7 @@ watch(
watch(
() => modelStore.params,
(newVal) => {
console.log(newVal);
tabsConfig.value = handleTabs(newVal);
let value = tabsConfig.value.find((item: any) => item.default);
currentActiveKey.value = value?.key;

View File

@ -481,144 +481,144 @@ const ENGTabs: Array<any> = [
// type: 'panorama'
// }
// ]
// //鱼类栖息地 √
// const FHTabs: Array<any> = [
// {
// name: '基础信息',
// key: 'basicInfo',
// type: 'basic',
// url: '/bbi/siteBipc/getSiteBasicInfo'
// },
// {
// name: '水温监测',
// key: 'WaterTemperature',
// type: 'WaterTemperature',
// tabs: [
// {
// url: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
// name: '水温',
// type: 'WaterTemperature',
// tableUrl: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
// chartType: 'line',
//鱼类栖息地 √
const FHTabs: Array<any> = [
{
name: '基础信息',
key: 'basicInfo',
type: 'basic',
url: '/bbi/siteBipc/getSiteBasicInfo'
},
{
name: '水温监测',
key: 'WaterTemperature',
type: 'WaterTemperature',
tabs: [
{
url: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
name: '水温',
type: 'WaterTemperature',
tableUrl: '/wmp-env-server/sw/alongDetail/GetKendoListCust',
chartType: 'line',
// filter: NormalStcdFilter,
// filterProps: {
// params: {
// ftype: 'WE',
// sttp: 'WT', //WT
// dataDimensionType: 'hyBase',
// dataDimensionVal: 'all'
filterProps: {
params: {
ftype: 'WE',
sttp: 'WT', //WT
dataDimensionType: 'hyBase',
dataDimensionVal: 'all'
}
}
}
]
},
{
name: '水质监测',
key: 'WaterQuality',
type: 'WaterQuality',
tabs: [
{
url: '/wmp-env-server/env/wq/data/GetKendoListCust',
name: '水质',
type: 'monitor',
key: 'WaterQuality',
tableUrl: '/wmp-env-server/env/wq/data/GetKendoListCust',
chartType: 'lines',
// chartEvent: {
// legendselectchanged: (object: any, instance: any) => {
// const selected = object.selected
// const options = instance.getOption()
// if (options.grid instanceof Array) {
// options.grid = options.grid[0]
// }
// if (selected != undefined && options) {
// let yAxis: any = options.yAxis
// yAxis.map((item: any, index: number) => {
// item.show = false
// for (let i in selected) {
// if (selected[i] == true && item.name.indexOf(i) !== -1) {
// item.show = true
// }
// }
// })
// options.legend && (options.legend.selected = selected)
// let offset = 30
// let padding = 60
// if (options.yAxis && options.yAxis instanceof Array && options.grid && !(options.grid instanceof Array)) {
// let showYAxis = yAxis.filter((x: any) => {
// return x.show
// })
// showYAxis.map((yAxis: any, index: number) => {
// yAxis.position = index % 2 === 0 ? "left" : "right"
// yAxis.offset = padding * Math.floor(index / 2)
// if (index >= 4) {
// yAxis.offset = padding * Math.floor(2 / 2)
// }
// })
// if (showYAxis.length % 2 === 0) {
// options.grid.left = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
// options.grid.right = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
// } else {
// const left = showYAxis.filter((x: any) => x.position === "left")
// const right = showYAxis.filter((x: any) => x.position === "right")
// const left_start = left.length ? 0 : 60
// const right_start = left.length ? 0 : 60
// options.grid.left = left_start + padding * (left.length >= 2 ? 2 : left.length)
// options.grid.right = right_start + padding * (right.length >= 2 ? 2 : right.length)
// }
// }
// instance.setOption(options, false, true)
// }
// }
// ]
// },
// {
// name: '水质监测',
// key: 'WaterQuality',
// type: 'WaterQuality',
// tabs: [
// {
// url: '/wmp-env-server/env/wq/data/GetKendoListCust',
// name: '水质',
// type: 'monitor',
// key: 'WaterQuality',
// tableUrl: '/wmp-env-server/env/wq/data/GetKendoListCust',
// chartType: 'lines',
// // chartEvent: {
// // legendselectchanged: (object: any, instance: any) => {
// // const selected = object.selected
// // const options = instance.getOption()
// // if (options.grid instanceof Array) {
// // options.grid = options.grid[0]
// // }
// // if (selected != undefined && options) {
// // let yAxis: any = options.yAxis
// // yAxis.map((item: any, index: number) => {
// // item.show = false
// // for (let i in selected) {
// // if (selected[i] == true && item.name.indexOf(i) !== -1) {
// // item.show = true
// // }
// // }
// // })
// // options.legend && (options.legend.selected = selected)
// // let offset = 30
// // let padding = 60
// // if (options.yAxis && options.yAxis instanceof Array && options.grid && !(options.grid instanceof Array)) {
// // let showYAxis = yAxis.filter((x: any) => {
// // return x.show
// // })
// // showYAxis.map((yAxis: any, index: number) => {
// // yAxis.position = index % 2 === 0 ? "left" : "right"
// // yAxis.offset = padding * Math.floor(index / 2)
// // if (index >= 4) {
// // yAxis.offset = padding * Math.floor(2 / 2)
// // }
// // })
// // if (showYAxis.length % 2 === 0) {
// // options.grid.left = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
// // options.grid.right = (showYAxis.length >= 4 ? 4 : showYAxis.length) * offset
// // } else {
// // const left = showYAxis.filter((x: any) => x.position === "left")
// // const right = showYAxis.filter((x: any) => x.position === "right")
// // const left_start = left.length ? 0 : 60
// // const right_start = left.length ? 0 : 60
// // options.grid.left = left_start + padding * (left.length >= 2 ? 2 : left.length)
// // options.grid.right = right_start + padding * (right.length >= 2 ? 2 : right.length)
// // }
// // }
// // instance.setOption(options, false, true)
// // }
// // }
// // },
// filter: NormalStcdFilter,
// filterProps: {
// params: {
// ftype: 'WE',
// sttp: 'WQ',
// dataDimensionType: 'hyBase',
// dataDimensionVal: 'all'
// }
// }
// }
// ]
// },
// {
// name: '流量监测',
// key: 'FlowMeasure',
// type: 'FlowMeasure',
// tabs: [
// {
// url: '/wmp-eng-server/eng/river/GetKendoListCust',
// name: '流量',
// type: 'monitor',
// tableUrl: '/wmp-eng-server/eng/river/GetKendoListCust',
// chartType: 'line',
filterProps: {
params: {
ftype: 'WE',
sttp: 'WQ',
dataDimensionType: 'hyBase',
dataDimensionVal: 'all'
}
}
}
]
},
{
name: '流量监测',
key: 'FlowMeasure',
type: 'FlowMeasure',
tabs: [
{
url: '/wmp-eng-server/eng/river/GetKendoListCust',
name: '流量',
type: 'monitor',
tableUrl: '/wmp-eng-server/eng/river/GetKendoListCust',
chartType: 'line',
// filter: NormalStcdFilter,
// filterProps: {
// params: {
// ftype: 'WE',
// sttp: 'ZQ',
// dataDimensionType: 'hyBase',
// dataDimensionVal: 'all',
// maptype: '2'
// }
// }
// }
// ]
// },
filterProps: {
params: {
ftype: 'WE',
sttp: 'ZQ',
dataDimensionType: 'hyBase',
dataDimensionVal: 'all',
maptype: '2'
}
}
}
]
},
{
name: '实时视频',
key: 'videoInfo',
type: 'video',
url: '/video/dataStcdFrame/getVideoMonitorList'
}
// {
// name: '实时视频',
// key: 'videoInfo',
// type: 'video',
// url: '/video/dataStcdFrame/getVideoMonitorList'
// name: "全景影像",
// key: "panoramaInfo",
// type: "panorama"
// }
// // {
// // name: "全景影像",
// // key: "panoramaInfo",
// // type: "panorama"
// // }
// ]
]
// const ZQTabs: Array<any> = [
// {
// name: '基础信息',
@ -652,19 +652,20 @@ const ENGTabs: Array<any> = [
// ]
// //水质监测站 √
// const WQFBTabs: Array<any> = [
// {
// name: '基础信息',
// key: 'basicInfo',
// type: 'basic',
// url: '/bbi/siteBipc/getSiteBasicInfo'
// },
// {
// name: '监测数据',
// key: 'WaterQuality',
// type: 'WaterQuality'
// }
// ]
const WQFBTabs: Array<any> = [
{
name: '基础信息',
key: 'basicInfo',
type: 'basic',
url: '/bbi/siteBipc/getSiteBasicInfo'
},
{
name: '监测数据',
key: 'WaterQuality',
type: 'WaterQuality',
default: true // 默认显示
}
]
// const WQTabs: Array<any> = [
// ...WQFBTabs,
// {
@ -698,46 +699,47 @@ const ENGTabs: Array<any> = [
// }
// ]
// //栖息地流量监测
// const FLOWTabs: Array<any> = [
// {
// name: '基础信息',
// key: 'basicInfo',
// type: 'basic',
// url: '/bbi/siteBipc/getSiteBasicInfo'
// },
// {
// name: '监测数据',
// key: 'FlowMeasure',
// type: 'FlowMeasure'
// }
// ]
//栖息地流量监测
const FLOWTabs: Array<any> = [
{
name: '基础信息',
key: 'basicInfo',
type: 'basic',
url: '/bbi/siteBipc/getSiteBasicInfo'
},
{
name: '监测数据',
key: 'FlowMeasure',
type: 'FlowMeasure'
}
]
// //水温监测站 √
// const WTTabs: Array<any> = [
const WTTabs: Array<any> = [
{
name: '基础信息',
key: 'basicInfo',
type: 'basic',
url: '/bbi/siteBipc/getSiteBasicInfo'
},
{
name: '监测数据',
key: 'WaterTemperature',
type: 'WaterTemperature',
default: true // 默认显示
},
// {
// name: '基础信息',
// key: 'basicInfo',
// type: 'basic',
// url: '/bbi/siteBipc/getSiteBasicInfo'
// name: '出入库水温对比',
// key: 'WaterTemperatureContrast',
// type: 'WaterTemperatureContrast',
// code: 'swjc.tabs.crkswdb',
// },
// {
// name: '监测数据',
// key: 'WaterTemperature',
// type: 'WaterTemperature'
// },
// // {
// // name: '出入库水温对比',
// // key: 'WaterTemperatureContrast',
// // type: 'WaterTemperatureContrast',
// // code: 'swjc.tabs.crkswdb',
// // },
// {
// name: '鱼类繁殖适宜性分析',
// key: 'WaterTemperatureRep',
// type: 'WaterTemperatureRep',
// code: 'swjc.tabs.ylfzsyxfx',
// }
// ]
{
name: '鱼类繁殖适宜性分析',
key: 'WaterTemperatureRep',
type: 'WaterTemperatureRep',
code: 'swjc.tabs.ylfzsyxfx',
}
]
// //垂向水温 √
// const WTTabs1: Array<any> = [
// {
@ -1147,9 +1149,19 @@ const handleTabs = (modaldata: any) => {
console.log('modaldata', modaldata);
if (!modaldata?.sttp) return;
let sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : '';
console.log('sttp', sttp);
switch (sttp) {
case 'ENG':
return ENGTabs;
case 'WT_POINT':
return WTTabs;
case 'FH_WQ_POINT':
return WQFBTabs;
case 'FH_POINT':
return FHTabs;
case 'FH_ZQ_POINT':
return FLOWTabs
//
// if (modaldata?.eqtp == 'QEC') {
// const { page } = Utility.parseQueryString()
// if (page == 'shengTaiLiuLiangManZuQingKuangJiangJu') {

View File

@ -0,0 +1,286 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="植物园情况介绍">
<div class="container" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<!-- 跑马灯轨道容器 -->
<div class="carousel-track" :class="{ 'no-transition': isTransitioning }"
:style="{ transform: `translateX(-${currentIndex * 100}%)` }">
<!-- 遍历所有媒体项包含克隆项 -->
<div v-for="(item, index) in renderMediaData" :key="index" class="carousel-item">
<!-- 图片 -->
<img :src="item.url" alt="" />
<!-- 说明文字随媒体项移动 -->
<div class="text">{{ item.text }}</div>
</div>
</div>
<!-- 面板指示器固定在底部右侧 -->
<div class="pagination-dots-fixed">
<span
v-for="(dot, index) in originalMediaData"
:key="index"
class="dot"
:class="{ active: getCurrentRealIndex() === index }"
@click="goToSlide(index)"
></span>
</div>
</div>
<!-- 独立的文字说明区域随跑马灯切换而变化 -->
<div class="description-text">
{{ currentDescription }}
</div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// 便
defineOptions({
name: 'zengZhiZhanJieShaoMod'
});
//
interface MediaItem {
type: 'image' | 'video';
url: string;
text: string;
description: string;
}
// 3
const originalMediaData = ref<MediaItem[]>([
{
type: 'image',
url: 'https://211.99.26.225:12125/?20230814205611342377136845462200&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920',
text: '松岗鱼类增殖站',
description: '松岗鱼类增殖放流站位于四川省阿坝藏族羌族自治州马尔康市松岗镇,主要服务于大渡河上游的双江口和金川两座水电站,同时还承担多种珍稀特有鱼类的救护和科研任务,实现工程建设与生态环境共同推进、相互促进。'
},
{
type: 'video',
url: 'https://211.99.26.225:12125/?20230805205848575430105387253710&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920', // URL
text: '猴子岩鱼类增殖站',
description: '猴子岩水电站鱼类增殖放流站位于猴子岩水电站坝址下游约7.0km(业主营地下游约1.5km)大渡河左岸桃花渣场顶部平台上紧邻枢纽桃花大桥下游侧占地面积47.3亩其中一期工程27.0亩预留二期工程用地20.3亩(二期工程目前为丹巴、巴底水电站预留工程)增殖放流站工作流程为:亲鱼收集购买、亲鱼驯养培育、人工催产和授精、人工孵化、苗种培育和放流。 猴子岩鱼类增殖放流站近期放流对象中齐口裂腹鱼、重口裂腹鱼、大渡软刺裸裂尻鱼增殖放流技术水平已趋于熟化,中期放流对象大渡软刺裸裂尻鱼人工繁殖技术逐渐趋于熟化'
},
{
type: 'image',
url: 'https://211.99.26.225:12125/?20230805205924378504010675106305&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920',
text: '黑马鱼类增殖站',
description: '大渡河黑马鱼类增殖放流站位于四川省甘洛县黑马乡黑马业主营地内距离甘洛县城45km,区域交通路况较好。主要承担瀑布沟、深溪沟、大岗山、枕头坝一级、沙坪二级等五座水电站鱼类增殖放流的重任。放流鱼类包含:齐口裂腹鱼、重口裂腹鱼、鲈鲤、长薄鳅、白甲鱼、中华倒刺、长吻脆、稀有鮊鲫、华鲮、侧沟爬岩鳅等10个种类共计约918.07万尾珍稀特有鱼苗。'
}
]);
//
// [, ..., ]
const renderMediaData = ref<MediaItem[]>([]);
// renderMediaData
const currentIndex = ref(1); // 1
//
let timer: any = null;
//
const isHovering = ref(false);
// transition
const isTransitioning = ref(false);
//
const initRenderData = () => {
const length = originalMediaData.value.length;
if (length === 0) return;
renderMediaData.value = [
originalMediaData.value[length - 1], //
...originalMediaData.value, //
originalMediaData.value[0] //
];
};
//
const startAutoPlay = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
if (!isHovering.value && !isTransitioning.value) {
nextSlide();
}
}, 4000);
};
//
const nextSlide = () => {
currentIndex.value++;
//
setTimeout(() => {
checkSeamlessJump();
}, 500); // transition
};
//
const checkSeamlessJump = () => {
const realLength = originalMediaData.value.length;
// = realLength + 1
if (currentIndex.value >= realLength + 1) {
// 1.
isTransitioning.value = true;
// 2. 1
currentIndex.value = 1;
// 3. DOM
requestAnimationFrame(() => {
requestAnimationFrame(() => {
isTransitioning.value = false;
});
});
}
};
//
const handleMouseEnter = () => {
isHovering.value = true;
};
//
const handleMouseLeave = () => {
isHovering.value = false;
};
//
const currentDescription = computed(() => {
const realIndex = getCurrentRealIndex();
return originalMediaData.value[realIndex]?.description || '';
});
//
onMounted(() => {
initRenderData();
startAutoPlay();
});
//
onUnmounted(() => {
if (timer) clearInterval(timer);
});
//
const getCurrentRealIndex = () => {
const realLength = originalMediaData.value.length;
let realIndex = currentIndex.value - 1; //
//
if (realIndex < 0) realIndex = realLength - 1;
if (realIndex >= realLength) realIndex = 0;
return realIndex;
};
//
const goToSlide = (targetIndex: number) => {
if (isTransitioning.value) return;
//
currentIndex.value = targetIndex + 1;
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 228px;
// border: 1px solid #7fd6ff;
// border-radius: 5px;
position: relative;
overflow: hidden; //
//
.carousel-track {
display: flex; //
width: 100%;
height: 100%;
transition: transform 0.5s ease-in-out; // 0.5
//
&.no-transition {
transition: none;
}
//
.carousel-item {
min-width: 100%; //
height: 100%;
position: relative;
flex-shrink: 0; //
img,
video {
width: 100%;
height: 100%;
object-fit: cover; //
}
.text {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 22px;
line-height: 22px;
background: rgba(0, 0, 0, 0.1);
color: #fff;
padding-left: 10px;
}
}
}
//
.pagination-dots-fixed {
position: absolute;
bottom: 10px;
right: 10px;
display: flex;
gap: 6px;
z-index: 10; //
.dot {
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #D8D8D8;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: #005293;
}
&:hover {
opacity: 0.8;
}
}
}
}
//
.description-text {
// padding: 8px 12px;
font-size: 14px;
line-height: 1.5;
// min-height: 40px;
transition: all 0.3s ease;
margin-bottom: 20px;
//
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
}
</style>

View File

@ -0,0 +1,203 @@
<!-- SidePanelItem.vue -->
<template>
<div>
<SidePanelItem title="生态流量限值沿程变化" :select="select" :datetimePicker="datetimePicker" >
<!-- 图表容器 -->
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed, watch, onBeforeUnmount } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
//
defineOptions({
name: 'xieFangFenBu'
});
const select = ref({
show: true,
value: undefined,
options: [
]
});
const datetimePicker = ref({
show: true,
value: undefined,
format: 'YYYY-MM', //YYYY-MM-DD HH
picker: 'month' //date | week | month | quarter | year
});
//
const chartData = ref([
{ stnm: '站点A001', qecLimit: 120.5 },
{ stnm: '站点B002', qecLimit: 135.8 },
{ stnm: '站点C003', qecLimit: 98.3 },
{ stnm: '站点D004', qecLimit: 142.6 },
{ stnm: '站点E005', qecLimit: 115.2 },
{ stnm: '站点F006', qecLimit: 128.9 },
{ stnm: '站点G007', qecLimit: 105.4 },
{ stnm: '站点H008', qecLimit: 138.7 },
{ stnm: '站点I009', qecLimit: 122.1 },
{ stnm: '站点J010', qecLimit: 145.3 },
{ stnm: '站点K011', qecLimit: 110.6 },
{ stnm: '站点L012', qecLimit: 132.4 },
{ stnm: '站点M013', qecLimit: 118.9 },
{ stnm: '站点N014', qecLimit: 140.2 },
{ stnm: '站点O015', qecLimit: 125.7 }
]);
//
const flowUnit = ref('m³/s');
//
const generateModerateColor = () => {
const hue = Math.floor(Math.random() * 360);
const saturation = 50 + Math.floor(Math.random() * 30); // 50-80%
const lightness = 45 + Math.floor(Math.random() * 20); // 45-65%
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};
//
const chartOption = computed<EChartsOption>(() => {
const dataLength = chartData.value.length;
return {
legend: {
data: ['生态流量限值'],
center: true,
icon: 'rect',
itemHeight: 3
},
grid: {
top: 40,
left: 40,
right: 20,
bottom: 60
},
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
if (!params || params.length === 0) return '';
const value = params[0].value ?? '-';
return `<h3 style="color:#FFF">${params[0].name}</h3>
<div>${params[0].marker}生态流量限值: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} ${flowUnit.value}</span></div>`;
},
axisPointer: {
type: 'line'
}
},
xAxis: {
type: 'category',
data: chartData.value.map((item: any) => item.stnm),
axisLabel: {
interval: dataLength > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const displayText = value.substring(0, 6) + (value.length > 6 ? '...' : '');
if (dataLength === 2) {
return `{a|${displayText}}`;
} else if (index % 2 !== 0) {
//
return `{a|${displayText}}`;
} else {
//
return '\n{b|}' + `{b|${displayText}}`;
}
},
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
},
axisTick: {
show: false
}
},
yAxis: [{
type: 'value',
name: `流量(${flowUnit.value})`
}],
dataZoom: [
{
type: 'inside',
show: false
},
{
type: 'slider',
show: false
}
],
series: [
{
name: '生态流量限值',
type: 'line',
data: chartData.value.map((item: any) => item.qecLimit),
smooth: false,
showSymbol: true,
symbolSize: 6
}
],
color: [generateModerateColor()]
};
});
//
let chartInstance: echarts.ECharts | null = null;
const chartRef = ref<HTMLDivElement>();
//
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未找到');
return;
}
console.log('开始初始化图表...');
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(chartOption.value);
console.log('图表初始化完成');
//
window.addEventListener('resize', handleResize);
};
//
const handleResize = () => {
chartInstance?.resize();
};
//
watch(chartOption, (newOption) => {
if (chartInstance) {
chartInstance.setOption(newOption, true);
}
});
onMounted(() => {
initChart();
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,479 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水质变化" :datetimePicker="datetimePicker">
<div class="chart-container" ref="chartRef"></div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// 便
defineOptions({
name: 'waterQuality'
});
// ==================== ====================
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
// 8:00
const now = new Date();
const todayAtEightAM = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0);
const defaultValue = `${todayAtEightAM.getFullYear()}-${String(todayAtEightAM.getMonth() + 1).padStart(2, '0')}-${String(todayAtEightAM.getDate()).padStart(2, '0')} ${String(todayAtEightAM.getHours()).padStart(2, '0')}:${String(todayAtEightAM.getMinutes()).padStart(2, '0')}`;
const datetimePicker = ref({
show: true,
value: defaultValue,
format: 'YYYY-MM-DD hh:mm',
picker: 'date',
options: []
});
// ==================== 2====================
const visibleSeriesQueue = ref<string[]>([]);
// ==================== ====================
const generateMockData = () => {
const stations = [
{ stnm: '两河口', stcd: 'ST001', type: '0' },
{ stnm: '锦屏一级', stcd: 'ST002', type: '1' },
{ stnm: '桐子林', stcd: 'ST003', type: '0' },
{ stnm: '溪洛渡', stcd: 'ST004', type: '0' },
{ stnm: '向家坝', stcd: 'ST005', type: '1' },
{ stnm: '三峡', stcd: 'ST006', type: '0' },
{ stnm: '葛洲坝', stcd: 'ST007', type: '0' }
];
const tm = '2024-01-15 08:00:00';
return stations.map((station, index) => ({
...station,
tm,
SORT: index + 1,
ph: 7.2 + Math.random() * 0.8,
dox: 6.5 + Math.random() * 2.5,
codmn: 1.5 + Math.random() * 2.0,
nh3n: 0.15 + Math.random() * 0.35,
tp: 0.05 + Math.random() * 0.15,
tn: 0.8 + Math.random() * 1.2
}));
};
const mockData = ref(generateMockData());
// ==================== ====================
const indicatorConfig = [
{ key: 'ph', name: 'pH', unit: '', color: '#5470C6' },
{ key: 'dox', name: '溶解氧', unit: 'mg/L', color: '#91CC75' },
{ key: 'codmn', name: '高锰酸盐指数', unit: 'mg/L', color: '#FAC858' },
{ key: 'nh3n', name: '氨氮', unit: 'mg/L', color: '#EE6666' },
{ key: 'tp', name: '总磷', unit: 'mg/L', color: '#73C0DE' },
{ key: 'tn', name: '总氮', unit: 'mg/L', color: '#3BA272' }
];
// ==================== ====================
const getChartOption = (): EChartsOption => {
const data = mockData.value;
if (!data || data.length === 0) {
return {};
}
// X
const xData = data.map((item, index) => ({
value: item.stnm,
textStyle: {
padding: index % 2 !== 0 ? [16, 0, 0, 0] : 0
}
}));
// 线
const markLineData: any[] = [];
data.forEach((item, index) => {
if (item.type === '1') {
markLineData.push({ xAxis: index });
}
});
//
const legendData = indicatorConfig.map(item => item.name);
//
const selectedState: Record<string, boolean> = {};
indicatorConfig.forEach(config => {
selectedState[config.name] = visibleSeriesQueue.value.includes(config.name);
});
// Series
const seriesData = indicatorConfig.map((config, index) => {
const _key = config.key === 'dox' ? 'do' : config.key;
return {
name: config.name,
type: 'line' as const,
yAxisIndex: index,
smooth: true,
connectNulls: true,
symbol: 'circle' as const,
symbolSize: 6,
itemStyle: {
color: config.color
},
data: data.map(item => {
const value = item[config.key as keyof typeof item];
return typeof value === 'number' && !isNaN(value) ? value : null;
}),
markLine: index === 0 ? {
symbol: ['none', 'none'],
label: { show: false },
lineStyle: {
color: '#ccc',
type: 'dashed' as const
},
data: markLineData
} : undefined
};
});
// Y1N
const yAxisData = indicatorConfig.map((config, index) => {
const isLeft = index === 0;
const offset = index < 2 ? 0 : (index - 1) * 60;
return {
type: 'value' as const,
name: config.name,
position: isLeft ? ('left' as const) : ('right' as const),
offset,
axisLine: {
show: true,
lineStyle: {
color: config.color
}
},
axisLabel: {
color: config.color,
formatter: (value: number) => {
const decimalCount = (value.toString().split('.')[1] || '').length;
return decimalCount >= 2 ? value.toFixed(1) : value;
}
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid' as const
}
},
show: selectedState[config.name]
};
});
const option: EChartsOption = {
tooltip: {
trigger: 'axis',
confine: true,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderColor: 'transparent',
textStyle: {
color: '#ffffff'
},
formatter: (params: any) => {
if (!params || params.length === 0) return '';
const tm = data.find(item => item.stnm === params[0].name)?.tm;
let result = tm ? `${new Date(tm).toLocaleString('zh-CN')}<br/>` : '';
result += `${params[0].name}<br/>`;
params.forEach((param: any) => {
const config = indicatorConfig.find(c => c.name === param.seriesName);
const unit = config?.unit || '';
if (param.value !== null && param.value !== undefined) {
//
const numValue = Number(param.value);
let displayValue = param.value;
// 2
if (!isNaN(numValue)) {
const decimalPart = param.value.toString().split('.')[1];
if (decimalPart && decimalPart.length > 2) {
displayValue = numValue.toFixed(2);
}
}
result += `${param.marker}${param.seriesName}${displayValue}${unit}<br/>`;
}
});
return result;
}
},
legend: {
type: 'scroll',
top: 0,
data: legendData,
selected: selectedState,
inactiveColor: '#ccc',
itemWidth: 16,
itemHeight: 12,
itemGap: 8,
textStyle: {
fontSize: 14
}
},
grid: {
top: 60,
bottom: 50,
left: '20px',
right: '20px',
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLabel: {
interval: 0,
color: '#333',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#8f8f8f'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid' as const
}
}
},
yAxis: yAxisData,
series: seriesData
};
return option;
};
// ==================== 2====================
const handleLegendSelectChanged = (params: any) => {
if (!chartInstance) return;
const { selected, name } = params;
const clickedName = name;
const isNowSelected = selected[clickedName];
console.log(`图例点击: ${clickedName}, 当前状态: ${isNowSelected ? '显示' : '隐藏'}`);
console.log('当前可见队列:', visibleSeriesQueue.value);
if (isNowSelected) {
//
if (visibleSeriesQueue.value.length >= 2) {
// 2
const removed = visibleSeriesQueue.value.shift();
console.log(`已达上限,移除最早系列: ${removed}`);
}
//
if (!visibleSeriesQueue.value.includes(clickedName)) {
visibleSeriesQueue.value.push(clickedName);
}
} else {
//
const index = visibleSeriesQueue.value.indexOf(clickedName);
if (index > -1) {
visibleSeriesQueue.value.splice(index, 1);
console.log(`从队列中移除: ${clickedName}`);
}
}
console.log('更新后可见队列:', visibleSeriesQueue.value);
// selected
const finalSelected: Record<string, boolean> = {};
indicatorConfig.forEach(config => {
finalSelected[config.name] = visibleSeriesQueue.value.includes(config.name);
});
//
const currentOption = JSON.parse(JSON.stringify(chartInstance.getOption()));
//
currentOption.legend[0].selected = finalSelected;
// Y
const newYAxis = currentOption.yAxis.map((item: any) => {
let isShow = false;
for (const key in finalSelected) {
if (key === item.name) {
isShow = finalSelected[key];
break;
}
}
return { ...item, show: isShow };
});
currentOption.yAxis = newYAxis;
// Y
yAxisShowDynamic(finalSelected, currentOption);
//
try {
chartInstance.setOption(currentOption, true);
console.log('图表配置已更新');
} catch (error) {
console.error('图表更新失败:', error);
}
};
// ==================== Y ====================
const yAxisShowDynamic = (selected: Record<string, boolean>, options: any) => {
const allShow = options.yAxis?.filter((item: any) => item.show);
const showCount = allShow?.length || 0;
// Y
if (showCount === 0) {
return;
}
// Y
if (showCount === 1) {
delete options.grid.right;
options.grid.left = '80px';
options.yAxis = options.yAxis.map((item: any) => {
if (item.show) {
return {
...item,
position: 'left',
offset: 0
};
}
return item;
});
return;
}
// Y1
if (showCount >= 2) {
let leftIndex = 0;
let rightIndex = 0;
options.yAxis = options.yAxis.map((item: any) => {
if (!item.show) {
return item;
}
// Y
if (leftIndex === 0) {
leftIndex++;
delete options.grid.right;
options.grid.left = '80px';
return {
...item,
position: 'left',
offset: 0
};
} else {
// Y
rightIndex++;
if (rightIndex > 1) {
options.grid.right = '100px';
return {
...item,
position: 'right',
offset: 60
};
} else {
options.grid.right = '60px';
return {
...item,
position: 'right',
offset: 0
};
}
}
});
}
};
// ==================== ====================
const initChart = async () => {
if (!chartRef.value) {
console.warn('图表容器未就绪');
return;
}
//
const rect = chartRef.value.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) {
console.warn('图表容器尺寸为0等待渲染...');
await new Promise(resolve => setTimeout(resolve, 50));
return initChart();
}
//
visibleSeriesQueue.value = [indicatorConfig[0].name];
console.log('初始化可见队列:', visibleSeriesQueue.value);
// ECharts
chartInstance = echarts.init(chartRef.value);
//
const option = getChartOption();
chartInstance.setOption(option);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
// resize
setTimeout(() => {
chartInstance?.resize();
}, 50);
console.log('图表初始化成功');
};
// ==================== ====================
const handleResize = () => {
chartInstance?.resize();
};
// ==================== ====================
onMounted(async () => {
await nextTick();
//
setTimeout(() => {
initChart();
}, 50);
window.addEventListener('resize', handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
if (chartInstance) {
chartInstance.off('legendselectchanged', handleLegendSelectChanged);
chartInstance.dispose();
chartInstance = null;
}
});
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 280px;
min-height: 231px;
}
</style>

View File

@ -55,8 +55,6 @@ router.beforeEach(async (to, from, next) => {
if (userStore.Token) {
// 登录成功,跳转到首页
if (to.path === '/login') {
//login
if (to.path === '/login') {
//login
next({ path: '/' });
@ -88,6 +86,8 @@ router.beforeEach(async (to, from, next) => {
// ✅ 关键修复:在添加路由前,标准化所有路径
accessRoutes = normalizeRoutes(accessRoutes);
console.log('Normalized Access Routes:', accessRoutes);
accessRoutes.forEach((route: any) => {
console.log('Adding Route:', route.path);
router.addRoute(route);

View File

@ -29,19 +29,31 @@ const showMapModal = () => {
modelStore.modalVisible = true;
modelStore.params.sttp = "ENG";
modelStore.title = "三峡 详情信息";
modelStore.currentTabKey = "basicInfo";
modelStore.isBasicEdit = true;
};
const showMapModal1 = () => {
modelStore.modalVisible = true;
modelStore.params.sttp = "zh";
modelStore.title = "三峡222 详情信息";
modelStore.currentTabKey = "basicInfo";
modelStore.isBasicEdit = false;
// modelStore.modalVisible = true;
// modelStore.params.sttp = "zh";
// modelStore.title = '222 ';
// modelStore.currentTabKey = "mapView";
modelStore.params.sttp = "wt_point";
modelStore.title = "水温 详情信息";
modelStore.isBasicEdit = true;
};
const showMapModal2 = () => {
modelStore.modalVisible = true;
modelStore.params.sttp = "fh_wq_point";
modelStore.title = "水质 详情信息";
modelStore.isBasicEdit = true;
};
const showMapModal3 = () => {
modelStore.modalVisible = true;
modelStore.params.sttp = "fh_point";
modelStore.title = "栖息地 详情信息";
modelStore.isBasicEdit = true;
};//
const showMapModal4 = () => {
modelStore.modalVisible = true;
modelStore.params.sttp = "fh_zq_point";
modelStore.title = "栖息地流量 详情信息";
modelStore.isBasicEdit = true;
};
</script>
@ -52,9 +64,11 @@ const showMapModal1 = () => {
</div>
<div class="rightContent">
<RightDrawer>
<!-- <a-button @click="showMapModal">打开电站地图弹窗</a-button>
<a-button @click="showMapModal1">打开地图弹窗1</a-button> -->
<a-button @click="showMapModal">打开电站弹窗</a-button>
<a-button @click="showMapModal1">打开水温弹窗</a-button>
<!-- <a-button @click="showMapModal2">打开水质弹窗</a-button> -->
<!-- <a-button @click="showMapModal3">打开栖息地弹窗</a-button> -->
<a-button @click="showMapModal4">打开栖息地流量弹窗</a-button>
<jidiInfoMod />
<shuidianhuangjingjieruMod />
</RightDrawer>