优化了检测管理页

This commit is contained in:
Xiaoyu 2025-02-05 22:35:04 +08:00
parent 1e2e7c9567
commit 31a5a78224
5 changed files with 682 additions and 68 deletions

View File

@ -192,10 +192,7 @@ onMounted(() => {
</el-col>
<el-col :span="8">
<el-card
class="statistics-card"
shadow="hover"
>
<el-card class="statistics-card" shadow="hover">
<template #header>
<div class="statistics-header">
<span>环境监测</span>

View File

@ -31,6 +31,38 @@ const tableData = ref<EnvData[]>([
},
]);
//
const envStats = ref([
{
label: "水质指数",
value: 92.5,
status: "优",
type: "success",
trend: [85, 88, 90, 92.5], //
},
{
label: "空气质量",
value: 76.8,
status: "良好",
type: "success",
trend: [75, 72, 78, 76.8],
},
{
label: "温度(°C)",
value: 25.6,
status: "正常",
type: "success",
trend: [24, 25, 26, 25.6],
},
{
label: "湿度(%)",
value: 65,
status: "正常",
type: "success",
trend: [62, 64, 66, 65],
},
]);
const initChart = () => {
const chartDom = document.getElementById("envChart");
if (!chartDom) return;
@ -39,17 +71,46 @@ const initChart = () => {
const option = {
title: {
text: "24小时温度趋势",
textStyle: {
fontSize: 16,
fontWeight: 500,
color: "#2c3e50",
},
},
tooltip: {
trigger: "axis",
backgroundColor: "rgba(255,255,255,0.9)",
borderColor: "#eee",
textStyle: {
color: "#666",
},
},
xAxis: {
type: "category",
data: ["00:00", "06:00", "12:00", "18:00", "24:00"],
axisLine: {
lineStyle: {
color: "#ddd",
},
},
axisLabel: {
color: "#666",
},
},
yAxis: {
type: "value",
name: "温度(°C)",
nameTextStyle: {
color: "#666",
},
splitLine: {
lineStyle: {
color: "#eee",
},
},
axisLabel: {
color: "#666",
},
},
series: [
{
@ -57,10 +118,39 @@ const initChart = () => {
data: [22, 20, 25, 28, 23],
smooth: true,
itemStyle: {
color: "#409EFF",
color: "#1677ff",
},
areaStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "rgba(22,119,255,0.2)" },
{ offset: 1, color: "rgba(22,119,255,0.01)" },
],
},
},
emphasis: {
itemStyle: {
color: "#1677ff",
borderColor: "#fff",
borderWidth: 2,
shadowColor: "rgba(0,0,0,0.2)",
shadowBlur: 10,
},
},
},
],
grid: {
left: "3%",
right: "4%",
bottom: "3%",
top: "60px",
containLabel: true,
},
};
myChart.setOption(option);
@ -83,13 +173,142 @@ const handleExportConfirm = () => {
exportDialogVisible.value = false;
};
//
const initMiniChart = (el: HTMLElement, data: number[]) => {
const chart = echarts.init(el);
chart.setOption({
grid: {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
xAxis: {
type: "category",
show: false,
boundaryGap: false,
},
yAxis: {
type: "value",
show: false,
scale: true,
},
series: [
{
data: data,
type: "line",
smooth: true,
symbol: "circle",
symbolSize: 0,
sampling: "average",
showSymbol: false,
emphasis: {
focus: "series",
showSymbol: true,
symbolSize: 4,
},
lineStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#409EFF",
},
{
offset: 1,
color: "#36CFFB",
},
],
},
width: 2,
},
areaStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "rgba(64,158,255,0.25)",
},
{
offset: 1,
color: "rgba(54,207,251,0.05)",
},
],
},
},
},
],
tooltip: {
trigger: "axis",
formatter: "{c}",
backgroundColor: "rgba(255,255,255,0.9)",
borderColor: "#eee",
borderWidth: 1,
textStyle: {
color: "#666",
fontSize: 12,
},
padding: [4, 8],
},
});
// hover
const card = el.closest(".env-card");
if (card) {
card.addEventListener("mouseenter", () => {
chart.dispatchAction({
type: "showTip",
seriesIndex: 0,
dataIndex: data.length - 1,
});
});
card.addEventListener("mouseleave", () => {
chart.dispatchAction({
type: "hideTip",
});
});
}
};
onMounted(() => {
//
envStats.value.forEach((stat, index) => {
const el = document.getElementById(`miniChart${index}`);
if (el) {
initMiniChart(el, stat.trend);
}
});
//
initChart();
});
</script>
<template>
<div class="env-container">
<!-- 环境指标卡片 -->
<el-row :gutter="20" class="mb-20">
<el-col :span="6" v-for="(item, index) in envStats" :key="index">
<div class="env-card">
<div class="env-header">
<span class="label">{{ item.label }}</span>
<el-tag :type="item.type" effect="plain">{{ item.status }}</el-tag>
</div>
<div class="env-value">{{ item.value }}</div>
<div class="env-chart" :id="`miniChart${index}`"></div>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-card>
@ -169,16 +388,116 @@ onMounted(() => {
@import "../../../styles/variables.scss";
.env-container {
.env-card {
background: #fff;
border-radius: 8px;
padding: 20px;
height: 140px;
position: relative;
overflow: hidden;
transition: all 0.3s;
cursor: pointer;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08);
.env-chart {
opacity: 1;
}
}
.env-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.label {
font-size: 14px;
color: $text-secondary;
}
.el-tag {
border: none;
padding: 2px 8px;
font-size: 12px;
height: 22px;
line-height: 20px;
border-radius: 4px;
}
}
.env-value {
font-size: 32px;
font-weight: 600;
color: $text-primary;
line-height: 1;
margin-bottom: 12px;
position: relative;
z-index: 1;
}
.env-chart {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 50px;
opacity: 0.8;
transition: opacity 0.3s;
}
}
.el-card {
background: #ffffff;
border: none;
border-radius: 4px;
border-radius: 8px;
transition: all 0.3s;
box-shadow: $box-shadow;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08);
}
.el-card__header {
padding: 16px 20px;
border-bottom: 1px solid $border-color;
}
.el-tag {
transition: all 0.3s;
&.el-tag--success {
background-color: rgba(103, 194, 58, 0.1);
border-color: rgba(103, 194, 58, 0.2);
}
&.el-tag--warning {
background-color: rgba(230, 162, 60, 0.1);
border-color: rgba(230, 162, 60, 0.2);
}
}
}
.el-table {
:deep(tbody tr) {
transition: all 0.3s;
&:hover {
background-color: rgba(64, 158, 255, 0.1) !important;
}
}
}
:deep(.el-checkbox-group) {
display: flex;
gap: 16px;
.el-checkbox {
margin-right: 0;
}
}
@ -191,6 +510,20 @@ onMounted(() => {
font-size: 16px;
font-weight: 500;
color: $text-primary;
position: relative;
padding-left: 12px;
&::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
background: $primary-color;
border-radius: 2px;
}
}
}
@ -219,4 +552,29 @@ onMounted(() => {
.el-card__body {
padding: 20px;
}
:deep(.el-dialog) {
border-radius: 8px;
overflow: hidden;
.el-dialog__header {
margin: 0;
padding: 20px;
border-bottom: 1px solid $border-color;
}
.el-dialog__body {
padding: 24px;
}
.el-dialog__footer {
padding: 16px 20px;
border-top: 1px solid $border-color;
}
}
.mb-20 {
margin-bottom: 20px;
}
}
</style>

View File

@ -39,19 +39,48 @@ const initChart = () => {
const option = {
title: {
text: "物种分布统计",
textStyle: {
fontSize: 16,
fontWeight: 500,
color: "#2c3e50",
},
},
tooltip: {
trigger: "axis",
backgroundColor: "rgba(255,255,255,0.9)",
borderColor: "#eee",
textStyle: {
color: "#666",
},
},
legend: {
data: ["数量"],
textStyle: {
color: "#666",
},
},
xAxis: {
type: "category",
data: ["东方白鹳", "黑鹳", "大天鹅", "小天鹅"],
axisLine: {
lineStyle: {
color: "#ddd",
},
},
axisLabel: {
color: "#666",
},
},
yAxis: {
type: "value",
splitLine: {
lineStyle: {
color: "#eee",
},
},
axisLabel: {
color: "#666",
},
},
series: [
{
@ -59,7 +88,34 @@ const initChart = () => {
type: "bar",
data: [12, 8, 15, 10],
itemStyle: {
color: "#409EFF",
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#83bff6" },
{ offset: 0.5, color: "#188df0" },
{ offset: 1, color: "#188df0" },
],
},
},
emphasis: {
itemStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#71a5eb" },
{ offset: 0.7, color: "#1677ff" },
{ offset: 1, color: "#1677ff" },
],
},
},
},
},
],
@ -91,6 +147,61 @@ const handleExportConfirm = () => {
<template>
<div class="species-container">
<!-- 统计卡片 -->
<el-row :gutter="20" class="mb-20">
<el-col :span="6">
<div class="stat-card">
<div class="stat-icon">
<el-icon><Histogram /></el-icon>
</div>
<div class="stat-info">
<div class="label">总物种数</div>
<div class="value">128</div>
<div class="trend up">
<el-icon><ArrowUp /></el-icon>
较上月增长 8%
</div>
</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-icon warning">
<el-icon><Timer /></el-icon>
</div>
<div class="stat-info">
<div class="label">本月新增</div>
<div class="value">12</div>
<div class="trend">较上月 +3</div>
</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-icon success">
<el-icon><Location /></el-icon>
</div>
<div class="stat-info">
<div class="label">监测点位</div>
<div class="value">24</div>
<div class="trend">覆盖率 95%</div>
</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card">
<div class="stat-icon info">
<el-icon><Camera /></el-icon>
</div>
<div class="stat-info">
<div class="label">今日识别</div>
<div class="value">386</div>
<div class="trend">准确率 98%</div>
</div>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-card>
@ -160,14 +271,121 @@ const handleExportConfirm = () => {
.el-card {
background: #ffffff;
border: none;
border-radius: 4px;
border-radius: 8px;
transition: all 0.3s;
box-shadow: $box-shadow;
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08);
}
.el-card__header {
padding: 16px 20px;
border-bottom: 1px solid $border-color;
}
}
.el-table {
:deep(tbody tr) {
transition: all 0.3s;
&:hover {
background-color: rgba(64, 158, 255, 0.1) !important;
}
}
}
:deep(.el-button) {
transition: all 0.3s;
&:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
}
.mb-20 {
margin-bottom: 20px;
}
.stat-card {
background: #fff;
border-radius: 8px;
padding: 20px;
display: flex;
align-items: center;
gap: 16px;
transition: all 0.3s;
cursor: pointer;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08);
}
.stat-icon {
width: 48px;
height: 48px;
border-radius: 8px;
background: rgba(64, 158, 255, 0.1);
color: $primary-color;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
&.warning {
background: rgba(230, 162, 60, 0.1);
color: $warning-color;
}
&.success {
background: rgba(103, 194, 58, 0.1);
color: $success-color;
}
&.info {
background: rgba(144, 147, 153, 0.1);
color: $info-color;
}
}
.stat-info {
flex: 1;
.label {
color: $text-secondary;
font-size: 14px;
margin-bottom: 4px;
}
.value {
font-size: 24px;
font-weight: 600;
color: $text-primary;
line-height: 1.2;
margin-bottom: 4px;
}
.trend {
font-size: 13px;
color: $text-secondary;
display: flex;
align-items: center;
gap: 4px;
&.up {
color: $success-color;
}
.el-icon {
font-size: 12px;
}
}
}
}
}
.card-header {
@ -179,6 +397,20 @@ const handleExportConfirm = () => {
font-size: 16px;
font-weight: 500;
color: $text-primary;
position: relative;
padding-left: 12px;
&::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
background: $primary-color;
border-radius: 2px;
}
}
}

