水温监测页面右侧组件完成

This commit is contained in:
王兴凯 2026-04-10 11:11:30 +08:00
parent 5695480021
commit 0a0433c3b8
9 changed files with 1121 additions and 158 deletions

View File

@ -39,7 +39,7 @@ const initChart = () => {
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)',
formatter: '{a} {b}: {c} ({d}%)',
position: 'right'
},
legend: {

View File

@ -0,0 +1,424 @@
<!-- 垂向水温变化图 -->
<template>
<SidePanelItem title="垂向水温变化">
<div class="chart-wrapper">
<!-- 图例与翻页控制 -->
<div class="chart-header">
<div class="legend-container">
<div
v-for="item in currentLegendItems"
:key="item.name"
class="legend-item"
:class="{ inactive: legendInactiveSet.has(item.name) }"
@click="toggleLegend(item.name)"
>
<span class="legend-dot" :style="{ backgroundColor: legendInactiveSet.has(item.name) ? '#ccc' : item.color }"></span>
<span class="legend-text" :style="{ color: legendInactiveSet.has(item.name) ? '#ccc' : '#333' }">{{ item.name }}</span>
</div>
</div>
<div class="pagination">
<span class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage"></span>
<span class="page-info">{{ currentPage }}/{{ totalPages }}</span>
<span class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage"></span>
</div>
</div>
<!-- 图表容器 -->
<div ref="chartRef" class="chart-container"></div>
</div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
//
defineOptions({
name: 'chuixiangshuiwenChangeMod'
});
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
//
const ITEMS_PER_PAGE = 5; // 5
const currentPage = ref(1);
// inactive
const legendInactiveSet = ref<Set<string>>(new Set());
// 12稿
const monthColors: Record<string, string> = {
'1月': '#5B9BD5',
'2月': '#70AD47',
'3月': '#7030A0',
'4月': '#ED7D31',
'5月': '#A5A5A5',
'6月': '#FFC000',
'7月': '#4472C4',
'8月': '#548235',
'9月': '#6F35A0',
'10月': '#C55A11',
'11月': '#8497B0',
'12月': '#7F7F7F'
};
// 12
const allLegendItems = ref(
Object.keys(monthColors).map(month => ({
name: month,
color: monthColors[month]
}))
);
//
const totalPages = computed(() => {
return Math.ceil(allLegendItems.value.length / ITEMS_PER_PAGE);
});
//
const currentLegendItems = computed(() => {
const start = (currentPage.value - 1) * ITEMS_PER_PAGE;
const end = start + ITEMS_PER_PAGE;
return allLegendItems.value.slice(start, end);
});
// -
const depths = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
//
const generateMonthData = (monthIndex: number) => {
const baseSurfaceTemp = 2 + monthIndex * 2.2;
const deepWaterTemp = 3.5 + monthIndex * 0.3;
return depths.map((depth, index) => {
let temp;
if (depth <= 10) {
temp = baseSurfaceTemp - depth * 0.15 + Math.sin(index * 0.8) * 0.5;
} else if (depth <= 40) {
const middleFactor = (depth - 10) / 30;
temp = baseSurfaceTemp - 1.5 - middleFactor * (baseSurfaceTemp - deepWaterTemp) * 0.6;
} else {
temp = deepWaterTemp + Math.sin(index * 0.3) * 0.2;
}
return Math.max(0, Math.round(temp * 100) / 100);
});
};
// [, ]
const monthData = ref(
Array.from({ length: 12 }, (_, i) => ({
month: `${i + 1}`,
data: generateMonthData(i).map((temp, idx) => [temp, depths[idx]]) // [, ]
}))
);
// /
const toggleLegend = (name: string) => {
if (legendInactiveSet.value.has(name)) {
legendInactiveSet.value.delete(name);
} else {
legendInactiveSet.value.add(name);
}
updateChart();
};
//
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
updateChart();
}
};
//
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++;
updateChart();
}
};
//
const initChart = () => {
if (!chartRef.value) return;
if (chartRef.value.clientHeight === 0) {
setTimeout(() => initChart(), 100);
return;
}
chartInstance = echarts.init(chartRef.value);
updateChart();
// (ECharts)
// chartInstance.on('legendselectchanged', (params: any) => { ... });
};
//
const updateChart = () => {
if (!chartInstance) return;
const option = {
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#ccc',
borderWidth: 1,
textStyle: {
color: '#333',
fontSize: 12
},
formatter: (params: any) => {
if (!params || !params.seriesName) return '';
const temperature = params.data[0]; //
const depth = params.data[1]; //
return `<div style="font-weight:bold;margin-bottom:8px;">${params.seriesName}</div>
<div>水温(°C)${temperature}</div>
<div>深度(m)${depth}</div>`;
}
},
legend: {
show: true,
data: allLegendItems.value.map(item => ({
name: item.name,
icon: 'circle'
})),
selected: allLegendItems.value.reduce((acc, item) => {
acc[item.name] = !legendInactiveSet.value.has(item.name);
return acc;
}, {} as Record<string, boolean>),
// ECharts使
top: -9999
},
grid: {
left: '70px',
right: '100px',
bottom: '60px',
top: '30px'
},
xAxis: {
type: 'value',
position: 'top',
name: '水温(°C)',
nameLocation: 'end',
nameGap: 20,
nameTextStyle: {
color: '#666',
fontSize: 12,
align: 'right',
verticalAlign: 'top'
},
min: 0,
max: 8,
interval: null,
axisLine: {
show: true,
lineStyle: {
color: '#d0d0d0',
width: 1
}
},
axisTick: {
show: true,
length: 4,
inside: false,
lineStyle: {
color: '#d0d0d0'
}
},
axisLabel: {
color: '#666',
fontSize: 11,
margin: 6,
formatter: (value: number) => {
const showTicks = [0, 3, 6, 8];
if (showTicks.includes(value)) {
return value.toString();
}
return '';
}
},
splitLine: {
show: false
}
},
yAxis: {
type: 'value',
position: 'left',
inverse: true,
min: 0,
max: 80,
interval: 20,
name: '水深(m)',
nameLocation: 'end',
nameGap: 25,
nameRotate: 0,
nameTextStyle: {
color: '#666',
fontSize: 12,
align: 'center',
verticalAlign: 'top'
},
axisLine: {
show: true,
lineStyle: {
color: '#d0d0d0',
width: 1
}
},
axisTick: {
show: true,
length: 3,
inside: false,
lineStyle: {
color: '#d0d0d0'
}
},
axisLabel: {
color: '#666',
fontSize: 11,
inside: false,
margin: 8
},
splitLine: {
show: true,
lineStyle: {
color: '#e5e5e5',
type: 'dashed',
width: 1
}
}
},
series: monthData.value.map((monthItem: any) => ({
name: monthItem.month,
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 2,
lineStyle: {
width: 1,
color: monthColors[monthItem.month]
},
itemStyle: {
color: monthColors[monthItem.month]
},
data: monthItem.data.map((item: any) => [item[0], item[1]]),
connectNulls: false
}))
};
chartInstance.setOption(option, { notMerge: true });
};
//
onMounted(() => {
initChart();
//
window.addEventListener('resize', () => {
chartInstance?.resize();
});
});
//
onBeforeUnmount(() => {
chartInstance?.dispose();
window.removeEventListener('resize', () => {
chartInstance?.resize();
});
});
</script>
<style scoped>
.chart-wrapper {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid #e8e8e8;
}
.legend-container {
display: flex;
flex-wrap: wrap;
gap: 12px;
flex: 1;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
transition: opacity 0.3s;
}
.legend-item.inactive {
opacity: 0.5;
}
.legend-dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
}
.legend-text {
font-size: 12px;
user-select: none;
}
.pagination {
display: flex;
align-items: center;
gap: 8px;
}
.page-btn {
cursor: pointer;
padding: 2px 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px;
user-select: none;
transition: all 0.3s;
}
.page-btn:hover:not(.disabled) {
border-color: #1890ff;
color: #1890ff;
}
.page-btn.disabled {
cursor: not-allowed;
opacity: 0.5;
}
.page-info {
font-size: 12px;
color: #666;
}
.chart-container {
flex: 1;
width: 100%;
min-height: 300px;
}
</style>

