更新环境监测页面和报告模块

This commit is contained in:
Xiaoyu 2025-02-18 15:36:23 +08:00
parent fca3cde8bc
commit a4496ca0fa
3 changed files with 241 additions and 253 deletions

View File

@ -3664,7 +3664,7 @@ GET /api/education/knowledge
|»» created_by|integer|false|none||none|
|»» updated_by|integer|false|none||none|
## GET 获取知识详情
## GET
GET /api/education/knowledge/1

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import * as echarts from "echarts";
import { ElMessage } from 'element-plus';
import { Monitor, Warning, TrendCharts } from '@element-plus/icons-vue';
import { ElMessage } from "element-plus";
import { Monitor, Warning, TrendCharts } from "@element-plus/icons-vue";
interface EnvData {
id: number;
@ -65,7 +65,7 @@ const envStats = ref([
]);
//
const timeRange = ref('24h');
const timeRange = ref("24h");
//
const initChart = () => {
@ -75,167 +75,180 @@ const initChart = () => {
const myChart = echarts.init(chartDom);
const option = {
title: {
text: '环境监测趋势',
text: "环境监测趋势",
textStyle: {
fontSize: 16,
fontWeight: 500,
color: '#303133'
}
color: "#303133",
},
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(255, 255, 255, 0.95)',
borderColor: '#eee',
trigger: "axis",
backgroundColor: "rgba(255, 255, 255, 0.95)",
borderColor: "#eee",
padding: [10, 15],
textStyle: {
color: '#666'
color: "#666",
},
formatter: function (params: any) {
let result = `${params[0].axisValue}<br/>`;
params.forEach((item: any) => {
result += `${item.marker} ${item.seriesName}: ${item.value}${
item.seriesName.includes('温度') ? '°C' :
item.seriesName.includes('湿度') ? '%' : ''
item.seriesName.includes("温度")
? "°C"
: item.seriesName.includes("湿度")
? "%"
: ""
}<br/>`;
});
return result;
}
},
},
legend: {
data: ['温度', '湿度', '水质指数', '空气质量'],
data: ["温度", "湿度", "水质指数", "空气质量"],
right: 20,
top: 10,
textStyle: {
color: '#666'
color: "#666",
},
itemWidth: 12,
itemHeight: 12,
itemGap: 20
itemGap: 20,
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: {
type: 'category',
type: "category",
boundaryGap: false,
data: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00', '24:00'],
data: [
"00:00",
"03:00",
"06:00",
"09:00",
"12:00",
"15:00",
"18:00",
"21:00",
"24:00",
],
axisLine: {
lineStyle: {
color: '#DCDFE6'
}
color: "#DCDFE6",
},
},
axisTick: {
show: false
show: false,
},
axisLabel: {
color: '#909399',
formatter: '{value}'
}
color: "#909399",
formatter: "{value}",
},
},
yAxis: [
{
type: 'value',
name: '温度/湿度',
type: "value",
name: "温度/湿度",
nameTextStyle: {
color: '#909399',
padding: [0, 30, 0, 0]
color: "#909399",
padding: [0, 30, 0, 0],
},
splitLine: {
lineStyle: {
color: '#EBEEF5',
type: 'dashed'
}
color: "#EBEEF5",
type: "dashed",
},
},
axisLabel: {
color: '#909399',
formatter: '{value}'
}
color: "#909399",
formatter: "{value}",
},
},
{
type: 'value',
name: '指数',
type: "value",
name: "指数",
nameTextStyle: {
color: '#909399',
padding: [0, 0, 0, 30]
color: "#909399",
padding: [0, 0, 0, 30],
},
splitLine: {
show: false
show: false,
},
axisLabel: {
color: '#909399',
formatter: '{value}'
}
}
color: "#909399",
formatter: "{value}",
},
},
],
series: [
{
name: '温度',
type: 'line',
name: "温度",
type: "line",
smooth: true,
lineStyle: {
width: 3,
color: '#409EFF'
color: "#409EFF",
},
itemStyle: {
color: '#409EFF'
color: "#409EFF",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(64, 158, 255, 0.2)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0)' }
])
{ offset: 0, color: "rgba(64, 158, 255, 0.2)" },
{ offset: 1, color: "rgba(64, 158, 255, 0)" },
]),
},
data: [22, 23, 24, 25, 26, 27, 26, 25, 24]
data: [22, 23, 24, 25, 26, 27, 26, 25, 24],
},
{
name: '湿度',
type: 'line',
name: "湿度",
type: "line",
smooth: true,
lineStyle: {
width: 3,
color: '#67C23A'
color: "#67C23A",
},
itemStyle: {
color: '#67C23A'
color: "#67C23A",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(103, 194, 58, 0.2)' },
{ offset: 1, color: 'rgba(103, 194, 58, 0)' }
])
{ offset: 0, color: "rgba(103, 194, 58, 0.2)" },
{ offset: 1, color: "rgba(103, 194, 58, 0)" },
]),
},
data: [60, 62, 65, 63, 65, 68, 67, 65, 64]
data: [60, 62, 65, 63, 65, 68, 67, 65, 64],
},
{
name: '水质指数',
type: 'line',
name: "水质指数",
type: "line",
yAxisIndex: 1,
smooth: true,
lineStyle: {
width: 3,
color: '#36CFC9'
color: "#36CFC9",
},
itemStyle: {
color: '#36CFC9'
color: "#36CFC9",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(54, 207, 201, 0.2)' },
{ offset: 1, color: 'rgba(54, 207, 201, 0)' }
])
{ offset: 0, color: "rgba(54, 207, 201, 0.2)" },
{ offset: 1, color: "rgba(54, 207, 201, 0)" },
]),
},
data: [90, 91, 92, 92, 93, 92, 92, 91, 92]
}
]
data: [90, 91, 92, 92, 93, 92, 92, 91, 92],
},
],
};
myChart.setOption(option);
//
window.addEventListener('resize', () => {
window.addEventListener("resize", () => {
myChart.resize();
});
};

View File

@ -12,14 +12,14 @@ import {
Cpu,
Link,
Cellphone,
Share
Share,
} from "@element-plus/icons-vue";
const projectInfo = ref({
title: "智慧湿地管理系统",
version: "v2.0.0",
description: `智慧湿地管理系统是一个基于现代信息技术的综合性湿地生态监测和管理平台。系统采用"前后端分离+小程序"的技术架构,
实现了Web端管理和移动端监测的完整生态系统通过实时数据采集可视化展示等手段为湿地生态保护提供智能化解决方案`,
description: `智慧湿地管理系统是一个基于现代信息技术的综合性湿地生态监测和管理平台。系统采用"Web管理端+微信小程序"的架构,
通过多端协同为湿地生态保护提供智能化解决方案`,
//
stats: [
@ -49,7 +49,7 @@ const projectInfo = ref({
change: "+15%",
color: "#064E3B",
bgColor: "linear-gradient(120deg, #4ADE80 0%, #22C55E 100%)",
textColor: "#FFFFFF"
textColor: "#FFFFFF",
},
{
title: "设备在线",
@ -59,7 +59,7 @@ const projectInfo = ref({
change: "stable",
color: "#EDE9FE",
bgColor: "linear-gradient(120deg, #A78BFA 0%, #8B5CF6 100%)",
textColor: "#FFFFFF"
textColor: "#FFFFFF",
},
],
@ -73,40 +73,28 @@ const projectInfo = ref({
{ name: "Element Plus", desc: "组件库" },
{ name: "TypeScript", desc: "开发语言" },
{ name: "ECharts", desc: "数据可视化" },
{ name: "Vite", desc: "构建工具" }
]
{ name: "Vite", desc: "构建工具" },
],
},
backend: {
title: "后端服务",
icon: Cpu,
items: [
{ name: "Node.js", desc: "运行环境" },
{ name: "MySQL", desc: "数据存储" },
{ name: "Redis", desc: "缓存服务" },
{ name: "RESTful API", desc: "接口规范" },
{ name: "WebSocket", desc: "实时通信" }
]
{ name: "MySQL", desc: "数据库" },
{ name: "Apifox", desc: "接口管理" },
],
},
miniapp: {
title: "小程序端",
icon: Cellphone,
items: [
{ name: "微信小程序", desc: "WXML & WXSS" },
{ name: "微信小程序", desc: "原生开发" },
{ name: "Vant Weapp", desc: "UI组件库" },
{ name: "wx-charts", desc: "图表库" },
{ name: "WebSocket", desc: "实时通信" }
]
{ name: "wx-charts", desc: "轻量图表库" },
{ name: "ec-canvas", desc: "ECharts适配" },
],
},
deployment: {
title: "开发部署",
icon: Share,
items: [
{ name: "Git", desc: "版本控制" },
{ name: "Docker", desc: "容器化部署" },
{ name: "Nginx", desc: "Web服务器" },
{ name: "PM2", desc: "进程管理" }
]
}
},
//
@ -115,33 +103,27 @@ const projectInfo = ref({
title: "Web管理端",
icon: Monitor,
desc: "提供完整的湿地生态系统管理功能",
features: ["数据看板", "环境监测", "物种管理", "系统配置"]
},
{
title: "环境监测",
icon: DataAnalysis,
desc: "实时采集和分析环境数据",
features: ["水质监测", "空气监测", "土壤监测", "气象监测"]
features: ["数据看板", "环境监测", "物种管理", "系统配置"],
},
{
title: "小程序端",
icon: Cellphone,
desc: "面向公众的湿地生态互动平台",
features: [
"实时数据查看",
"生态科普",
"环保打卡",
"在线咨询",
"消息通知"
]
"实时生态数据监测",
"湿地生态知识科普",
"最新公告通知",
"环保行为打卡",
"AI生态问答助手",
],
},
{
title: "巡护管理",
icon: Location,
desc: "智能化的巡护任务管理系统",
features: ["任务分配", "轨迹记录", "实时通讯", "数据采集"]
}
]
title: "数据服务",
icon: DataAnalysis,
desc: "提供数据存储和分析能力",
features: ["数据采集", "实时监测", "数据分析", "预警提醒"],
},
],
});
</script>
@ -160,18 +142,19 @@ const projectInfo = ref({
</div>
</div>
<!-- 系统架构 -->
<div class="architecture-section">
<!-- 系统架构部分 -->
<div class="section architecture-section">
<h2>系统架构</h2>
<div class="arch-grid">
<el-card v-for="(arch, key) in projectInfo.architecture"
<div class="card-grid">
<el-card
v-for="(arch, key) in projectInfo.architecture"
:key="key"
class="arch-card"
shadow="hover">
<div class="arch-header">
<el-icon :size="24" :class="key">
<component :is="arch.icon" />
</el-icon>
>
<div class="card-header">
<div :class="['icon-wrapper', key]">
<el-icon><component :is="arch.icon" /></el-icon>
</div>
<h3>{{ arch.title }}</h3>
</div>
<ul class="tech-list">
@ -184,14 +167,15 @@ const projectInfo = ref({
</div>
</div>
<!-- 应用场景 -->
<div class="scenarios-section">
<!-- 应用场景部分 -->
<div class="section scenarios-section">
<h2>应用场景</h2>
<div class="scenario-grid">
<el-card v-for="scenario in projectInfo.scenarios"
<div class="card-grid">
<el-card
v-for="scenario in projectInfo.scenarios"
:key="scenario.title"
class="scenario-card"
shadow="hover">
>
<div class="scenario-icon">
<el-icon :size="32">
<component :is="scenario.icon" />
@ -200,9 +184,7 @@ const projectInfo = ref({
<h3>{{ scenario.title }}</h3>
<p>{{ scenario.desc }}</p>
<div class="feature-tags">
<el-tag v-for="feature in scenario.features"
:key="feature"
size="small">
<el-tag v-for="feature in scenario.features" :key="feature" size="small">
{{ feature }}
</el-tag>
</div>
@ -214,6 +196,108 @@ const projectInfo = ref({
<style lang="scss" scoped>
.about-container {
padding: 20px;
.section {
margin-bottom: 60px;
h2 {
font-size: 24px;
margin-bottom: 30px;
text-align: center;
color: #303133;
}
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
max-width: 1200px;
margin: 0 auto;
padding: 0 24px; //
}
}
//
.el-card {
border: none;
border-radius: 12px;
transition: all 0.3s;
height: 100%;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
.icon-wrapper {
width: 64px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 16px;
font-size: 24px;
&.frontend {
background: rgba(24, 144, 255, 0.1);
color: #1890ff;
}
&.backend {
background: rgba(82, 196, 26, 0.1);
color: #52c41a;
}
&.miniapp {
background: rgba(250, 84, 28, 0.1);
color: #fa541c;
}
}
h3 {
margin: 0;
font-size: 18px;
color: #303133;
}
}
}
//
.tech-list {
list-style: none;
padding: 0;
margin: 0;
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.tech-name {
font-weight: 500;
color: #303133;
}
.tech-desc {
font-size: 13px;
color: #909399;
}
}
}
.hero-section {
padding: 40px;
margin: -20px -20px 20px;
@ -264,105 +348,7 @@ const projectInfo = ref({
}
}
.architecture-section {
margin-bottom: 60px;
h2 {
font-size: 24px;
margin-bottom: 30px;
text-align: center;
color: #303133;
}
.arch-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
}
.arch-card {
.arch-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
.el-icon {
padding: 12px;
border-radius: 8px;
&.frontend {
background: rgba(24, 144, 255, 0.1);
color: #1890FF;
}
&.backend {
background: rgba(82, 196, 26, 0.1);
color: #52C41A;
}
&.miniapp {
background: rgba(250, 84, 28, 0.1);
color: #FA541C;
}
&.tools {
background: rgba(114, 46, 209, 0.1);
color: #722ED1;
}
}
h3 {
margin: 0;
font-size: 18px;
color: #303133;
}
}
.tech-list {
list-style: none;
padding: 0;
margin: 0;
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.tech-name {
font-weight: 500;
color: #303133;
}
.tech-desc {
font-size: 13px;
color: #909399;
}
}
}
}
}
.scenarios-section {
h2 {
font-size: 24px;
margin-bottom: 30px;
text-align: center;
color: #303133;
}
.scenario-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.scenario-card {
text-align: center;
padding: 30px;
@ -376,7 +362,7 @@ const projectInfo = ref({
justify-content: center;
border-radius: 16px;
background: rgba(24, 144, 255, 0.1);
color: #1890FF;
color: #1890ff;
}
h3 {
@ -403,16 +389,5 @@ const projectInfo = ref({
}
}
}
.el-card {
border: none;
border-radius: 12px;
transition: all 0.3s;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
}
}
</style>