2025-05-20 17:34:11 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div>
|
|
|
|
|
<common>
|
|
|
|
|
<template #main>
|
|
|
|
|
<div>
|
|
|
|
|
<devices :title="'环境监测设备'" :devices="devices"></devices>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="margin-top: 10px; display: flex; justify-content: space-between">
|
|
|
|
|
<div style="display: flex; justify-content: space-between; margin-top: 10px; width: 100%">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<el-card style="width: 60%; margin-right: 20px; border-radius: 16px">
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div style="display: flex; justify-content: space-between">
|
|
|
|
|
<div style="font-size: 16px; font-weight: bold; text-align: left">实时环境监测</div>
|
2025-05-26 17:10:06 +08:00
|
|
|
|
<div>
|
|
|
|
|
<div>当前设备状态:</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="dot"></div>
|
|
|
|
|
<span>正常</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div style="color: #999999; line-height: 25px">
|
|
|
|
|
当前设备
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<el-select
|
|
|
|
|
v-model="currentDevice"
|
|
|
|
|
placeholder="Select"
|
|
|
|
|
size="small"
|
|
|
|
|
style="width: 160px; margin-left: 10px"
|
|
|
|
|
@change="changeDevice($event)"
|
|
|
|
|
>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<el-option v-for="item in devices" :key="item.value" :label="item.detail" :value="item.id" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="envData">
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.co2 }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">空气温度</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.humidity }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">空气湿度</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.rainfall }}</div>
|
|
|
|
|
<div class="points">降水量</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.wind }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">风向</div>
|
|
|
|
|
</div>
|
2025-05-21 17:21:03 +08:00
|
|
|
|
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.pm25 }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">PM2.5</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.light }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">光照强度</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.co2 }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">二氧化碳浓度</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="dt">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<div class="values">{{ monitorData.windSpeed }}</div>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<div class="points">风速</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="notices">
|
|
|
|
|
<div v-for="(item, index) in notices" :key="index">
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<img :src="getAssetsFile('images/smartFarm/bell.png')" alt="" style="height: 20px; margin-right: 5px" />
|
2025-05-20 17:34:11 +08:00
|
|
|
|
<span style="font-size: 14px">{{ item.title }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-card>
|
2025-05-21 17:21:03 +08:00
|
|
|
|
<DataDisplay :title="'环境分析报告'" :data="rightData" style="flex: 1"></DataDisplay>
|
2025-05-20 17:34:11 +08:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</common>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-05-21 17:21:03 +08:00
|
|
|
|
import { onMounted, ref } from 'vue';
|
2025-05-20 17:34:11 +08:00
|
|
|
|
import Devices from '@/views/smartFarm/components/devices.vue';
|
|
|
|
|
import Common from '@/views/smartFarm/components/common.vue';
|
|
|
|
|
import { getAssetsFile } from '@/utils/index.js';
|
2025-05-21 17:21:03 +08:00
|
|
|
|
import DataDisplay from '@/views/smartFarm/components/dataDisplay.vue';
|
|
|
|
|
import Mock from 'mockjs';
|
2025-05-20 17:34:11 +08:00
|
|
|
|
|
|
|
|
|
/* --------------- data --------------- */
|
|
|
|
|
// #region
|
|
|
|
|
const devices = ref([
|
|
|
|
|
{
|
|
|
|
|
name: 'A-001',
|
|
|
|
|
icon: 'temp',
|
|
|
|
|
detail: 'A区-监控设备1',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 0,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'A-004',
|
|
|
|
|
icon: 'soilSensor',
|
|
|
|
|
detail: 'A区-监控设备4',
|
|
|
|
|
status: '-1',
|
|
|
|
|
id: 3,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'A-005',
|
|
|
|
|
icon: 'anemometer',
|
|
|
|
|
detail: 'A区-监控设备5',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 4,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'B-001',
|
|
|
|
|
icon: 'rainGauge',
|
|
|
|
|
detail: 'B区-监控设备1',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 6,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'B-003',
|
|
|
|
|
icon: 'waterLoggingSensor',
|
|
|
|
|
detail: 'B区-监控设备3',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 8,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'B-004',
|
|
|
|
|
icon: 'PM2.5',
|
|
|
|
|
detail: 'B区-监控设备4',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 9,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: 'B-006',
|
|
|
|
|
icon: 'light',
|
|
|
|
|
detail: 'B区-监控设备6',
|
|
|
|
|
status: '1',
|
|
|
|
|
id: 11,
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
const currentDevice = ref(0);
|
|
|
|
|
const notices = ref([
|
|
|
|
|
{
|
2025-05-21 17:21:03 +08:00
|
|
|
|
title: '2025年1月2日,预计将会有特大暴雨,请提前做好防护措施!',
|
2025-05-20 17:34:11 +08:00
|
|
|
|
content: '',
|
|
|
|
|
},
|
|
|
|
|
{
|
2025-05-21 17:21:03 +08:00
|
|
|
|
title: '2025年1月1日,预计将会有大雨,请提前做好防护措施!',
|
2025-05-20 17:34:11 +08:00
|
|
|
|
content: '',
|
|
|
|
|
},
|
|
|
|
|
]);
|
2025-05-21 17:21:03 +08:00
|
|
|
|
let monitorData = ref({});
|
|
|
|
|
let rightData = ref([]);
|
|
|
|
|
const changeDevice = (id) => {
|
|
|
|
|
currentDevice.value = id;
|
|
|
|
|
monitorData.value = getMockData()[0];
|
|
|
|
|
rightData.value = getMockData()[1];
|
|
|
|
|
};
|
|
|
|
|
// 生成模拟数据
|
|
|
|
|
const getMockData = () => {
|
|
|
|
|
// 左侧环境监测数据
|
|
|
|
|
const leftData = Mock.mock({
|
|
|
|
|
co2: () => randomRange(200, 800, 0) + 'ppm', // CO₂浓度(300~800ppm)
|
|
|
|
|
temperature: () => randomRange(-10, 40, 1) + '℃', // 温度(-10~40℃)
|
|
|
|
|
humidity: () => randomRange(10, 100, 0) + '%', // 湿度(10%~100%)
|
|
|
|
|
wind: '@pick(["东南风", "西南风", "东北风", "西北风"])',
|
|
|
|
|
rainfall: () => randomRange(0, 200, 1) + 'mm', // 降水量(0~200mm,1位小数)
|
|
|
|
|
pm25: () => randomRange(0, 300, 0) + 'μg/m³', // PM2.5(0~300μg/m³,整数)
|
|
|
|
|
light: () => randomRange(100, 1000, 0) + 'Lux', // 光照强度(100~1000Lux,整数)
|
|
|
|
|
windSpeed: () => randomRange(0, 10, 1) + 'm/s', // 风速(0~10m/s,1位小数)
|
|
|
|
|
});
|
|
|
|
|
// 右侧环境分析报告数据
|
|
|
|
|
const rightData = Mock.mock({
|
|
|
|
|
'list|6': [
|
|
|
|
|
{
|
|
|
|
|
// 基础字段
|
|
|
|
|
'title|+1': ['酸碱度(pH)', '养分含量', '重金属含量', '水温', '水浑浊度', '盐分含量'],
|
|
|
|
|
'status|1': ['0', '1'],
|
|
|
|
|
'unit|+1': ['pH值', '%', 'mg/kg', '℃', 'NTU', 'dS/m'],
|
|
|
|
|
|
|
|
|
|
// 动态生成异常文本
|
|
|
|
|
statusText: function () {
|
|
|
|
|
const statusMap = {
|
|
|
|
|
'酸碱度(pH)':
|
|
|
|
|
this.status === '0' ? `酸碱度${Mock.mock('@float(4.0, 9.0, 1, 1)')}(${Mock.mock('@pick(["酸性过强","碱性过强"])')})` : '正常',
|
|
|
|
|
养分含量: this.status === '0' ? `${Mock.mock('@pick(["N","P","K","Ca","Mg"])')}元素含量不足` : '正常',
|
|
|
|
|
重金属含量: this.status === '0' ? `${Mock.mock('@pick(["镉","铅","砷","汞"])')}超标(${Mock.mock('@float(1, 5, 1, 1)')}mg/kg)` : '正常',
|
|
|
|
|
水温: this.status === '0' ? `${Mock.mock('@integer(10, 40)')}℃(${Mock.mock('@pick(["低温胁迫","高温胁迫"])')})` : '正常',
|
|
|
|
|
水浑浊度: this.status === '0' ? `浊度${Mock.mock('@integer(10, 50)')}NTU` : '正常',
|
|
|
|
|
盐分含量: this.status === '0' ? `盐分${Mock.mock('@float(2, 5, 1, 1)')}dS/m` : '正常',
|
|
|
|
|
};
|
|
|
|
|
return statusMap[this.title];
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
return [leftData, rightData.list];
|
|
|
|
|
};
|
|
|
|
|
// 自定义随机范围函数
|
|
|
|
|
const randomRange = (min, max, fixed = 0) => {
|
|
|
|
|
return Mock.Random.float(min, max, fixed).toFixed(fixed);
|
|
|
|
|
};
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
changeDevice(0);
|
|
|
|
|
});
|
2025-05-20 17:34:11 +08:00
|
|
|
|
// #endregion
|
|
|
|
|
|
|
|
|
|
/* --------------- methods --------------- */
|
|
|
|
|
// #region
|
|
|
|
|
const chooseIcon = (type) => {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'light':
|
|
|
|
|
return '分光器.png';
|
|
|
|
|
case 'float':
|
|
|
|
|
return '悬浮物.png';
|
|
|
|
|
case 'O2':
|
|
|
|
|
return '水质溶解氧.png';
|
|
|
|
|
case 'elect':
|
|
|
|
|
return '水质电导率.png';
|
|
|
|
|
case 'dust':
|
|
|
|
|
return '浊度.png';
|
|
|
|
|
case 'temp':
|
|
|
|
|
return '温度.png';
|
|
|
|
|
case 'ph':
|
|
|
|
|
return '酸碱度.png';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// #endregion
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2025-05-26 17:10:06 +08:00
|
|
|
|
.dot {
|
|
|
|
|
height: 10px;
|
|
|
|
|
width: 10px;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
border-radius: 90px;
|
|
|
|
|
background-color: #25bf82;
|
|
|
|
|
}
|
2025-05-20 17:34:11 +08:00
|
|
|
|
.plantStatus {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
margin: 7px 0;
|
|
|
|
|
.leftKey {
|
|
|
|
|
color: #000000;
|
|
|
|
|
}
|
|
|
|
|
.rightValue {
|
|
|
|
|
color: #25bf82;
|
|
|
|
|
}
|
|
|
|
|
.errorValue {
|
|
|
|
|
color: #fe4066;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.notices {
|
|
|
|
|
div {
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
}
|
|
|
|
|
text-align: left;
|
|
|
|
|
}
|
|
|
|
|
.envData {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
2025-05-21 17:21:03 +08:00
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
margin-top: 20px;
|
2025-05-20 17:34:11 +08:00
|
|
|
|
.dt {
|
2025-05-21 17:21:03 +08:00
|
|
|
|
width: 25%;
|
2025-05-20 17:34:11 +08:00
|
|
|
|
text-align: left;
|
2025-05-21 17:21:03 +08:00
|
|
|
|
margin-bottom: 20px;
|
2025-05-20 17:34:11 +08:00
|
|
|
|
.values {
|
|
|
|
|
color: #25bf82;
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
.points {
|
|
|
|
|
color: #999999;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.plantStatus {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
margin: 10px 0;
|
|
|
|
|
|
|
|
|
|
.leftKey {
|
|
|
|
|
color: #000000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.rightValue {
|
|
|
|
|
color: #25bf82;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|