480 lines
12 KiB
Vue
480 lines
12 KiB
Vue
<script setup lang="ts">
|
||
import { ref, onMounted, onUnmounted, computed } from "vue";
|
||
import * as echarts from "echarts";
|
||
import { ElMessageBox, ElMessage } from "element-plus";
|
||
import { Plus } from '@element-plus/icons-vue';
|
||
|
||
interface AnalysisReport {
|
||
id: number;
|
||
title: string;
|
||
type: "species" | "environment"; // 分析类型:物种/环境
|
||
timeRange: {
|
||
// 分析时间范围
|
||
start: string;
|
||
end: string;
|
||
};
|
||
dataSource: {
|
||
// 数据来源
|
||
type: string;
|
||
points: string[]; // 监测点位
|
||
}[];
|
||
analysis: {
|
||
summary: string; // 分析总结
|
||
trends: {
|
||
// 趋势分析
|
||
indicator: string; // 指标
|
||
trend: string; // 变化趋势
|
||
data: any[]; // 数据
|
||
}[];
|
||
abnormal: {
|
||
// 异常分析
|
||
type: string;
|
||
description: string;
|
||
level: string;
|
||
}[];
|
||
};
|
||
recommendations: string[]; // 建议措施
|
||
}
|
||
|
||
// 示例数据
|
||
const tableData = ref<AnalysisReport[]>([
|
||
{
|
||
id: 1,
|
||
title: "2024年第一季度水质监测分析报告",
|
||
type: "environment",
|
||
timeRange: {
|
||
start: "2024-01-01",
|
||
end: "2024-03-31",
|
||
},
|
||
dataSource: [
|
||
{
|
||
type: "水质监测",
|
||
points: ["A区-1号监测点", "A区-2号监测点", "B区-1号监测点"],
|
||
},
|
||
],
|
||
analysis: {
|
||
summary: "第一季度水质总体保持稳定,但3月份出现轻微波动",
|
||
trends: [
|
||
{
|
||
indicator: "pH值",
|
||
trend: "稳定",
|
||
data: [7.1, 7.2, 7.0, 7.3],
|
||
},
|
||
{
|
||
indicator: "溶解氧",
|
||
trend: "下降",
|
||
data: [6.5, 6.3, 6.0, 5.8],
|
||
},
|
||
],
|
||
abnormal: [
|
||
{
|
||
type: "溶解氧",
|
||
description: "3月底溶解氧水平略低于标准值",
|
||
level: "轻微",
|
||
},
|
||
],
|
||
},
|
||
recommendations: ["加强对B区-1号监测点的巡查频率", "建议增加水体曝气设施"],
|
||
},
|
||
]);
|
||
|
||
// 筛选条件
|
||
const filterForm = ref({
|
||
dateRange: [],
|
||
type: "",
|
||
indicator: "",
|
||
});
|
||
|
||
// 添加详情查看功能
|
||
const detailVisible = ref(false);
|
||
const currentReport = ref<AnalysisReport | null>(null);
|
||
|
||
const handleView = (row: AnalysisReport) => {
|
||
currentReport.value = row;
|
||
detailVisible.value = true;
|
||
};
|
||
|
||
// 添加导出功能
|
||
const handleExport = (row: AnalysisReport) => {
|
||
ElMessageBox.confirm("确认导出该分析报告?", "提示", {
|
||
confirmButtonText: "确定",
|
||
cancelButtonText: "取消",
|
||
type: "info",
|
||
})
|
||
.then(() => {
|
||
ElMessage.success("导出成功,文件已下载");
|
||
})
|
||
.catch(() => {
|
||
// 取消导出
|
||
});
|
||
};
|
||
|
||
// 添加图表resize监听
|
||
let myChart: echarts.ECharts | null = null;
|
||
|
||
const initChart = () => {
|
||
const chartDom = document.getElementById("trendChart");
|
||
if (!chartDom) return;
|
||
|
||
myChart = echarts.init(chartDom);
|
||
const option = {
|
||
title: {
|
||
text: "监测指标趋势分析",
|
||
},
|
||
tooltip: {
|
||
trigger: "axis",
|
||
},
|
||
legend: {
|
||
data: ["pH值", "溶解氧", "水温"],
|
||
},
|
||
xAxis: {
|
||
type: "category",
|
||
data: ["1月", "2月", "3月", "4月"],
|
||
},
|
||
yAxis: {
|
||
type: "value",
|
||
},
|
||
series: [
|
||
{
|
||
name: "pH值",
|
||
type: "line",
|
||
data: [7.1, 7.2, 7.0, 7.3],
|
||
},
|
||
{
|
||
name: "溶解氧",
|
||
type: "line",
|
||
data: [6.5, 6.3, 6.0, 5.8],
|
||
},
|
||
{
|
||
name: "水温",
|
||
type: "line",
|
||
data: [15, 16, 18, 21],
|
||
},
|
||
],
|
||
};
|
||
|
||
myChart.setOption(option);
|
||
};
|
||
|
||
onMounted(() => {
|
||
initChart();
|
||
window.addEventListener("resize", handleResize);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
window.removeEventListener("resize", handleResize);
|
||
myChart?.dispose();
|
||
});
|
||
|
||
const handleResize = () => {
|
||
myChart?.resize();
|
||
};
|
||
|
||
// 添加分页功能
|
||
const currentPage = ref(1);
|
||
const pageSize = ref(10);
|
||
|
||
const paginatedData = computed(() => {
|
||
const start = (currentPage.value - 1) * pageSize.value;
|
||
const end = start + pageSize.value;
|
||
return tableData.value.slice(start, end);
|
||
});
|
||
|
||
const handleSizeChange = (val: number) => {
|
||
pageSize.value = val;
|
||
currentPage.value = 1;
|
||
};
|
||
|
||
const handleCurrentChange = (val: number) => {
|
||
currentPage.value = val;
|
||
};
|
||
|
||
// 新建报告
|
||
const dialogVisible = ref(false);
|
||
const formData = ref({
|
||
title: "",
|
||
type: "",
|
||
timeRange: [],
|
||
summary: "",
|
||
recommendations: "",
|
||
});
|
||
|
||
const handleCreate = () => {
|
||
dialogVisible.value = true;
|
||
};
|
||
|
||
const handleSubmit = () => {
|
||
// TODO: 提交表单
|
||
dialogVisible.value = false;
|
||
};
|
||
|
||
// 刷新数据
|
||
const handleRefresh = () => {
|
||
ElMessage.success('数据已更新');
|
||
// TODO: 实际刷新数据的逻辑
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<div class="analysis-report">
|
||
<!-- 趋势图表 -->
|
||
<el-card>
|
||
<div id="trendChart" style="height: 400px"></div>
|
||
</el-card>
|
||
|
||
<!-- 报告列表 -->
|
||
<el-card class="mt-20">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span>分析报告</span>
|
||
<el-button type="primary" :icon="Plus" @click="handleCreate">新建报告</el-button>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 数据统计卡片 -->
|
||
<el-row :gutter="20" class="mb-20">
|
||
<el-col :span="8">
|
||
<el-card shadow="hover" class="stat-card">
|
||
<div class="stat-value">128</div>
|
||
<div class="stat-label">报告总数</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-card shadow="hover" class="stat-card">
|
||
<div class="stat-value">45</div>
|
||
<div class="stat-label">本月新增</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-card shadow="hover" class="stat-card">
|
||
<div class="stat-value">24</div>
|
||
<div class="stat-label">待处理</div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 报告列表 -->
|
||
<el-table :data="tableData" style="width: 100%">
|
||
<el-table-column prop="title" label="报告标题" min-width="200" />
|
||
<el-table-column prop="type" label="类型" width="120">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.type === 'species' ? 'success' : 'primary'">
|
||
{{ row.type === 'species' ? '物种分析' : '环境分析' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button type="primary" link @click="handleView(row)">查看</el-button>
|
||
<el-button type="warning" link @click="handleExport(row)">导出</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页器 -->
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
v-model:current-page="currentPage"
|
||
v-model:page-size="pageSize"
|
||
:page-sizes="[10, 20, 50]"
|
||
layout="total, sizes, prev, pager, next"
|
||
:total="tableData.length"
|
||
/>
|
||
</div>
|
||
</el-card>
|
||
|
||
<!-- 新建报告弹窗 -->
|
||
<el-dialog v-model="dialogVisible" title="新建分析报告" width="800px">
|
||
<el-form :model="formData" label-width="100px">
|
||
<el-form-item label="报告标题" required>
|
||
<el-input v-model="formData.title" placeholder="请输入报告标题" />
|
||
</el-form-item>
|
||
<el-form-item label="分析类型" required>
|
||
<el-radio-group v-model="formData.type">
|
||
<el-radio label="species">物种分析</el-radio>
|
||
<el-radio label="environment">环境分析</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="分析周期" required>
|
||
<el-date-picker
|
||
v-model="formData.timeRange"
|
||
type="daterange"
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="分析总结" required>
|
||
<el-input
|
||
v-model="formData.summary"
|
||
type="textarea"
|
||
rows="4"
|
||
placeholder="请输入分析总结"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="建议措施" required>
|
||
<el-input
|
||
v-model="formData.recommendations"
|
||
type="textarea"
|
||
rows="4"
|
||
placeholder="请输入建议措施"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSubmit">提交</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 添加详情弹窗 -->
|
||
<el-dialog v-model="detailVisible" title="分析报告详情" width="900px">
|
||
<template v-if="currentReport">
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="报告标题" :span="2">
|
||
{{ currentReport.title }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="分析类型">
|
||
{{ currentReport.type === "species" ? "物种分析" : "环境分析" }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="时间范围">
|
||
{{ currentReport.timeRange.start }} 至 {{ currentReport.timeRange.end }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="监测点位" :span="2">
|
||
<el-tag
|
||
v-for="point in currentReport.dataSource[0].points"
|
||
:key="point"
|
||
style="margin-right: 8px"
|
||
>
|
||
{{ point }}
|
||
</el-tag>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="分析总结" :span="2">
|
||
{{ currentReport.analysis.summary }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="趋势分析" :span="2">
|
||
<div v-for="trend in currentReport.analysis.trends" :key="trend.indicator">
|
||
<div class="trend-item">
|
||
<span class="indicator">{{ trend.indicator }}:</span>
|
||
<el-tag :type="trend.trend === '下降' ? 'danger' : 'success'">
|
||
{{ trend.trend }}
|
||
</el-tag>
|
||
</div>
|
||
</div>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="异常情况" :span="2">
|
||
<div v-for="item in currentReport.analysis.abnormal" :key="item.type">
|
||
<div class="abnormal-item">
|
||
<span class="type">{{ item.type }}:</span>
|
||
<span>{{ item.description }}</span>
|
||
<el-tag
|
||
:type="item.level === '严重' ? 'danger' : 'warning'"
|
||
size="small"
|
||
style="margin-left: 8px"
|
||
>
|
||
{{ item.level }}
|
||
</el-tag>
|
||
</div>
|
||
</div>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="建议措施" :span="2">
|
||
<ul class="recommendations-list">
|
||
<li v-for="(item, index) in currentReport.recommendations" :key="index">
|
||
{{ item }}
|
||
</li>
|
||
</ul>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</template>
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="detailVisible = false">关闭</el-button>
|
||
<el-button
|
||
type="warning"
|
||
@click="handleExport(currentReport!)"
|
||
:disabled="!currentReport"
|
||
>
|
||
导出
|
||
</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="scss" scoped>
|
||
@import "../../../styles/variables.scss";
|
||
|
||
.analysis-report {
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.mt-20 {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.pagination-container {
|
||
margin-top: 20px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.trend-item {
|
||
margin-bottom: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.indicator {
|
||
margin-right: 8px;
|
||
color: $text-regular;
|
||
}
|
||
}
|
||
|
||
.abnormal-item {
|
||
margin-bottom: 8px;
|
||
|
||
.type {
|
||
color: $text-regular;
|
||
}
|
||
}
|
||
|
||
.recommendations-list {
|
||
margin: 0;
|
||
padding-left: 20px;
|
||
|
||
li {
|
||
margin-bottom: 4px;
|
||
color: $text-regular;
|
||
}
|
||
}
|
||
|
||
.stat-card {
|
||
padding: 20px;
|
||
text-align: center;
|
||
transition: all 0.3s;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 28px;
|
||
font-weight: 600;
|
||
color: $primary-color;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 14px;
|
||
color: $text-secondary;
|
||
}
|
||
}
|
||
}
|
||
</style>
|