View File

@ -0,0 +1,240 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="出入库水温">
<div ref="chartContainer" class="chart-container"></div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as echarts from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// (便)
defineOptions({
name: 'churukushuiwenMod'
});
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
//
onMounted(() => {
// , DOM
setTimeout(() => {
if (chartContainer.value) {
initChart();
window.addEventListener('resize', handleResize);
}
}, 100);
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
const initChart = () => {
if (!chartContainer.value) return;
// , 0
const containerHeight = chartContainer.value.offsetHeight;
if (containerHeight === 0) {
setTimeout(() => initChart(), 100);
return;
}
chartInstance = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(50, 50, 50, 0.9)',
borderColor: 'transparent',
textStyle: {
color: '#fff',
fontSize: 14
},
axisPointer: {
type: 'line',
lineStyle: {
color: 'rgba(91, 143, 249, 0.15)',
width: 30,
type: 'solid'
}
},
formatter: function(params: any) {
if (!params || params.length === 0) return '';
const date = params[0].name;
let result = `<div style="font-weight: bold; margin-bottom: 8px; font-size: 14px;">${date}</div>`;
params.forEach((item: any) => {
result += `<div style="display: flex; align-items: center; gap: 6px; margin: 4px 0; font-size: 14px;">
<span style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: ${item.color};"></span>
<span>${item.seriesName}</span>
<span style="font-weight: bold; margin-left: auto;">${item.value}°C</span>
</div>`;
});
return result;
}
},
title: {
text: '水温(°C)',
left: 17,
top: 13,
textStyle: {
fontSize: 13,
color: '#000000',
fontWeight: 'normal'
}
},
legend: {
data: ['入库水温', '出库水温'],
top: 13,
left: 'center',
itemWidth: 10,
itemHeight: 10,
itemGap: 20,
textStyle: {
fontSize: 13,
color: '#000000'
}
},
grid: {
left: '10%',
right: '5%',
top: '15%',
bottom: '18%'
},
xAxis: {
type: 'category',
data: ['2026-04-01', '2026-04-02', '2026-04-03', '2026-04-04', '2026-04-05', '2026-04-06', '2026-04-07'],
boundaryGap: true,
axisLine: {
show: true,
lineStyle: {
color: '#000000'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#000000',
fontSize: 13,
margin: 10,
interval: 2
},
splitLine: {
show: true,
lineStyle: {
color: '#bfbfbf',
type: 'solid'
}
}
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
minValueSpan: 2,
zoomOnMouseWheel: true,
moveOnMouseMove: true,
moveOnMouseWheel: false,
zoomLock: false,
throttle: 50
}
],
yAxis: {
type: 'value',
min: 5.2,
max: 5.9,
interval: 0.1,
axisLine: {
show: true,
lineStyle: {
color: '#000000',
width: 1
}
},
axisTick: {
show: true,
lineStyle: {
color: '#000000',
width: 1
},
length: 4
},
axisLabel: {
color: '#000000',
fontSize: 12,
formatter: '{value}'
},
splitLine: {
show: true,
lineStyle: {
color: '#bfbfbf',
type: 'solid'
}
}
},
series: [
{
name: '入库水温',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: '#4b79ab'
},
itemStyle: {
color: '#4b79ab'
},
data: [5.4, 5.3, 5.6, 5.4, 5.5, 5.6, 5.6]
},
{
name: '出库水温',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: '#78c300'
},
itemStyle: {
color: '#78c300'
},
data: [5.8, 5.8, 5.8, 5.8, 5.8, 5.8, 5.8]
}
]
};
chartInstance.setOption(option);
// ,
setTimeout(() => {
if (chartInstance) {
chartInstance.resize();
}
}, 50);
};
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 252px;
}
</style>

