模块增加-水温监测和水质监测-水质监测工作开展情况
This commit is contained in:
parent
0a0433c3b8
commit
35be267360
@ -2,8 +2,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<SidePanelItem title="典型设施介绍">
|
<SidePanelItem title="典型设施介绍">
|
||||||
<div v-if="carouselData.length > 0" class="carousel-wrapper">
|
<div v-if="carouselData.length > 0" class="carousel-wrapper">
|
||||||
<a-carousel v-model:current="currentIndex" class="tech-carousel" :dot-style="{ bottom: '0px' }">
|
<a-carousel v-model:current="currentIndex" autoplay class="tech-carousel" :dot-style="{ bottom: '0px' }">
|
||||||
<!-- autoplay -->
|
<!-- -->
|
||||||
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item">
|
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item">
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<img :src="item.image" :alt="item.title" class="carousel-image" />
|
<img :src="item.image" :alt="item.title" class="carousel-image" />
|
||||||
@ -66,7 +66,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.carousel-wrapper {
|
.carousel-wrapper {
|
||||||
|
width: 414px;
|
||||||
:deep(.slick-slide) {
|
:deep(.slick-slide) {
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
line-height: 160px;
|
line-height: 160px;
|
||||||
|
|||||||
@ -0,0 +1,163 @@
|
|||||||
|
<!-- SidePanelItem.vue -->
|
||||||
|
<template>
|
||||||
|
<SidePanelItem title="设施类型及接入情况">
|
||||||
|
<div class="card-container">
|
||||||
|
<div v-for="(item, index) in dataJson" class="facility-card">
|
||||||
|
<div class="img_icon">
|
||||||
|
<i class="icon iconfont" :class="item?.icon" />
|
||||||
|
</div>
|
||||||
|
<div class="img_text">
|
||||||
|
<div>{{ item.nameString }}</div>
|
||||||
|
<div class="text_num">{{ item.total + item.zj }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <a-card v-for="(item, index) in dataJson" :key="index" class="facility-card" type="inner" size="small"
|
||||||
|
@click="handleCardClick(item)">
|
||||||
|
<template #title>
|
||||||
|
<i class="icon iconfont" :class="item?.icon" style="
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 40px;
|
||||||
|
background-color: #5389B5;
|
||||||
|
line-height: 40px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
" />
|
||||||
|
</template>
|
||||||
|
<a-tooltip>
|
||||||
|
<div style="font-size: 14px; color: #333">{{ item.nameString }}</div>
|
||||||
|
<div style="padding: 4px 0" class="showNum">
|
||||||
|
<span>{{ item.total + item.zj }}</span>
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-card> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div v-else>
|
||||||
|
<a-empty />
|
||||||
|
</div> -->
|
||||||
|
</SidePanelItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
|
||||||
|
// 定义组件名(便于调试和递归)
|
||||||
|
defineOptions({
|
||||||
|
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 数据类型定义
|
||||||
|
interface DataString {
|
||||||
|
icon?: string;
|
||||||
|
nameString: string;
|
||||||
|
num?: number;
|
||||||
|
total: number;
|
||||||
|
zj: number;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const dataJson = ref<DataString[]>([
|
||||||
|
{
|
||||||
|
icon: 'icon-dwsjhDieliangmen',
|
||||||
|
nameString: '叠梁门',
|
||||||
|
num: 18,
|
||||||
|
total: 18,
|
||||||
|
zj: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'icon-dwsjhQianzhidangqiang',
|
||||||
|
nameString: '前置挡墙',
|
||||||
|
num: 4,
|
||||||
|
total: 4,
|
||||||
|
zj: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'icon-dwsjhGeshuimuqiang',
|
||||||
|
nameString: '隔水幕墙',
|
||||||
|
num: 1,
|
||||||
|
total: 1,
|
||||||
|
zj: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'icon-dwsjhQita',
|
||||||
|
nameString: '其他',
|
||||||
|
num: 1,
|
||||||
|
total: 1,
|
||||||
|
zj: 0
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const clickList = ref<DataString | null>(null);
|
||||||
|
const res = ref({
|
||||||
|
bldstt: '',
|
||||||
|
hydrodtin: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 卡片点击事件处理
|
||||||
|
const handleCardClick = (item: DataString) => {
|
||||||
|
clickList.value = item;
|
||||||
|
// dialog.current?.open() - 需要根据实际的对话框实现调整
|
||||||
|
res.value = {
|
||||||
|
bldstt: '',
|
||||||
|
hydrodtin: ''
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面加载时执行的逻辑
|
||||||
|
onMounted(() => {
|
||||||
|
// 可以在这里加载实际的图片数据
|
||||||
|
// loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card-container {
|
||||||
|
width: 406px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.facility-card {
|
||||||
|
width: 95.5px;
|
||||||
|
height: 158px;
|
||||||
|
border: 1px solid rgb(229, 236, 245);
|
||||||
|
border-radius: 2px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.img_icon {
|
||||||
|
margin-top: 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 40px;
|
||||||
|
background-color: rgb(83, 137, 181);
|
||||||
|
line-height: 40px;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img_text {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
.text_num{
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 3px;
|
||||||
|
text-align: center;
|
||||||
|
// font-size: 16px;
|
||||||
|
color: #2f6b98;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
237
frontend/src/modules/monthlyAvgWaterTemCompareHistory/index.vue
Normal file
237
frontend/src/modules/monthlyAvgWaterTemCompareHistory/index.vue
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
<!-- NEW_FILE_CODE -->
|
||||||
|
<template>
|
||||||
|
<SidePanelItem title="月平均水温历史对比">
|
||||||
|
<div>
|
||||||
|
<div class="water-temp-compare-chart" ref="chartRef"></div>
|
||||||
|
</div>
|
||||||
|
<!-- <div v-else>
|
||||||
|
<a-empty />
|
||||||
|
</div> -->
|
||||||
|
</SidePanelItem>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
defineOptions({
|
||||||
|
name: 'monthlyAvgWaterTemCompareHistory'
|
||||||
|
});
|
||||||
|
const chartRef = ref<HTMLElement | null>(null)
|
||||||
|
let chartInstance: echarts.ECharts | null = null
|
||||||
|
|
||||||
|
const unit = '°C'
|
||||||
|
|
||||||
|
const initChart = () => {
|
||||||
|
if (!chartRef.value) return
|
||||||
|
|
||||||
|
chartInstance = echarts.init(chartRef.value)
|
||||||
|
|
||||||
|
const legendData = ['实测值', '去年同期', '天然']
|
||||||
|
|
||||||
|
// x轴数据 - 保持与原始配置一致的结构 { value, stnm }
|
||||||
|
const xData = [
|
||||||
|
{ value: '两河口', stnm: '两河口' },
|
||||||
|
{ value: '锦屏一级', stnm: '锦屏一级' },
|
||||||
|
{ value: '桐子林', stnm: '桐子林' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// 根据图片数据提取的静态数据
|
||||||
|
const actualData = [9, 11.5, 14] // 实测值(蓝色线)
|
||||||
|
const lastData = [8.8, 10.5, 13.2] // 去年同期(紫色线)
|
||||||
|
const naturalData = [9.2, 12, 15.5] // 天然(绿色线)
|
||||||
|
|
||||||
|
// 计算Y轴范围:最小值向下取整,最大值向上取整
|
||||||
|
const allData = [...actualData, ...lastData, ...naturalData].filter(val => val !== null && val !== undefined)
|
||||||
|
const dataMin = Math.min(...allData)
|
||||||
|
const dataMax = Math.max(...allData)
|
||||||
|
const yAxisMin = Math.floor(dataMin)
|
||||||
|
const yAxisMax = Math.ceil(dataMax)
|
||||||
|
|
||||||
|
// 完全按照原始React代码中的options配置
|
||||||
|
const options: any = {
|
||||||
|
noShowToolbox: true,
|
||||||
|
yAxisSplit: 5,
|
||||||
|
xData,
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
type: 'inside',
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'slider',
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'axis',
|
||||||
|
confine: true,
|
||||||
|
formatter: (params: any) => {
|
||||||
|
const label = xData.filter((item: any) => item.value === params[0].axisValueLabel)?.[0]?.stnm
|
||||||
|
let elm = ``
|
||||||
|
for (const item of params) {
|
||||||
|
elm += `
|
||||||
|
<div>
|
||||||
|
${item.marker}
|
||||||
|
<span>${item.seriesName}:</span>
|
||||||
|
<span>${item.value === null || item.value === undefined ? '-' : item.value}${unit}</span>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
return `<div>${label}</div>` + elm
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: legendData
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 30,
|
||||||
|
bottom: 50,
|
||||||
|
right: 15,
|
||||||
|
left: 30
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow',
|
||||||
|
lineStyle: {
|
||||||
|
color: '#007aff1a',
|
||||||
|
width: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#8f8f8f'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#000000',
|
||||||
|
fontSize: 12,
|
||||||
|
interval: xData.length < 5 ? 0 : 2,
|
||||||
|
rotate: 0,
|
||||||
|
formatter: (value: any) => {
|
||||||
|
const label = xData.filter((item: any) => item.value === value)?.[0]?.stnm
|
||||||
|
return `{a|${label.substring(0, 6)}}` + (label.length > 6 ? '...\n{b|}' : '\n{b|}')
|
||||||
|
},
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
height: 30,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
b: {
|
||||||
|
height: 30,
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: xData,
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: `水温(${unit})`,
|
||||||
|
min: yAxisMin,
|
||||||
|
max: yAxisMax,
|
||||||
|
nameTextStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#000000'
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: '#6ca4f7',
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: true,
|
||||||
|
length: 3,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#8f8f8f'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#333',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: legendData[0],
|
||||||
|
data: actualData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: legendData[1],
|
||||||
|
data: lastData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: legendData[2],
|
||||||
|
data: naturalData,
|
||||||
|
type: 'line',
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 颜色配置 - 对应 getColorByCodeAndType(['Other'], ['ACTUALTEMP', 'LASTTEMP', 'NATURALTEMP'])
|
||||||
|
// 根据图片:实测值(蓝)、去年同期(紫)、天然(绿)
|
||||||
|
options.color = ['#5470c6', '#9b59b6', '#91cc75']
|
||||||
|
|
||||||
|
chartInstance.setOption(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 延迟初始化,确保容器尺寸已就绪
|
||||||
|
setTimeout(() => {
|
||||||
|
initChart()
|
||||||
|
// 初始化完成后再次调用 resize 确保尺寸正确
|
||||||
|
chartInstance?.resize()
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
chartInstance?.dispose()
|
||||||
|
window.removeEventListener('resize', () => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.water-temp-compare-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
height: 260px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
130
frontend/src/modules/sheshileixingjieshao/index.vue
Normal file
130
frontend/src/modules/sheshileixingjieshao/index.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<!-- SidePanelItem.vue -->
|
||||||
|
<template>
|
||||||
|
<SidePanelItem title="设施类型介绍">
|
||||||
|
<div v-if="carouselData.length > 0" class="carousel-wrapper">
|
||||||
|
<a-carousel v-model:current="currentIndex" autoplay class="tech-carousel" :dot-style="{ bottom: '0px' }">
|
||||||
|
<!-- -->
|
||||||
|
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item">
|
||||||
|
<div class="image-container">
|
||||||
|
<img :src="item.image" :alt="item.title" class="carousel-image" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-carousel>
|
||||||
|
|
||||||
|
<!-- 文字描述区域 -->
|
||||||
|
<div v-if="carouselData[currentIndex]" class="description-container">
|
||||||
|
<p class="item-description">{{ carouselData[currentIndex].description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<a-empty />
|
||||||
|
</div>
|
||||||
|
</SidePanelItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
|
||||||
|
// 定义组件名(便于调试和递归)
|
||||||
|
defineOptions({
|
||||||
|
name: 'diwenshuijianhuansheshileixingzuchengjijieruqingkuang'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前轮播索引
|
||||||
|
const currentIndex = ref(0);
|
||||||
|
|
||||||
|
// 轮播图数据
|
||||||
|
const carouselData = ref([
|
||||||
|
{
|
||||||
|
title: '叠梁门',
|
||||||
|
description: '叠梁门是一种用于调节水库流量和控制水位的设施。在低温季节,可以通过控制叠梁门的开闭程度来调节流量,减少低温水体的进...',
|
||||||
|
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png' // 替换为实际图片路径
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '环保设施',
|
||||||
|
description: '现代化环保设施,采用先进技术,有效处理工业废水废气,实现达标排放,保护生态环境...',
|
||||||
|
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '智能监控',
|
||||||
|
description: '24 小时智能监控系统,实时监测设备运行状态,确保设施安全稳定运行...',
|
||||||
|
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '水处理系统',
|
||||||
|
description: '高效水处理系统,通过多级过滤和生物处理,实现水资源循环利用...',
|
||||||
|
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 页面加载时执行的逻辑
|
||||||
|
onMounted(() => {
|
||||||
|
// 可以在这里加载实际的图片数据
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.carousel-wrapper {
|
||||||
|
width: 414px;
|
||||||
|
:deep(.slick-slide) {
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
height: 250px;
|
||||||
|
line-height: 160px;
|
||||||
|
background: #364d79;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep() {
|
||||||
|
.ant-carousel .slick-dots li {
|
||||||
|
width: 5px !important;
|
||||||
|
height: 5px !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #888e95;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ant-carousel .slick-dots li button{
|
||||||
|
width: 5px !important;
|
||||||
|
height: 5px !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #888e95;
|
||||||
|
}
|
||||||
|
.ant-carousel .slick-dots li.slick-active{
|
||||||
|
background-color: #005293 !important;
|
||||||
|
}
|
||||||
|
.ant-carousel .slick-dots li.slick-active button{
|
||||||
|
background-color: #005293 !important;
|
||||||
|
}
|
||||||
|
.ant-carousel .slick-dots li :hover {
|
||||||
|
width: 5px !important;
|
||||||
|
height: 5px !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #ffffffcc;
|
||||||
|
|
||||||
|
}
|
||||||
|
.ant-carousel .slick-dots li button :hover{
|
||||||
|
width: 5px !important;
|
||||||
|
height: 5px !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background-color: #ffffffcc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-container {
|
||||||
|
height: 44px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 6px;
|
||||||
|
line-height: 22px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
text-indent: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
249
frontend/src/modules/shuiWenNianNeiFenBu/index.vue
Normal file
249
frontend/src/modules/shuiWenNianNeiFenBu/index.vue
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<template>
|
||||||
|
<SidePanelItem title="水温年内分布">
|
||||||
|
<div class="water-temp-chart-container">
|
||||||
|
<div ref="chartRef" class="chart-wrapper"></div>
|
||||||
|
</div>
|
||||||
|
<!-- <div v-else>
|
||||||
|
<a-empty />
|
||||||
|
</div> -->
|
||||||
|
</SidePanelItem>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
const data = [
|
||||||
|
{ monthInt: 1, actualTemp: 0.9, naturalTemp: 0 },
|
||||||
|
{ monthInt: 2, actualTemp: 0.9, naturalTemp: 0.1 },
|
||||||
|
{ monthInt: 3, actualTemp: 1.0, naturalTemp: 2.0 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const chartRef = ref<HTMLElement | null>(null)
|
||||||
|
let chartInstance: echarts.ECharts | null = null
|
||||||
|
|
||||||
|
const transUnit = (value: number | null, code: string, type: string) => {
|
||||||
|
if (value === null) return null
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUnitConfigByCode = (code: string, type: string) => {
|
||||||
|
return {
|
||||||
|
unit: '℃'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getColorByCodeAndType = (code: string[], typeKey: string[]) => {
|
||||||
|
return ['#4b79ab', '#78c300']
|
||||||
|
}
|
||||||
|
|
||||||
|
const getChartOption = () => {
|
||||||
|
const { unit } = getUnitConfigByCode('Other', 'ACTUALTEMP')
|
||||||
|
const legendData = ['实测值', '天然']
|
||||||
|
const xData: string[] = []
|
||||||
|
const actualData: (number | null)[] = []
|
||||||
|
const naturalData: (number | null)[] = []
|
||||||
|
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
xData.push(`${item.monthInt}月`)
|
||||||
|
actualData.push(item.actualTemp === null ? null : transUnit(item.actualTemp, 'Other', 'ACTUALTEMP'))
|
||||||
|
naturalData.push(item.naturalTemp === null ? null : transUnit(item.naturalTemp, 'Other', 'NATURALTEMP'))
|
||||||
|
})
|
||||||
|
|
||||||
|
const code = ['Other']
|
||||||
|
const typeKey = ['ACTUALTEMP', 'NATURALTEMP']
|
||||||
|
const colors = getColorByCodeAndType(code, typeKey)
|
||||||
|
|
||||||
|
const options: any = {
|
||||||
|
color: colors,
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(51, 51, 51, 0.9)',
|
||||||
|
borderColor: 'transparent',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
formatter: function(params) {
|
||||||
|
if (!params || params.length === 0) return '';
|
||||||
|
let result = `<div style="font-weight: bold; margin-bottom: 8px;">${params[0].axisValue}</div>`;
|
||||||
|
params.forEach(item => {
|
||||||
|
result += `<div style="display: flex; align-items: center; margin: 4px 0;">`;
|
||||||
|
result += `<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color}; margin-right: 8px;"></span>`;
|
||||||
|
result += `<span>${item.seriesName} ${item.value}${unit}</span>`;
|
||||||
|
result += `</div>`;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: true,
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow',
|
||||||
|
shadowStyle: {
|
||||||
|
color: '#007aff1a'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#8f8f8f'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0,
|
||||||
|
color: '#000000',
|
||||||
|
fontSize: 12,
|
||||||
|
rotate: 0,
|
||||||
|
margin: 8,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
data: xData
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
name: '水温(℃)',
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 5,
|
||||||
|
nameTextStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#000000'
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: '#6ca4f7',
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: true,
|
||||||
|
length: 3,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#000000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#333',
|
||||||
|
fontSize: 12
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#bfbfbf',
|
||||||
|
type: 'solid'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
legend: {
|
||||||
|
data: legendData
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 30,
|
||||||
|
bottom: 50,
|
||||||
|
right: 15,
|
||||||
|
left: 30
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: legendData[0],
|
||||||
|
data: actualData,
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true,
|
||||||
|
type: 'line',
|
||||||
|
itemStyle: {
|
||||||
|
color: colors[0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: legendData[1],
|
||||||
|
data: naturalData,
|
||||||
|
connectNulls: true,
|
||||||
|
smooth: true,
|
||||||
|
type: 'line',
|
||||||
|
itemStyle: {
|
||||||
|
color: colors[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
const initChart = async () => {
|
||||||
|
// 延迟初始化,确保容器已完成渲染
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100))
|
||||||
|
|
||||||
|
if (!chartRef.value) {
|
||||||
|
console.error('图表容器未找到')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!chartInstance) {
|
||||||
|
chartInstance = echarts.init(chartRef.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = getChartOption()
|
||||||
|
chartInstance.setOption(option, false)
|
||||||
|
|
||||||
|
// 强制重绘,确保图表尺寸正确
|
||||||
|
setTimeout(() => {
|
||||||
|
chartInstance?.resize()
|
||||||
|
}, 100)
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图表初始化失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleResize = () => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.resize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initChart()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose()
|
||||||
|
chartInstance = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.water-temp-chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 290px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 290px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
112
frontend/src/modules/shuizhijiancegongzuoQK/index.vue
Normal file
112
frontend/src/modules/shuizhijiancegongzuoQK/index.vue
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<!-- SidePanelItem.vue -->
|
||||||
|
<template>
|
||||||
|
<SidePanelItem title="环保设施情况">
|
||||||
|
<div class="facility-grid" >
|
||||||
|
<div v-for="facility in facilities" :key="facility.name" class="facility-card">
|
||||||
|
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;">
|
||||||
|
<div class="facility-icon">
|
||||||
|
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="facility-info">
|
||||||
|
<div class="facility-name">{{ facility.name }}</div>
|
||||||
|
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count }}</span><span>个</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SidePanelItem>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import SidePanelItem from '@/components/SidePanelItem/index.vue';
|
||||||
|
|
||||||
|
// 定义组件名(便于调试和递归)
|
||||||
|
defineOptions({
|
||||||
|
name: 'shuizhijiancegongzuoQK'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 设施数据
|
||||||
|
const facilities = ref([
|
||||||
|
{
|
||||||
|
name: '自建水质站',
|
||||||
|
count: 56,
|
||||||
|
icon: 'icon iconfont icon-qixidi'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '国家水质站',
|
||||||
|
count: 1722,
|
||||||
|
icon: 'icon iconfont icon-diwenshuijianhuan'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '人工水质监测断面',
|
||||||
|
count: 135,
|
||||||
|
icon: 'icon iconfont icon-shuiwen-line'
|
||||||
|
},
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 页面加载时执行的逻辑
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.facility-grid {
|
||||||
|
width: 406px;
|
||||||
|
flex-flow: wrap;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-card {
|
||||||
|
width: 200px;
|
||||||
|
height: 70px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 4px 0px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
// margin-right: 8px;
|
||||||
|
background: #5389b5;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-name {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
// margin-bottom: 4px;
|
||||||
|
// font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facility-count {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #2f6b98;
|
||||||
|
// font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,5 +1,21 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
||||||
|
import RightDrawer from "@/components/RightDrawer/index.vue";
|
||||||
|
import DiWenSJHSSLXZCJJRQK from "@/modules/diwenshuijianhuansheshileixingzuchengjijieruqingkuang/index.vue"
|
||||||
|
import SheShiLeiXingJieShao from "@/modules/sheshileixingjieshao/index.vue"
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="moduleContent">
|
||||||
<h2>低温水减缓设施</h2>
|
<div class="leftContent">
|
||||||
|
<JidiSelectorMod />
|
||||||
|
</div>
|
||||||
|
<div class="rightContent">
|
||||||
|
<RightDrawer>
|
||||||
|
<SheShiLeiXingJieShao />
|
||||||
|
<DiWenSJHSSLXZCJJRQK />
|
||||||
|
</RightDrawer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
||||||
|
import RightDrawer from "@/components/RightDrawer/index.vue";
|
||||||
|
import MonthlyAvgWaterTemCompareHistory from "@/modules/monthlyAvgWaterTemCompareHistory/index.vue"; // 月平均水温历史对比
|
||||||
|
import ShuiWenNianNeiFenBu from "@/modules/shuiWenNianNeiFenBu/index.vue"; // 水温年内分布
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="moduleContent">
|
||||||
<h2>水温分析</h2>
|
<div class="leftContent">
|
||||||
|
<JidiSelectorMod />
|
||||||
|
</div>
|
||||||
|
<div class="rightContent">
|
||||||
|
<RightDrawer>
|
||||||
|
<MonthlyAvgWaterTemCompareHistory />
|
||||||
|
<ShuiWenNianNeiFenBu />
|
||||||
|
</RightDrawer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
|
||||||
|
import RightDrawer from "@/components/RightDrawer/index.vue";
|
||||||
|
import ShuiZhiJianCeGongZuoQingKuang from "@/modules/shuizhijiancegongzuoQK/index.vue"
|
||||||
|
// import EnvironmentalQuality from "@/modules/environmentalQuality/index.vue" // 环境质量满足度
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="moduleContent">
|
||||||
<h1>水质监测</h1>
|
<div class="leftContent">
|
||||||
|
<JidiSelectorMod />
|
||||||
|
</div>
|
||||||
|
<div class="rightContent">
|
||||||
|
<RightDrawer>
|
||||||
|
<ShuiZhiJianCeGongZuoQingKuang />
|
||||||
|
<!-- <EnvironmentalQuality /> -->
|
||||||
|
</RightDrawer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user