View File

@ -1,20 +1,20 @@
<script setup lang="ts">
import { ref } from 'vue';
import { ref } from "vue";
//
const systemConfig = ref({
dataCollectionInterval: 5, //
dataRetentionDays: 90, //
autoBackupEnabled: true, //
backupInterval: 24 //
backupInterval: 24, //
});
// AI
const aiConfig = ref({
modelVersion: 'v2.0.1',
modelVersion: "v2.0.1",
confidenceThreshold: 0.85,
maxDetections: 100,
enabledModels: ['bird', 'fish', 'plant']
enabledModels: ["bird", "fish", "plant"],
});
//
@ -22,20 +22,24 @@ const alertConfig = ref({
waterQuality: {
ph: { min: 6.5, max: 8.5 },
dissolvedOxygen: { min: 5, max: 9 },
temperature: { min: 15, max: 30 }
temperature: { min: 15, max: 30 },
},
airQuality: {
pm25: { max: 75 },
humidity: { min: 30, max: 70 }
}
humidity: { min: 30, max: 70 },
},
});
//
const handleSave = (type: string) => {
//
console.log(`保存${type}配置:`,
type === 'system' ? systemConfig.value :
type === 'ai' ? aiConfig.value : alertConfig.value
console.log(
`保存${type}配置:`,
type === "system"
? systemConfig.value
: type === "ai"
? aiConfig.value
: alertConfig.value
);
};
</script>
@ -53,7 +57,11 @@ const handleSave = (type: string) => {
<el-form :model="systemConfig" label-width="160px">
<el-form-item label="数据采集间隔(分钟)">
<el-input-number v-model="systemConfig.dataCollectionInterval" :min="1" :max="60" />
<el-input-number
v-model="systemConfig.dataCollectionInterval"
:min="1"
:max="60"
/>
</el-form-item>
<el-form-item label="数据保留天数">
<el-input-number v-model="systemConfig.dataRetentionDays" :min="30" :max="365" />
@ -81,7 +89,12 @@ const handleSave = (type: string) => {
<el-input v-model="aiConfig.modelVersion" disabled />
</el-form-item>
<el-form-item label="置信度阈值">
<el-slider v-model="aiConfig.confidenceThreshold" :min="0" :max="1" :step="0.01" />
<el-slider
v-model="aiConfig.confidenceThreshold"
:min="0"
:max="1"
:step="0.01"
/>
</el-form-item>
<el-form-item label="最大检测数量">
<el-input-number v-model="aiConfig.maxDetections" :min="10" :max="500" />
@ -109,21 +122,35 @@ const handleSave = (type: string) => {
<el-divider content-position="left">水质指标</el-divider>
<el-form-item label="pH值范围">
<el-col :span="11">
<el-input-number v-model="alertConfig.waterQuality.ph.min" :precision="1" :step="0.1" />
<el-input-number
v-model="alertConfig.waterQuality.ph.min"
:precision="1"
:step="0.1"
/>
</el-col>
<el-col :span="2" class="text-center">-</el-col>
<el-col :span="11">
<el-input-number v-model="alertConfig.waterQuality.ph.max" :precision="1" :step="0.1" />
<el-input-number
v-model="alertConfig.waterQuality.ph.max"
:precision="1"
:step="0.1"
/>
</el-col>
</el-form-item>
<el-form-item label="溶解氧范围(mg/L)">
<el-col :span="11">
<el-input-number v-model="alertConfig.waterQuality.dissolvedOxygen.min" :precision="1" />
<el-input-number
v-model="alertConfig.waterQuality.dissolvedOxygen.min"
:precision="1"
/>
</el-col>
<el-col :span="2" class="text-center">-</el-col>
<el-col :span="11">
<el-input-number v-model="alertConfig.waterQuality.dissolvedOxygen.max" :precision="1" />
<el-input-number
v-model="alertConfig.waterQuality.dissolvedOxygen.max"
:precision="1"
/>
</el-col>
</el-form-item>