View File

@ -1,10 +1,9 @@
<!-- SidePanelItem.vue -->
<template>
<div class="carousel-container">
<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' }">
<a-carousel v-model:current="currentIndex" class="tech-carousel" :dot-style="{ bottom: '0px' }">
<!-- autoplay -->
<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" />
@ -21,7 +20,6 @@
<a-empty />
</div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
@ -67,93 +65,64 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.carousel-wrapper {
width: 100%;
:deep(.ant-carousel) {
width: 100%;
.slick-slide {
height: auto !important;
}
.slick-dots {
bottom: 0px !important;
margin: 0;
padding: 8px 0;
display: flex;
justify-content: center;
gap: 6px;
li {
width: 6px;
height: 6px;
margin: 0;
background-color: transparent;
border-radius: 50%;
button {
width: 6px;
height: 6px;
background-color: #005293;
opacity: 0.3;
border-radius: 50%;
transition: all 0.3s;
padding: 0;
border: none;
}
&.slick-active button {
width: 8px;
height: 8px;
opacity: 1;
background-color: #005293;
}
}
}
}
}
.carousel-item {
display: block;
}
.image-container {
width: 100%;
background-color: #f5f0e1; //
display: flex;
align-items: center;
justify-content: center;
:deep(.slick-slide) {
text-align: center;
height: 250px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.carousel-image {
width: 100%;
height: auto;
display: block;
object-fit: contain; //
: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 {
padding: 12px 0 0 0;
text-align: left;
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;
}
.item-title {
font-size: 16px;
font-weight: 600;
color: #1f1f1f;
margin: 0 0 8px 0;
line-height: 1.5;
}
.item-description {
font-size: 14px;
color: #595959;
margin: 0;
line-height: 1.8;
text-align: justify;
}
</style>

View File

@ -6,7 +6,7 @@
<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">
<img width="18" height="14" :src="facility.icon ">
<img style="width: 18px;height: 14px;" :src="facility.icon ">
</div>
</div>
@ -90,7 +90,7 @@ onMounted(() => {
flex-flow: wrap;
display: flex;
justify-content: space-between;
margin-top: -7px;
margin-top: -8px;
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;
}

View File

@ -1,8 +1,8 @@
<!-- DataTable.vue -->
<template>
<div class="data-table-container">
<a-table :columns="columns" :data-source="tableData" :pagination="false" size="middle" :customRow="customRow" bordered
class="custom-table">
<a-table :columns="columns" :data-source="tableData" :pagination="false" size="middle" :customRow="customRow"
bordered class="custom-table">
</a-table>
</div>
</template>
@ -23,7 +23,7 @@ const columns: ColumnsType = [
dataIndex: 'name',
key: 'name',
fixed: 'left',
width: 114,
width: 114.19,
align: 'left'
},
{
@ -35,21 +35,21 @@ const columns: ColumnsType = [
title: '总计',
dataIndex: 'total',
key: 'total',
// // width: 76,
width: 76.64,
align: 'center'
},
{
title: '已建',
dataIndex: 'built',
key: 'built',
// width: 76,
width: 76.64,
align: 'center'
},
{
title: '在建',
dataIndex: 'building',
key: 'building',
// width: 76,
width: 68.25,
align: 'center'
},
{
@ -215,6 +215,7 @@ onMounted(() => {
font-size: 14px;
// border: 1px solid #d5e2ed;
border-top: 1px solid #d5e2ed;
.ant-table-thead {
>tr {
>th {
@ -222,8 +223,10 @@ border-top: 1px solid #d5e2ed;
color: #2f6b98;
// font-weight: 600;
// border: 1px solid #d5e2ed!important;
padding: 4px 6px;
padding: 0px 6px;
text-align: center;
font-weight: 600;
line-height: 31px;
&:first-child {
background-color: #e5eff8 !important;
@ -247,8 +250,10 @@ border-top: 1px solid #d5e2ed;
>tr {
>td {
// border: 1px solid #d5e2ed;
padding: 6px 6px;
padding: 0px 6px !important;
text-align: center;
overflow-wrap: break-word;
line-height: 33px;
&:first-child {
text-align: left;
@ -262,55 +267,33 @@ border-top: 1px solid #d5e2ed;
}
}
.ant-table-footer {
padding: 0;
background-color: #fafafa;
.table-footer {
.footer-row {
display: flex;
align-items: center;
padding: 12px 6px;
// border-top: 1px solid #d5e2ed;
background-color: #fafafa;
.footer-item {
flex: 1;
text-align: center;
// font-weight: 600;
color: #333;
&:first-child {
flex: 0 0 140px;
text-align: center;
}
}
}
}
}
// footer
.ant-table-footer::before {
display: none;
}
}
}
:deep() {
.ant-table-bordered .ant-table-tbody>tr>td {
border-bottom: 1px solid #d5e2ed !important;
border-inline-end: 1px solid #d5e2ed !important;
}
.ant-table-container {
border-inline-start: 1px solid #d5e2ed !important;
}
.ant-table-wrapper .ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr:not(:last-child)>th {
border-bottom: 1px solid #d5e2ed !important;
}
.ant-table-wrapper .ant-table.ant-table-bordered>.ant-table-container>.ant-table-content>table>thead>tr>th {
border-inline-end: 1px solid #d5e2ed !important;
}
.ant-table-wrapper .ant-table-thead>tr>th {
border-bottom: 0px solid #d5e2ed !important;
border-bottom: 1px solid #d5e2ed00 !important;
}
}

View File

@ -0,0 +1,106 @@
<!-- 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: 'shuiwenjiancegongzuokaizhangqingkuang'
});
//
const facilities = ref([
{
name: '表层水温',
count: 145,
icon: 'icon iconfont icon-shuizhijiancezhan'
},
{
name: '垂向水温',
count: 24,
icon: 'icon iconfont icon-diwenshuijianhuan'
},
]);
//
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: 64px;
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: #2f6b98;
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>

View File

@ -0,0 +1,221 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水温变化" :prompt="prompts">
<div ref="chartRef" class="chart-container"></div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// 便
defineOptions({
name: 'yanchengshuiwenChangeMod'
});
const prompts = ref({
show: true,
value: '注:最新数据时间为2026-04-08 23',
});
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
// -
const stationNames = ref([
'班多',
'龙羊峡',
'拉西瓦',
'李家峡',
'公伯峡',
'苏只',
'积石峡'
]);
// - (°C) null
const waterTemperatures = ref([
null,
5.7,
5.7,
6.5,
7.2,
7.8,
8.4
]);
//
const currentTime = '2026-04-08 23';
//
const initChart = () => {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
const option = {
title: {
text: '水温(°C)',
left: 5,
top: 0,
textStyle: {
color: '#000000',
fontSize: 12,
fontWeight: 'normal',
}
},
tooltip: {
trigger: 'axis',
formatter: (params: any) => {
if (params && params.length > 0) {
const data = params[0];
// null
if (data.value !== null && data.value !== undefined) {
return `${currentTime}<br/>${data.name}${data.value}°C`;
}
}
return '';
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: stationNames.value,
boundaryGap: true,
axisLine: {
show: true,
lineStyle: {
color: '#8f8f8f'
}
},
axisTick: {
show: false
},
axisLabel: {
color: '#333',
fontSize: 12,
margin: 8,
interval: 0,
formatter: (value: string, index: number) => {
// 0, 2, 4, 6
// 1, 3, 5
//
if (index % 2 === 0) {
return `${value}\n `; // + +
} else {
return ` \n${value}`; // + +
}
}
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid'
}
}
},
yAxis: {
type: 'value',
min: 0,
max: 10,
interval: 2,
axisLine: {
show: true,
lineStyle: {
color: '#8f8f8f'
}
},
axisTick: {
show: true,
length: 3,
lineStyle: {
color: '#8f8f8f'
}
},
axisLabel: {
color: '#333',
fontSize: 12
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid'
}
}
},
series: [
{
name: '水温',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
color: '#6ca4f7',
width: 2
},
itemStyle: {
color: '#6ca4f7'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(108, 164, 247, 0.3)'
},
{
offset: 1,
color: 'rgba(108, 164, 247, 0.05)'
}
])
},
data: waterTemperatures.value
}
]
};
chartInstance.setOption(option);
};
//
const handleResize = () => {
chartInstance?.resize();
};
//
onMounted(() => {
// DOM
setTimeout(() => {
initChart();
//
setTimeout(() => {
chartInstance?.resize();
}, 100);
}, 50);
window.addEventListener('resize', handleResize);
});
//
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 252px;
}
</style>

View File

@ -1,5 +1,25 @@
<script setup lang="ts">
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue";
import RightDrawer from "@/components/RightDrawer/index.vue";
import ChuixiangshuiwenChangeMod from "@/modules/chuixiangshuiwenChangeMod/index.vue" //
import ChurukushuiwenMod from "@/modules/churukushuiwenMod/index.vue" //
import YanchengshuiwenChangeMod from "@/modules/yanchengshuiwenChangeMod/index.vue" // 沿
import ShuiwenJCGZKZQK from "@/modules/shuiwenjiancegongzuokaizhangqingkuang/index.vue"
</script>
<template>
<div>
<h2>水温监测</h2>
<div class="moduleContent">
<div class="leftContent">
<JidiSelectorMod />
</div>
<div class="rightContent">
<RightDrawer>
<ShuiwenJCGZKZQK />
<YanchengshuiwenChangeMod />
<ChuixiangshuiwenChangeMod />
<ChurukushuiwenMod />
</RightDrawer>
</div>
</div>
</template>
<style scoped lang="scss"></style>