|
|
@@ -1,128 +1,274 @@
|
|
|
<template>
|
|
|
- <div class="fertilizer-input-form">
|
|
|
- <!-- 输入表单部分 -->
|
|
|
- <el-card v-if="showInputForm" shadow="always" class="form-card">
|
|
|
- <div class="card-content">
|
|
|
- <div class="input-section">
|
|
|
- <el-form label-width="250px" label-position="top">
|
|
|
- <div class="form-section">
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="氮肥镉含量平均值 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f3_nitrogen_cd_content" placeholder="0.12"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="氮肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.nf_nitrogen_usage" placeholder="0.25"></el-input>
|
|
|
- </el-form-item>
|
|
|
+ <div class="agricultural-input-management">
|
|
|
+ <!-- 计算页面 -->
|
|
|
+ <div v-if="showInputForm" class="page-container">
|
|
|
+ <el-card class="gradient-card">
|
|
|
+ <div class="calculation-content">
|
|
|
+ <h2 class="page-title">农业投入品输入通量计算</h2>
|
|
|
+ <div class="scrollable-content">
|
|
|
+ <el-form label-position="left">
|
|
|
+ <div class="input-section">
|
|
|
+ <!-- 第一行:氮肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">氮肥镉含量平均值 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f3_nitrogen_cd_content"
|
|
|
+ placeholder="0.12"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">氮肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.nf_nitrogen_usage"
|
|
|
+ placeholder="0.25"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第二行:磷肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">磷肥镉含量平均值 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f4_phosphorus_cd_content"
|
|
|
+ placeholder="0.85"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">磷肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.pf_phosphorus_usage"
|
|
|
+ placeholder="0.15"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第三行:钾肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">钾肥镉含量平均值 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f5_potassium_cd_content"
|
|
|
+ placeholder="0.05"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">钾肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.kf_potassium_usage"
|
|
|
+ placeholder="0.12"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第四行:复合肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">复合肥镉含量平均值 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f6_compound_cd_content"
|
|
|
+ placeholder="0.45"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">复合肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.cf_compound_usage"
|
|
|
+ placeholder="0.30"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第五行:有机肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">有机肥镉含量平均值 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f7_organic_cd_content"
|
|
|
+ placeholder="0.22"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">有机肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.of_organic_usage"
|
|
|
+ placeholder="2.50"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第六行:农药的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农药镉含量 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f8_pesticide_cd_content"
|
|
|
+ placeholder="0.08"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农药单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.p_pesticide_usage"
|
|
|
+ placeholder="0.02"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第七行:农家肥的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农家肥镉含量 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f9_farmyard_cd_content"
|
|
|
+ placeholder="0.15"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农家肥单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.ff_farmyard_usage"
|
|
|
+ placeholder="1.80"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 第八行:农膜的两个输入栏 -->
|
|
|
+ <div class="input-row">
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农膜镉含量 (mg/kg)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.f10_film_cd_content"
|
|
|
+ placeholder="0.03"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="input-item">
|
|
|
+ <div class="input-title">农膜单位面积使用量 (t/ha/a)</div>
|
|
|
+ <el-input
|
|
|
+ v-model="formData.af_film_usage"
|
|
|
+ placeholder="0.05"
|
|
|
+ size="large"
|
|
|
+ class="fixed-width-input"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="磷肥镉含量平均值 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f4_phosphorus_cd_content" placeholder="0.85"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="磷肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.pf_phosphorus_usage" placeholder="0.15"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="钾肥镉含量平均值 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f5_potassium_cd_content" placeholder="0.05"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="钾肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.kf_potassium_usage" placeholder="0.12"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="复合肥镉含量平均值 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f6_compound_cd_content" placeholder="0.45"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="复合肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.cf_compound_usage" placeholder="0.30"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="有机肥镉含量平均值 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f7_organic_cd_content" placeholder="0.22"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="有机肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.of_organic_usage" placeholder="2.50"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="农药镉含量 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f8_pesticide_cd_content" placeholder="0.08"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="农药单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.p_pesticide_usage" placeholder="0.02"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="农家肥镉含量 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f9_farmyard_cd_content" placeholder="0.15"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="农家肥单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.ff_farmyard_usage" placeholder="1.80"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- <div class="input-group">
|
|
|
- <el-form-item label="农膜镉含量 (mg/kg)" class="form-item">
|
|
|
- <el-input v-model="formData.f10_film_cd_content" placeholder="0.03"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="农膜(存留)单位面积使用量 (t/ha/a)" class="form-item">
|
|
|
- <el-input v-model="formData.af_film_usage" placeholder="0.05"></el-input>
|
|
|
- </el-form-item>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="button-section">
|
|
|
- <div class="button-bg"></div>
|
|
|
- <div class="bottom-overlay"></div>
|
|
|
- <el-button
|
|
|
- class="calculate-btn"
|
|
|
- @click="calculateAndVisualize"
|
|
|
- :loading="loading"
|
|
|
- >
|
|
|
- <span class="btn-text">计算并生成可视化</span>
|
|
|
- </el-button>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="button-container">
|
|
|
+ <el-button
|
|
|
+ class="calculate-btn"
|
|
|
+ @click="calculateAndVisualize"
|
|
|
+ :loading="loading"
|
|
|
+ size="large"
|
|
|
+ >
|
|
|
+ 计算农业投入品输入通量
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 结果页面 -->
|
|
|
+ <div v-if="!showInputForm" class="page-container">
|
|
|
+ <div class="toolbar">
|
|
|
+ <el-button class="custom-button back-button" @click="showInputForm = true">
|
|
|
+ 返回计算
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <!-- 结果页面部分 -->
|
|
|
- <div v-if="!showInputForm" class="results-page">
|
|
|
- <!-- 返回按钮 -->
|
|
|
- <el-button
|
|
|
- type="primary"
|
|
|
- class="back-button"
|
|
|
- @click="showInputForm = true"
|
|
|
- >
|
|
|
- 返回计算
|
|
|
- </el-button>
|
|
|
- <!-- 结果页面标题 -->
|
|
|
- <h2 class="results-title">农业投入Cd通量计算结果</h2>
|
|
|
|
|
|
- <!-- 自定义数据计算结果卡片 -->
|
|
|
- <el-card class="result-card" v-if="customResult.success">
|
|
|
- <h3>农业投入Cd通量计算结果</h3>
|
|
|
- <p>总通量: {{ customResult.data.total_cd_flux }} g/ha/a</p>
|
|
|
- <el-table :data="customResultDetails" border>
|
|
|
- <el-table-column prop="type" label="投入类型"></el-table-column>
|
|
|
- <el-table-column prop="flux" label="Cd通量(g/ha/a)"></el-table-column>
|
|
|
- </el-table>
|
|
|
- <div class="chart-container">
|
|
|
- <div ref="customPieChart" style="width: 100%; height: 400px;"></div>
|
|
|
+ <el-card class="results-card">
|
|
|
+ <div class="results-content">
|
|
|
+ <!-- 地图区域 -->
|
|
|
+ <div class="map-section">
|
|
|
+ <h3>农业投入品Cd通量分布图</h3>
|
|
|
+ <div v-if="loadingMap" class="loading-container">
|
|
|
+ <el-icon class="loading-icon"><Loading /></el-icon>
|
|
|
+ <span>地图加载中...</span>
|
|
|
+ </div>
|
|
|
+ <div class="image-container">
|
|
|
+ <img v-if="mapImageUrl" :src=mapImageUrl class="result-image"></img>
|
|
|
+ <div v-if="!mapImageUrl && !loadingMap" class="no-data">
|
|
|
+ <el-icon><Picture /></el-icon>
|
|
|
+ <p>暂无地图数据</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 添加地图展示区域 -->
|
|
|
- <div class="map-container">
|
|
|
- <h3>空间分布图</h3>
|
|
|
- <div class="map-wrapper">
|
|
|
- <div v-if="mapImageUrl" class="map-image-container">
|
|
|
- <img :src=mapImageUrl alt="农业投入品输入通量分布图" class="map-image">
|
|
|
+ <!-- 统计图表区域 -->
|
|
|
+ <div class="stats-area">
|
|
|
+ <h3>农业投入品Cd通量统计信息</h3>
|
|
|
+ <div class="model-info">
|
|
|
+ <el-tag type="info">农业投入品Cd通量模型</el-tag>
|
|
|
+ <span class="update-time">
|
|
|
+ 最后更新: {{ updateTime ? new Date(updateTime).toLocaleString() : '未知' }}
|
|
|
+ </span>
|
|
|
</div>
|
|
|
- <div v-else class="map-placeholder">
|
|
|
- <p>地图生成中...</p>
|
|
|
- <el-progress :percentage="mapProgress" :status="mapStatus"></el-progress>
|
|
|
+
|
|
|
+ <div v-if="loadingStats" class="loading-container">
|
|
|
+ <el-icon class="loading-icon"><Loading /></el-icon>
|
|
|
+ <span>统计数据加载中...</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="!loadingStats && customResult.data" class="stats-container">
|
|
|
+ <div class="total-flux">
|
|
|
+ 总通量: {{ customResult.data.total_cd_flux }} g/ha/a
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ :data="customResultDetails"
|
|
|
+ style="width: 100%; margin-bottom: 15px;"
|
|
|
+ border
|
|
|
+ stripe
|
|
|
+ >
|
|
|
+ <el-table-column prop="type" label="投入类型" align="center" min-width="120" />
|
|
|
+ <el-table-column prop="flux" label="Cd通量(g/ha/a)" align="center" :formatter="formatNumber" min-width="120" />
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="!loadingStats && !customResult.data" class="no-data">
|
|
|
+ <el-icon><DataAnalysis /></el-icon>
|
|
|
+ <p>暂无统计数据</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 饼图区域 -->
|
|
|
+ <div class="chart-section">
|
|
|
+ <h3>农业投入品Cd通量占比</h3>
|
|
|
+ <div class="image-container">
|
|
|
+ <div ref="pieChart" style="width: 100%; height: 350px;"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -132,96 +278,131 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import axios from 'axios';
|
|
|
+import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
|
|
+import {
|
|
|
+ ElInput,
|
|
|
+ ElButton,
|
|
|
+ ElMessage,
|
|
|
+ ElCard,
|
|
|
+ ElTable,
|
|
|
+ ElTableColumn,
|
|
|
+ ElTag,
|
|
|
+ ElIcon,
|
|
|
+ ElForm
|
|
|
+} from 'element-plus';
|
|
|
+import {
|
|
|
+ Loading,
|
|
|
+ Picture,
|
|
|
+ DataAnalysis
|
|
|
+} from '@element-plus/icons-vue';
|
|
|
import * as echarts from 'echarts';
|
|
|
-import { ElNotification } from 'element-plus';
|
|
|
+import { api8000 } from '@/utils/request';
|
|
|
|
|
|
export default {
|
|
|
- data() {
|
|
|
- return {
|
|
|
- showInputForm: true,
|
|
|
- formData: {
|
|
|
- f3_nitrogen_cd_content: "0.12",
|
|
|
- f4_phosphorus_cd_content: "0.85",
|
|
|
- f5_potassium_cd_content: "0.05",
|
|
|
- f6_compound_cd_content: "0.45",
|
|
|
- f7_organic_cd_content: "0.22",
|
|
|
- f8_pesticide_cd_content: "0.08",
|
|
|
- f9_farmyard_cd_content: "0.15",
|
|
|
- f10_film_cd_content: "0.03",
|
|
|
- nf_nitrogen_usage: "0.25",
|
|
|
- pf_phosphorus_usage: "0.15",
|
|
|
- kf_potassium_usage: "0.12",
|
|
|
- cf_compound_usage: "0.30",
|
|
|
- of_organic_usage: "2.50",
|
|
|
- p_pesticide_usage: "0.02",
|
|
|
- ff_farmyard_usage: "1.80",
|
|
|
- af_film_usage: "0.05",
|
|
|
- description: "自定义数据计算结果"
|
|
|
- },
|
|
|
- loading: false,
|
|
|
- customResult: {},
|
|
|
- customPieChart: null,
|
|
|
- mapImageUrl: null,
|
|
|
- mapProgress: 0,
|
|
|
- mapStatus: 'success',
|
|
|
- mapInterval: null
|
|
|
- };
|
|
|
+ components: {
|
|
|
+ ElInput,
|
|
|
+ ElButton,
|
|
|
+ ElCard,
|
|
|
+ ElTable,
|
|
|
+ ElTableColumn,
|
|
|
+ ElTag,
|
|
|
+ ElIcon,
|
|
|
+ ElForm,
|
|
|
+ Loading,
|
|
|
+ Picture,
|
|
|
+ DataAnalysis
|
|
|
},
|
|
|
- computed: {
|
|
|
- customResultDetails() {
|
|
|
- if (!this.customResult.data || !this.customResult.data.details) return [];
|
|
|
- return Object.entries(this.customResult.data.details).map(([type, flux]) => ({
|
|
|
- type: this.getTypeName(type),
|
|
|
- flux: flux
|
|
|
- }));
|
|
|
- },
|
|
|
- customPieData() {
|
|
|
- if (!this.customResult.data || !this.customResult.data.details) return [];
|
|
|
- return Object.entries(this.customResult.data.details).map(([type, value]) => ({
|
|
|
- name: this.getTypeName(type),
|
|
|
- value: value
|
|
|
- }));
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
- async calculateAndVisualize() {
|
|
|
+ setup() {
|
|
|
+ // 计算页面数据
|
|
|
+ const showInputForm = ref(true);
|
|
|
+ const formData = ref({
|
|
|
+ f3_nitrogen_cd_content: "0.12",
|
|
|
+ f4_phosphorus_cd_content: "0.85",
|
|
|
+ f5_potassium_cd_content: "0.05",
|
|
|
+ f6_compound_cd_content: "0.45",
|
|
|
+ f7_organic_cd_content: "0.22",
|
|
|
+ f8_pesticide_cd_content: "0.08",
|
|
|
+ f9_farmyard_cd_content: "0.15",
|
|
|
+ f10_film_cd_content: "0.03",
|
|
|
+ nf_nitrogen_usage: "0.25",
|
|
|
+ pf_phosphorus_usage: "0.15",
|
|
|
+ kf_potassium_usage: "0.12",
|
|
|
+ cf_compound_usage: "0.30",
|
|
|
+ of_organic_usage: "2.50",
|
|
|
+ p_pesticide_usage: "0.02",
|
|
|
+ ff_farmyard_usage: "1.80",
|
|
|
+ af_film_usage: "0.05"
|
|
|
+ });
|
|
|
+ const loading = ref(false);
|
|
|
+
|
|
|
+ // 结果页面数据
|
|
|
+ const mapImageUrl = ref('');
|
|
|
+ const customResult = ref({});
|
|
|
+ const updateTime = ref(new Date().toISOString());
|
|
|
+ const loadingMap = ref(false);
|
|
|
+ const loadingStats = ref(false);
|
|
|
+ const pieChart = ref(null);
|
|
|
+
|
|
|
+ // 格式化数字显示(保留4位小数)
|
|
|
+ const formatNumber = (row, column, cellValue) => {
|
|
|
+ if (typeof cellValue === 'number') {
|
|
|
+ return cellValue.toFixed(4);
|
|
|
+ }
|
|
|
+ return cellValue;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取类型名称
|
|
|
+ const getTypeName = (type) => {
|
|
|
+ const typeNames = {
|
|
|
+ 'nitrogen_fertilizer': '氮肥',
|
|
|
+ 'phosphorus_fertilizer': '磷肥',
|
|
|
+ 'potassium_fertilizer': '钾肥',
|
|
|
+ 'compound_fertilizer': '复合肥',
|
|
|
+ 'organic_fertilizer': '有机肥',
|
|
|
+ 'pesticide': '农药',
|
|
|
+ 'farmyard_manure': '农家肥',
|
|
|
+ 'agricultural_film': '农膜'
|
|
|
+ };
|
|
|
+ return typeNames[type] || type;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 计算详情数据
|
|
|
+ const customResultDetails = ref([]);
|
|
|
+
|
|
|
+ // 计算并可视化
|
|
|
+ const calculateAndVisualize = async () => {
|
|
|
try {
|
|
|
- this.loading = true;
|
|
|
- this.mapImageUrl = null;
|
|
|
- this.mapProgress = 0;
|
|
|
- this.mapStatus = 'success';
|
|
|
+ loading.value = true;
|
|
|
+ loadingMap.value = true;
|
|
|
+ loadingStats.value = true;
|
|
|
+ mapImageUrl.value = '';
|
|
|
|
|
|
// 准备请求数据
|
|
|
const requestBody = {
|
|
|
- ...this.formData,
|
|
|
+ ...formData.value,
|
|
|
// 将字符串值转换为数字
|
|
|
- f3_nitrogen_cd_content: parseFloat(this.formData.f3_nitrogen_cd_content),
|
|
|
- f4_phosphorus_cd_content: parseFloat(this.formData.f4_phosphorus_cd_content),
|
|
|
- f5_potassium_cd_content: parseFloat(this.formData.f5_potassium_cd_content),
|
|
|
- f6_compound_cd_content: parseFloat(this.formData.f6_compound_cd_content),
|
|
|
- f7_organic_cd_content: parseFloat(this.formData.f7_organic_cd_content),
|
|
|
- f8_pesticide_cd_content: parseFloat(this.formData.f8_pesticide_cd_content),
|
|
|
- f9_farmyard_cd_content: parseFloat(this.formData.f9_farmyard_cd_content),
|
|
|
- f10_film_cd_content: parseFloat(this.formData.f10_film_cd_content),
|
|
|
- nf_nitrogen_usage: parseFloat(this.formData.nf_nitrogen_usage),
|
|
|
- pf_phosphorus_usage: parseFloat(this.formData.pf_phosphorus_usage),
|
|
|
- kf_potassium_usage: parseFloat(this.formData.kf_potassium_usage),
|
|
|
- cf_compound_usage: parseFloat(this.formData.cf_compound_usage),
|
|
|
- of_organic_usage: parseFloat(this.formData.of_organic_usage),
|
|
|
- p_pesticide_usage: parseFloat(this.formData.p_pesticide_usage),
|
|
|
- ff_farmyard_usage: parseFloat(this.formData.ff_farmyard_usage),
|
|
|
- af_film_usage: parseFloat(this.formData.af_film_usage),
|
|
|
- description: this.formData.description
|
|
|
+ f3_nitrogen_cd_content: parseFloat(formData.value.f3_nitrogen_cd_content),
|
|
|
+ f4_phosphorus_cd_content: parseFloat(formData.value.f4_phosphorus_cd_content),
|
|
|
+ f5_potassium_cd_content: parseFloat(formData.value.f5_potassium_cd_content),
|
|
|
+ f6_compound_cd_content: parseFloat(formData.value.f6_compound_cd_content),
|
|
|
+ f7_organic_cd_content: parseFloat(formData.value.f7_organic_cd_content),
|
|
|
+ f8_pesticide_cd_content: parseFloat(formData.value.f8_pesticide_cd_content),
|
|
|
+ f9_farmyard_cd_content: parseFloat(formData.value.f9_farmyard_cd_content),
|
|
|
+ f10_film_cd_content: parseFloat(formData.value.f10_film_cd_content),
|
|
|
+ nf_nitrogen_usage: parseFloat(formData.value.nf_nitrogen_usage),
|
|
|
+ pf_phosphorus_usage: parseFloat(formData.value.pf_phosphorus_usage),
|
|
|
+ kf_potassium_usage: parseFloat(formData.value.kf_potassium_usage),
|
|
|
+ cf_compound_usage: parseFloat(formData.value.cf_compound_usage),
|
|
|
+ of_organic_usage: parseFloat(formData.value.of_organic_usage),
|
|
|
+ p_pesticide_usage: parseFloat(formData.value.p_pesticide_usage),
|
|
|
+ ff_farmyard_usage: parseFloat(formData.value.ff_farmyard_usage),
|
|
|
+ af_film_usage: parseFloat(formData.value.af_film_usage)
|
|
|
};
|
|
|
|
|
|
- // 启动进度条模拟
|
|
|
- this.startProgressSimulation();
|
|
|
-
|
|
|
- // 调用计算并可视化接口(返回FileResponse)
|
|
|
+ // 调用计算并可视化接口
|
|
|
const [mapResponse, calcResponse] = await Promise.all([
|
|
|
- axios.post(
|
|
|
- 'http://localhost:8000/api/agricultural-input/calculate-and-visualize-file',
|
|
|
+ api8000.post(
|
|
|
+ '/api/agricultural-input/calculate-and-visualize-file',
|
|
|
requestBody,
|
|
|
{
|
|
|
params: {
|
|
|
@@ -232,443 +413,491 @@ export default {
|
|
|
enable_interpolation: false,
|
|
|
cleanup_intermediate: true
|
|
|
},
|
|
|
- responseType: 'blob' // 重要:指定响应类型为blob
|
|
|
+ responseType: 'blob'
|
|
|
}
|
|
|
),
|
|
|
- // 同时调用计算接口获取结果数据
|
|
|
- axios.post(
|
|
|
- 'http://localhost:8000/api/agricultural-input/calculate-with-custom-data',
|
|
|
+ api8000.post(
|
|
|
+ '/api/agricultural-input/calculate-with-custom-data',
|
|
|
requestBody
|
|
|
)
|
|
|
]);
|
|
|
-
|
|
|
+
|
|
|
// 处理地图响应
|
|
|
const blob = new Blob([mapResponse.data], { type: 'image/jpeg' });
|
|
|
- this.mapImageUrl = URL.createObjectURL(blob);
|
|
|
-
|
|
|
+ mapImageUrl.value = URL.createObjectURL(blob);
|
|
|
+
|
|
|
// 处理计算结果
|
|
|
if (calcResponse.data.success) {
|
|
|
- this.customResult = {
|
|
|
+ customResult.value = {
|
|
|
success: true,
|
|
|
data: calcResponse.data.data
|
|
|
};
|
|
|
-
|
|
|
- // 显示结果页面
|
|
|
- this.showInputForm = false;
|
|
|
-
|
|
|
+
|
|
|
+ // 更新详情数据
|
|
|
+ customResultDetails.value = Object.entries(customResult.value.data.details).map(([type, flux]) => ({
|
|
|
+ type: getTypeName(type),
|
|
|
+ flux: flux
|
|
|
+ }));
|
|
|
+
|
|
|
+ showInputForm.value = false;
|
|
|
+ updateTime.value = new Date().toISOString();
|
|
|
+
|
|
|
// 初始化图表
|
|
|
- this.$nextTick(() => {
|
|
|
- this.initCharts();
|
|
|
- });
|
|
|
+ initPieChart();
|
|
|
+
|
|
|
+ ElMessage.success('计算完成,结果已展示');
|
|
|
} else {
|
|
|
throw new Error(calcResponse.data.message);
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('API调用错误:', error);
|
|
|
- this.mapStatus = 'exception';
|
|
|
- ElNotification.error({
|
|
|
- title: '计算失败',
|
|
|
- message: error.message || '请检查网络连接',
|
|
|
- duration: 5000
|
|
|
- });
|
|
|
+ ElMessage.error('计算失败: ' + (error.message || '请检查网络连接'));
|
|
|
} finally {
|
|
|
- this.stopProgressSimulation();
|
|
|
- this.loading = false;
|
|
|
+ loading.value = false;
|
|
|
+ loadingMap.value = false;
|
|
|
+ loadingStats.value = false;
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- getTypeName(type) {
|
|
|
- const typeNames = {
|
|
|
- 'nitrogen_fertilizer': '氮肥',
|
|
|
- 'phosphorus_fertilizer': '磷肥',
|
|
|
- 'potassium_fertilizer': '钾肥',
|
|
|
- 'compound_fertilizer': '复合肥',
|
|
|
- 'organic_fertilizer': '有机肥',
|
|
|
- 'pesticide': '农药',
|
|
|
- 'farmyard_manure': '农家肥',
|
|
|
- 'agricultural_film': '农膜'
|
|
|
- };
|
|
|
- return typeNames[type] || type;
|
|
|
- },
|
|
|
-
|
|
|
- initCharts() {
|
|
|
- if (this.customPieChart) {
|
|
|
- this.customPieChart.dispose();
|
|
|
- }
|
|
|
-
|
|
|
- this.customPieChart = echarts.init(this.$refs.customPieChart);
|
|
|
- this.customPieChart.setOption(this.getPieChartOption('各项投入通量占比', this.customPieData));
|
|
|
+ };
|
|
|
+
|
|
|
+ // 初始化饼图
|
|
|
+ const initPieChart = () => {
|
|
|
+ if (!customResult.value.data || !customResult.value.data.details) return;
|
|
|
|
|
|
- window.addEventListener('resize', this.onResize);
|
|
|
- },
|
|
|
-
|
|
|
- getPieChartOption(title, data) {
|
|
|
- return {
|
|
|
- title: {
|
|
|
- text: title,
|
|
|
- left: 'center',
|
|
|
- textStyle: {
|
|
|
- fontSize: 16,
|
|
|
- fontWeight: 'bold'
|
|
|
- }
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- trigger: 'item',
|
|
|
- formatter: '{a} <br/>{b}: {c} g/ha/a ({d}%)'
|
|
|
- },
|
|
|
- legend: {
|
|
|
- orient: 'vertical',
|
|
|
- right: 10,
|
|
|
- top: 'center',
|
|
|
- data: data.map(item => item.name)
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: title,
|
|
|
- type: 'pie',
|
|
|
- radius: ['40%', '70%'],
|
|
|
- center: ['40%', '50%'],
|
|
|
- avoidLabelOverlap: false,
|
|
|
- itemStyle: {
|
|
|
- borderRadius: 10,
|
|
|
- borderColor: '#fff',
|
|
|
- borderWidth: 2
|
|
|
- },
|
|
|
- label: {
|
|
|
- show: false,
|
|
|
- position: 'center'
|
|
|
- },
|
|
|
- emphasis: {
|
|
|
+ nextTick(() => {
|
|
|
+ const chartContainer = document.querySelector('.chart-section .image-container');
|
|
|
+ if (!chartContainer) {
|
|
|
+ console.error('图表容器未找到');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理图表数据
|
|
|
+ const chartData = Object.entries(customResult.value.data.details)
|
|
|
+ .filter(([_, value]) => value > 0)
|
|
|
+ .map(([type, value]) => ({
|
|
|
+ name: getTypeName(type),
|
|
|
+ value: parseFloat(value.toFixed(4))
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 销毁旧图表实例
|
|
|
+ if (pieChart.value) {
|
|
|
+ pieChart.value.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化新图表
|
|
|
+ pieChart.value = echarts.init(chartContainer);
|
|
|
+
|
|
|
+ // 设置图表选项
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ formatter: '{a} <br/>{b}: {c} g/ha/a ({d}%)'
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ orient: 'vertical',
|
|
|
+ right: 10,
|
|
|
+ top: 'center',
|
|
|
+ data: chartData.map(item => item.name)
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '农业投入品Cd通量占比',
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['40%', '70%'],
|
|
|
+ center: ['40%', '50%'],
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 10,
|
|
|
+ borderColor: '#fff',
|
|
|
+ borderWidth: 2
|
|
|
+ },
|
|
|
label: {
|
|
|
- show: true,
|
|
|
- fontSize: '16',
|
|
|
- fontWeight: 'bold',
|
|
|
- formatter: '{b}\n{c} g/ha/a\n{d}%'
|
|
|
- }
|
|
|
- },
|
|
|
- labelLine: {
|
|
|
- show: false
|
|
|
- },
|
|
|
- data: data
|
|
|
- }
|
|
|
- ]
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- onResize() {
|
|
|
- if (this.customPieChart) {
|
|
|
- this.customPieChart.resize();
|
|
|
+ show: false,
|
|
|
+ position: 'center'
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ fontSize: '16',
|
|
|
+ fontWeight: 'bold',
|
|
|
+ formatter: '{b}\n{c} g/ha/a\n({d}%)'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ labelLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ data: chartData
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ responsive: true,
|
|
|
+ animation: true,
|
|
|
+ animationDuration: 1000,
|
|
|
+ animationEasing: 'cubicOut'
|
|
|
+ };
|
|
|
+
|
|
|
+ // 设置图表选项
|
|
|
+ pieChart.value.setOption(option);
|
|
|
+
|
|
|
+ // 添加窗口大小变化监听
|
|
|
+ window.addEventListener('resize', function() {
|
|
|
+ pieChart.value.resize();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // 响应式调整
|
|
|
+ const handleResize = () => {
|
|
|
+ if (pieChart.value) {
|
|
|
+ pieChart.value.resize();
|
|
|
}
|
|
|
- },
|
|
|
-
|
|
|
- startProgressSimulation() {
|
|
|
- this.mapInterval = setInterval(() => {
|
|
|
- if (this.mapProgress < 90) {
|
|
|
- this.mapProgress += 10;
|
|
|
- } else if (this.mapProgress < 99) {
|
|
|
- this.mapProgress += 1;
|
|
|
- }
|
|
|
- }, 500);
|
|
|
- },
|
|
|
-
|
|
|
- stopProgressSimulation() {
|
|
|
- if (this.mapInterval) {
|
|
|
- clearInterval(this.mapInterval);
|
|
|
- this.mapInterval = null;
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ window.addEventListener('resize', handleResize);
|
|
|
+ });
|
|
|
+
|
|
|
+ onBeforeUnmount(() => {
|
|
|
+ window.removeEventListener('resize', handleResize);
|
|
|
+ if (pieChart.value) {
|
|
|
+ pieChart.value.dispose();
|
|
|
}
|
|
|
- this.mapProgress = 100;
|
|
|
- }
|
|
|
- },
|
|
|
- beforeUnmount() {
|
|
|
- window.removeEventListener('resize', this.onResize);
|
|
|
- if (this.customPieChart) {
|
|
|
- this.customPieChart.dispose();
|
|
|
- }
|
|
|
- if (this.mapInterval) {
|
|
|
- clearInterval(this.mapInterval);
|
|
|
- }
|
|
|
- // 释放Blob URL内存
|
|
|
- if (this.mapImageUrl) {
|
|
|
- URL.revokeObjectURL(this.mapImageUrl);
|
|
|
- }
|
|
|
+ if (mapImageUrl.value) {
|
|
|
+ URL.revokeObjectURL(mapImageUrl.value);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ showInputForm,
|
|
|
+ formData,
|
|
|
+ loading,
|
|
|
+ mapImageUrl,
|
|
|
+ customResult,
|
|
|
+ updateTime,
|
|
|
+ loadingMap,
|
|
|
+ loadingStats,
|
|
|
+ customResultDetails,
|
|
|
+ formatNumber,
|
|
|
+ calculateAndVisualize
|
|
|
+ };
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/* 样式部分保持不变,与之前相同 */
|
|
|
-.fertilizer-input-form {
|
|
|
- padding: 20px;
|
|
|
+/* 整体布局优化 - 紧凑版 */
|
|
|
+.agricultural-input-management {
|
|
|
+ padding: 15px;
|
|
|
+ background: linear-gradient(
|
|
|
+ 135deg,
|
|
|
+ rgba(230, 247, 255, 0.7) 0%,
|
|
|
+ rgba(240, 248, 255, 0.7) 100%
|
|
|
+ );
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.page-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- background-color: rgba(255, 255, 255, 0.8);
|
|
|
}
|
|
|
|
|
|
-.form-card {
|
|
|
- width: 90%;
|
|
|
- max-width: 1200px;
|
|
|
- margin: 0 auto;
|
|
|
- background: linear-gradient(135deg, #FAFDFF, #FFFAA2);
|
|
|
- border: 1px solid #e6e6e6;
|
|
|
- border-radius: 12px;
|
|
|
- overflow: hidden;
|
|
|
- box-shadow: 0 8px 24px rgba极端的(0, 0, 0, 0.1);
|
|
|
-}
|
|
|
-
|
|
|
-.card-content {
|
|
|
+.gradient-card, .results-card {
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 15px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ backdrop-filter: blur(5px);
|
|
|
+ flex: 1;
|
|
|
display: flex;
|
|
|
- min-height: 600px;
|
|
|
-}
|
|
|
-
|
|
|
-.input-section {
|
|
|
- width: 60%;
|
|
|
- padding: 30px;
|
|
|
- border-right: 1px dashed #c0c4cc;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
-.button-section {
|
|
|
- width: 40%;
|
|
|
+/* 计算内容区域 */
|
|
|
+.calculation-content {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 极端的30px;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
-.button-bg {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- background-size: cover;
|
|
|
- z-index: 0;
|
|
|
+.page-title {
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ color: #333;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
|
|
|
-.bottom-overlay {
|
|
|
- position: absolute;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- bottom: 0;
|
|
|
- height: 40%;
|
|
|
- background: linear-gradient(to top, rgba(255, 255, 255, 0.5), transparent);
|
|
|
- z-index: 1;
|
|
|
+.scrollable-content {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 8px;
|
|
|
+ margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
-.form-section {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- height: 100%;
|
|
|
+/* 输入区域样式 - 标题在左侧 */
|
|
|
+.input-section {
|
|
|
+ width: 100%;
|
|
|
+ padding: 8px 0;
|
|
|
}
|
|
|
|
|
|
-.input-group {
|
|
|
+.input-row {
|
|
|
display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- margin-bottom: 20px;
|
|
|
- gap: 20px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ gap: 12px;
|
|
|
}
|
|
|
|
|
|
-.form-item {
|
|
|
+.input-item {
|
|
|
flex: 1;
|
|
|
- margin-bottom: 0;
|
|
|
+ min-width: calc(50% - 6px);
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-start;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
}
|
|
|
|
|
|
-.el-form-item__label {
|
|
|
+.input-title {
|
|
|
font-size: 16px;
|
|
|
+ color: #666;
|
|
|
text-align: left;
|
|
|
- margin-bottom: 8px;
|
|
|
- padding: 0 !important;
|
|
|
- font-weight: 600;
|
|
|
- color: #333;
|
|
|
+ font-weight: 500;
|
|
|
+ width:220px;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
-.el-input {
|
|
|
- width: 100%;
|
|
|
+/* 固定输入栏宽度 */
|
|
|
+.fixed-width-input {
|
|
|
+ width: 300px;
|
|
|
+ flex-shrink: 0; /* 防止输入框被压缩 */
|
|
|
}
|
|
|
|
|
|
-:deep(.el-input) .el-input__inner {
|
|
|
- width: 100% !important;
|
|
|
- padding: 12px 0;
|
|
|
- border: none;
|
|
|
- border-radius: 0;
|
|
|
- background: transparent;
|
|
|
- border-bottom: 1px solid #dcdfe6;
|
|
|
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-input) .el-input__inner:focus {
|
|
|
- border-bottom: 2px solid #409EFF;
|
|
|
- box-shadow: 0 2px 0 rgba(64, 158, 255, 0.2);
|
|
|
- background: rgba(64, 158, 255, 0.03);
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-input) .el-input__inner::placeholder {
|
|
|
- color: #a0a0a0;
|
|
|
- font-style: italic;
|
|
|
+/* 按钮容器 */
|
|
|
+.button-container {
|
|
|
+ padding: 10px 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: auto;
|
|
|
}
|
|
|
|
|
|
.calculate-btn {
|
|
|
- width: 100%;
|
|
|
- max-width: 300px;
|
|
|
- height: 200px;
|
|
|
- border: none;
|
|
|
- border-radius: 25px !important;
|
|
|
- font-size: 24px;
|
|
|
+ width: 280px;
|
|
|
+ background-color: #47C3B9 !important;
|
|
|
+ color: white !important;
|
|
|
font-weight: bold;
|
|
|
- transition: all 0.4s ease;
|
|
|
- position: relative;
|
|
|
- z-index: 2;
|
|
|
- background: linear-gradient(to right, #8DF9F0, #26B046);
|
|
|
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15),
|
|
|
- 0 4px 10px rgba(38, 176, 70, 0.3) inset;
|
|
|
-}
|
|
|
-
|
|
|
-.calculate-btn:hover {
|
|
|
- transform: scale(1.03);
|
|
|
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2),
|
|
|
- 0 4px 12px rgba(38, 176, 70, 0.4) inset;
|
|
|
- background: linear-gradient(to right, #7de8df, #20a03d);
|
|
|
-}
|
|
|
-
|
|
|
-.calculate-btn:active {
|
|
|
- transform: scale(0.98);
|
|
|
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15),
|
|
|
- 0 2px 8px rgba(38, 176, 70, 极端的0.4) inset;
|
|
|
-}
|
|
|
-
|
|
|
-.btn-text {
|
|
|
- position: relative;
|
|
|
- color: white;
|
|
|
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
|
|
|
- font-size: 26px;
|
|
|
- letter-spacing: 1px;
|
|
|
- z-index: 1;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-size: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.results-card {
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+ border-radius: 8px;
|
|
|
padding: 20px;
|
|
|
- text-align: center;
|
|
|
- line-height: 1.4;
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
+ backdrop-filter: blur(5px);
|
|
|
+ height: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
-/* 结果页面样式 */
|
|
|
-.results-page {
|
|
|
- width: 90%;
|
|
|
- max-width: 1200px;
|
|
|
- padding: 30px;
|
|
|
- background: linear-gradient(135deg, #FAFDFF, #FFFAA2);
|
|
|
- border-radius: 12px;
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
- position: relative;
|
|
|
+.results-content {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.map-section, .stats-area, .chart-section {
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 15px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
-.results-title {
|
|
|
- text-align: center;
|
|
|
+h3 {
|
|
|
+ margin-bottom: 12px;
|
|
|
color: #333;
|
|
|
- margin-bottom: 30px;
|
|
|
- font-size: 28px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
|
|
|
|
-.result-card {
|
|
|
- width: 100%;
|
|
|
- margin: 0 auto;
|
|
|
- padding: 20px;
|
|
|
- background: white;
|
|
|
- border-radius: 12px;
|
|
|
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
+.model-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ margin-bottom: 12px;
|
|
|
}
|
|
|
|
|
|
-.result-card h3 {
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 20px;
|
|
|
- color: #333;
|
|
|
+.update-time {
|
|
|
+ color: #666;
|
|
|
+ font-size: 13px;
|
|
|
}
|
|
|
|
|
|
-.result-card p {
|
|
|
- margin: 10px 0;
|
|
|
- font-size: 16px;
|
|
|
+.total-flux {
|
|
|
text-align: center;
|
|
|
+ font-size: 16px;
|
|
|
font-weight: bold;
|
|
|
- color: #26B046;
|
|
|
-}
|
|
|
-
|
|
|
-.chart-container {
|
|
|
- margin-top: 20px;
|
|
|
- border: 1px solid #eee;
|
|
|
- border-radius: 8px;
|
|
|
- padding: 10px;
|
|
|
- background: #f9f9f9;
|
|
|
+ margin-bottom: 15px;
|
|
|
}
|
|
|
|
|
|
-.map-container {
|
|
|
- margin-top: 30px;
|
|
|
- padding: 20px;
|
|
|
+/* 图片容器限定大小 */
|
|
|
+.image-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 500px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
background-color: #f9f9f9;
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #eee;
|
|
|
+ border-radius: 6px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
-.map-container h3 {
|
|
|
- text-align: center;
|
|
|
- margin-bottom: 15px;
|
|
|
- color: #333;
|
|
|
+.result-image {
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
}
|
|
|
|
|
|
-.map-wrapper {
|
|
|
- position: relative;
|
|
|
- min-height: 400px;
|
|
|
+.loading-container {
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- background-color: white;
|
|
|
- border-radius: 6px;
|
|
|
- overflow: hidden;
|
|
|
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ height: 250px;
|
|
|
+ color: #47C3B9;
|
|
|
}
|
|
|
|
|
|
-.map-image-container {
|
|
|
- width: 100%;
|
|
|
+.no-data {
|
|
|
display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
justify-content: center;
|
|
|
+ height: 250px;
|
|
|
+ color: #999;
|
|
|
+ font-size: 14px;
|
|
|
}
|
|
|
|
|
|
-.map-image {
|
|
|
- max-width: 100%;
|
|
|
- max-height: 500px;
|
|
|
- object-fit: contain;
|
|
|
+.no-data .el-icon {
|
|
|
+ font-size: 40px;
|
|
|
+ margin-bottom: 8px;
|
|
|
}
|
|
|
|
|
|
-.map-placeholder {
|
|
|
- text-align: center;
|
|
|
- padding: 20px;
|
|
|
- width: 80%;
|
|
|
+.loading-icon {
|
|
|
+ font-size: 32px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ animation: rotate 2s linear infinite;
|
|
|
}
|
|
|
|
|
|
-.map-placeholder p {
|
|
|
- margin-bottom: 15px;
|
|
|
- font-size: 16px;
|
|
|
- color: #666;
|
|
|
+@keyframes rotate {
|
|
|
+ from { transform: rotate(0deg); }
|
|
|
+ to { transform: rotate(360deg); }
|
|
|
}
|
|
|
|
|
|
-.back-button {
|
|
|
- position: absolute;
|
|
|
- top: 20px;
|
|
|
- left: 20px;
|
|
|
- width: 120px;
|
|
|
- font-size: 16px;
|
|
|
- padding: 10px;
|
|
|
- background: linear-gradient(to right, #8DF9F0, #26B046);
|
|
|
- color: white;
|
|
|
- border: none;
|
|
|
- border-radius: 20px;
|
|
|
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
|
+/* 响应式设计 */
|
|
|
+@media (max-width: 992px) {
|
|
|
+ .input-row {
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-item {
|
|
|
+ min-width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 18px;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fixed-width-input {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-.back-button:hover {
|
|
|
- background: linear-gradient(to right, #7de8df, #20a03d);
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .toolbar {
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: stretch;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-title {
|
|
|
+ min-width: 150px;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image-container {
|
|
|
+ height: 280px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-input__inner) {
|
|
|
+ height: 34px;
|
|
|
+ line-height: 34px;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 480px) {
|
|
|
+ .agricultural-input-management {
|
|
|
+ padding: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .gradient-card, .results-card {
|
|
|
+ padding: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-item {
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-title {
|
|
|
+ min-width: 100%;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .calculate-btn {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 280px;
|
|
|
+ height: 38px;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .image-container {
|
|
|
+ height: 220px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .total-flux {
|
|
|
+ font-size: 15px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.custom-button {
|
|
|
+ background-color: #47C3B9 !important;
|
|
|
+ color: #DCFFFA !important;
|
|
|
+ border: none;
|
|
|
+ border-radius: 155px;
|
|
|
+ padding: 10px 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+/* 工具栏样式 */
|
|
|
+.toolbar {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-start;
|
|
|
+ gap: 15px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ padding: 15px;
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
+ backdrop-filter: blur(5px);
|
|
|
}
|
|
|
</style>
|