Эх сурвалжийг харах

Merge branch 'ding'

# Conflicts:
#	components.d.ts
#	src/components/layout/AppLayout.vue
#	src/views/User/heavyMetalFluxCalculation/inputFluxCalculation/irrigationWater.vue
yangtaodemon 3 долоо хоног өмнө
parent
commit
83695a451a

+ 1 - 1
auto-imports.d.ts

@@ -68,6 +68,6 @@ declare global {
 // for type re-export
 declare global {
   // @ts-ignore
-  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
+  export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
   import('vue')
 }

+ 3 - 2
components.d.ts

@@ -2,6 +2,7 @@
 // @ts-nocheck
 // Generated by unplugin-vue-components
 // Read more: https://github.com/vuejs/core/pull/3399
+// biome-ignore lint: disable
 export {}
 
 /* prettier-ignore */
@@ -14,12 +15,10 @@ declare module 'vue' {
     ElAside: typeof import('element-plus/es')['ElAside']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
-    ElCard: typeof import('element-plus/es')['ElCard']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
     ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
     ElCol: typeof import('element-plus/es')['ElCol']
     ElContainer: typeof import('element-plus/es')['ElContainer']
-    ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
     ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@@ -28,6 +27,7 @@ declare module 'vue' {
     ElHeader: typeof import('element-plus/es')['ElHeader']
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElInput: typeof import('element-plus/es')['ElInput']
+    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElMain: typeof import('element-plus/es')['ElMain']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
@@ -40,6 +40,7 @@ declare module 'vue' {
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     ElTabPane: typeof import('element-plus/es')['ElTabPane']
     ElTabs: typeof import('element-plus/es')['ElTabs']
+    ElTag: typeof import('element-plus/es')['ElTag']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
     IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
     IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']

+ 11 - 0
src/components/layout/AppLayout.vue

@@ -168,6 +168,17 @@ const tabs = computed<TabItem[]>(() => {
         icon: "el-icon-pie-chart", 
         routes: ["/DetectionStatistics", "/FarmlandPollutionStatistics", "/PlantingRiskStatistics"] 
       },
+      { name: "shuJuKanBan", label: "数据看板", icon: "el-icon-data-analysis", routes: ["/shuJuKanBan"] },
+      { name: "introduction", label: "软件简介", icon: "el-icon-info-filled", routes: ["/SoilPro", "/Overview", "/ResearchFindings", "/Unit"] },
+      { name: "heavyMetalFluxCalculation", label: "重金属输入输出通量", icon: "el-icon-refresh", routes: ["/irrigationWater", "/agriculturalProductInput", "/atmosphericDryWetDeposition", "/surfaceRunoff", "/cropRemoval", "/subsurfaceFlow"] },
+      { name: "mapView", label: "地图展示", icon: "el-icon-map-location", routes: ["/mapView"] },
+      { name: "cadmiumPrediction", label: "土壤镉预测", icon: "el-icon-c-scale-to-original", routes: ["/EffectiveCadmiumPrediction","/CropCadmiumPrediction"] },
+      { name: "cropRiskAssessment", label: "作物风险评估", icon: "el-icon-warning", routes: ["/cropRiskAssessment"] },
+      { name: "farmlandQualityAssessment", label: "耕地质量评估", icon: "el-icon-rank", routes: ["/farmlandQualityAssessment"] },
+      { name: "soilAcidificationPrediction", label: "土壤酸化预测", icon: "el-icon-magic-stick", routes: ["/Calculation", "/AcidNeutralizationModel"] },
+      { name: "scenarioSimulation", label: "情景模拟", icon: "el-icon-s-operation", routes: ["/TraditionalFarmingRisk", "/HeavyMetalCadmiumControl", "/SoilAcidificationControl"] },
+      { name: "dataStatistics", label: "数据统计", icon: "el-icon-pie-chart", routes: ["/DetectionStatistics", "/FarmlandPollutionStatistics", "/PlantingRiskStatistics"] },
+
     ];
   }
 });

+ 0 - 6
src/components/layout/menuItems.ts

@@ -156,12 +156,6 @@ import {
       icon: Location,
       tab: 'mapView'
     },
-    {
-      index: '/TotalCadmiumPrediction',
-      label: '土壤镉的总含量预测',
-      icon: PieChart,
-      tab: 'cadmiumPrediction'
-    },
     {
       index: '/EffectiveCadmiumPrediction',
       label: '土壤镉有效态含量预测',

+ 0 - 7
src/router/index.ts

@@ -103,13 +103,6 @@ const routes = [
         component: () => import("@/views/User/heavyMetalFluxCalculation/inputFluxCalculation/waterdata/tencentMapView.vue"), // 修复路径
         meta: { title: "地图展示" },
       },
-      {
-        path: "TotalCadmiumPrediction",
-        name: "TotalCadmiumPrediction",
-        component: () =>
-          import("@/views/User/cadmiumPrediction/TotalCadmiumPrediction.vue"), // 修复路径
-        meta: { title: "土壤镉的总含量预测" },
-      },
       {
         path: "EffectiveCadmiumPrediction",
         name: "EffectiveCadmiumPrediction",

+ 336 - 41
src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue

@@ -28,7 +28,7 @@
         <el-button class="custom-button" :disabled="!histogramBlob" @click="exportHistogram">
           <el-icon class="upload-icon"><Download /></el-icon>
           导出直方图</el-button>
-        <el-button class="custom-button" :disabled="!tableData.length" @click="exportData">
+        <el-button class="custom-button" :disabled="!statisticsData.length" @click="exportData">
           <el-icon class="upload-icon"><Download /></el-icon>
           导出数据</el-button>
       </div>
@@ -67,15 +67,50 @@
         </div>
       </div>
 
-      <!-- 表格区域 -->
-      <div class="table-area">
-        <h3>表格数据</h3>
-        <el-table :data="tableData" style="width: 100%;">
-          <el-table-column prop="name" label="名称" width="180" />
-          <el-table-column prop="value" label="值" width="100" />
-          <el-table-column prop="unit" label="单位" width="100" />
-          <el-table-column prop="description" label="描述" />
-        </el-table>
+      <!-- 统计图表区域 -->
+      <div class="stats-area">
+        <h3>{{countyName}} - 作物Cd预测统计信息</h3>
+        <div class="model-info">
+          <el-tag type="info">{{currentStats?.['模型类型'] || '作物Cd模型'}}</el-tag>
+          <span class="update-time">
+            最后更新: {{currentStats?.['数据更新时间'] ? new Date(currentStats['数据更新时间']).toLocaleString() : '未知'}}
+          </span>
+        </div>
+        
+        <div v-if="loadingStats" class="loading-container">
+          <el-icon class="loading-icon"><Loading /></el-icon>
+          <span>统计数据加载中...</span>
+        </div>
+        
+        <div v-if="!loadingStats && statisticsData.length" class="stats-container">
+          <!-- 统计表格 -->
+         <el-table 
+            :data="statisticsData" 
+            style="width: 100%; margin-bottom: 20px;"
+            border
+            stripe
+          >
+            <el-table-column prop="name" label="统计项" min-width="180" />
+            <el-table-column prop="value" label="值" min-width="150" />
+            <el-table-column prop="unit" label="单位" min-width="100" />
+            <el-table-column prop="description" label="描述" min-width="200" />
+          </el-table>
+          
+          <!-- 统计图表 -->
+          <div class="charts-container">
+            <div class="chart-item">
+              <div ref="distributionChart" style="width: 100%; height: 400px;"></div>
+            </div>
+            <div class="chart-item">
+              <div ref="exceedanceChart" style="width: 100%; height: 400px;"></div>
+            </div>
+          </div>
+        </div>
+        
+        <div v-if="!loadingStats && !statisticsData.length" class="no-data">
+          <el-icon><DataAnalysis /></el-icon>
+          <p>暂无统计数据</p>
+        </div>
       </div>
     </div>
   </div>
@@ -85,28 +120,45 @@
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
 import axios from 'axios';
-import { Loading, Upload, Picture, Histogram, Download, Document } from '@element-plus/icons-vue';
+import * as echarts from 'echarts';
+import { 
+  Loading, Upload, Picture, Histogram, Download, Document, DataAnalysis 
+} from '@element-plus/icons-vue';
 
 export default {
   name: 'CropCadmiumPrediction',
-  components: { Loading, Upload, Picture, Histogram, Download, Document },
+  components: { 
+    Loading, Upload, Picture, Histogram, Download, Document, DataAnalysis 
+  },
   data() {
     return {
       isCalculating: false,
       loadingMap: false,
       loadingHistogram: false,
-      tableData: [],
+      loadingStats: false,
+      statisticsData: [],
       mapImageUrl: null,
       histogramImageUrl: null,
       mapBlob: null,
       histogramBlob: null,
       selectedFile: null,
-      countyName: '乐昌市' // 默认县市名称
+      countyName: '乐昌市', // 默认县市名称
+      distributionChart: null,
+      exceedanceChart: null
     };
   },
+
   mounted() {
     // 组件挂载时获取最新数据
     this.fetchLatestResults();
+    this.fetchStatistics();
+  },
+
+  beforeDestroy() {
+    if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
+    if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
+    if (this.distributionChart) this.distributionChart.dispose();
+    if (this.exceedanceChart) this.exceedanceChart.dispose();
   },
   methods: {
     // 触发文件选择
@@ -177,6 +229,197 @@ export default {
       }
     },
     
+    // 格式化统计数据
+    formatStatisticsData(stats) {
+      return [
+        { name: '数据点总数', value: stats['基础统计']['数据点总数'], unit: '个', description: '总样本数量' },
+        { name: '平均值', value: stats['基础统计']['均值'].toFixed(4), unit: '(mg/kg)', description: '所有样本的平均Cd含量' },
+        { name: '中位数', value: stats['基础统计']['中位数'].toFixed(4), unit: '(mg/kg)', description: '样本的中位Cd含量' },
+        { name: '标准差', value: stats['基础统计']['标准差'].toFixed(4), unit: '(mg/kg)', description: 'Cd含量的标准差' },
+        { name: '最小值', value: stats['基础统计']['最小值'].toFixed(4), unit: '(mg/kg)', description: '样本中的最小Cd含量' },
+        { name: '最大值', value: stats['基础统计']['最大值'].toFixed(4), unit: '(mg/kg)', description: '样本中的最大Cd含量' },
+        { name: '偏度', value: stats['基础统计']['偏度'].toFixed(4), unit: '', description: '数据分布偏斜程度' },
+        { name: '峰度', value: stats['基础统计']['峰度'].toFixed(4), unit: '', description: '数据分布峰态' },
+        { 
+          name: '经度范围', 
+          value: `${stats['空间统计']['经度范围']['最小值'].toFixed(6)} - ${stats['空间统计']['经度范围']['最大值'].toFixed(6)}`, 
+          unit: '度', 
+          description: `跨度: ${stats['空间统计']['经度范围']['跨度'].toFixed(6)}度` 
+        },
+        { 
+          name: '纬度范围', 
+          value: `${stats['空间统计']['纬度范围']['最小值'].toFixed(6)} - ${stats['空间统计']['纬度范围']['最大值'].toFixed(6)}`, 
+          unit: '度', 
+          description: `跨度: ${stats['空间统计']['纬度范围']['跨度'].toFixed(6)}度` 
+        }
+      ];
+    },
+
+    // 初始化图表 - 根据实际数据更新
+    initCharts() {
+      if (!this.statisticsData.length || !this.currentStats) return;
+      
+      // 销毁旧图表
+      if (this.distributionChart) this.distributionChart.dispose();
+      if (this.exceedanceChart) this.exceedanceChart.dispose();
+      
+      const histData = this.currentStats['分布直方图'];
+      
+      // 1. 分布直方图
+      this.distributionChart = echarts.init(this.$refs.distributionChart);
+      this.distributionChart.setOption({
+        title: {
+          text: 'Cd含量分布直方图',
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'item',
+          formatter: params => {
+            const index = params.dataIndex;
+            const lowerBound = histData['区间边界'][index].toFixed(4);
+            const upperBound = histData['区间边界'][index + 1].toFixed(4);
+            return `区间: ${lowerBound} ~ ${upperBound}<br/>频次: ${params.value}`;
+          }
+        },
+        xAxis: {
+          type: 'category',
+          data: histData['区间中心'].map(v => v.toFixed(4)),
+          name: 'Cd含量',
+          axisLabel: {
+            rotate: 45
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '频次'
+        },
+        series: [{
+          name: '样本分布',
+          type: 'bar',
+          data: histData['频次'],
+          itemStyle: {
+            color: '#47C3B9'
+          },
+          barWidth: '80%'
+        }],
+        grid: {
+          bottom: '20%'
+        }
+      });
+      
+      // 2. 箱线图/统计图表
+      this.exceedanceChart = echarts.init(this.$refs.exceedanceChart);
+      
+      // 准备箱线图数据
+      const boxData = [
+        [
+          this.currentStats['基础统计']['最小值'],
+          this.currentStats['基础统计']['25%分位数'],
+          this.currentStats['基础统计']['中位数'],
+          this.currentStats['基础统计']['75%分位数'],
+          this.currentStats['基础统计']['最大值'],
+          // 还可以添加离群点数据(如果有)
+        ]
+      ];
+      
+      this.exceedanceChart.setOption({
+        title: {
+          text: 'Cd含量统计指标',
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'item',
+          axisPointer: {
+            type: 'shadow'
+          },
+          formatter: params => {
+            const data = boxData[0];
+            return [
+              '最大值: ' + data[4].toFixed(4),
+              '75%分位数: ' + data[3].toFixed(4),
+              '中位数: ' + data[2].toFixed(4),
+              '25%分位数: ' + data[1].toFixed(4),
+              '最小值: ' + data[0].toFixed(4)
+            ].join('<br/>');
+          }
+        },
+        xAxis: {
+          type: 'category',
+          data: ['Cd含量统计'],
+          axisLabel: {
+            rotate: 45
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '(Cd含量)'
+        },
+        series: [{
+          name: '统计值',
+          type: 'boxplot',
+          data: boxData,
+          itemStyle: {
+            color: '#47C3B9',
+            borderColor: '#2F4554'
+          },
+          emphasis: {
+            itemStyle: {
+              color: '#FF6B6B',
+              borderColor: '#C23531'
+            }
+          },
+          tooltip: {
+            formatter: param => {
+              const data = boxData[0];
+              return [
+                '最大值: ' + data[4].toFixed(4),
+                '75%分位数: ' + data[3].toFixed(4),
+                '中位数: ' + data[2].toFixed(4),
+                '25%分位数: ' + data[1].toFixed(4),
+                '最小值: ' + data[0].toFixed(4)
+              ].join('<br/>');
+            }
+          }
+        }],
+        grid: {
+          bottom: '15%'
+        }
+      });
+      
+      // 响应式调整
+      window.addEventListener('resize', this.handleResize);
+    },
+
+    // 修改fetchStatistics方法
+    async fetchStatistics() {
+      try {
+        this.loadingStats = true;
+        
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/crop-cd/statistics/${this.countyName}`
+        );
+        
+        if (response.data.success && response.data.data) {
+          this.currentStats = response.data.data; // 保存原始统计数据
+          this.statisticsData = this.formatStatisticsData(response.data.data);
+          this.$nextTick(() => {
+            this.initCharts();
+          });
+        }
+      } catch (error) {
+        console.error('获取统计信息失败:', error);
+        this.$message.warning('获取统计信息失败');
+      } finally {
+        this.loadingStats = false;
+      }
+    },
+    
+    // 处理窗口大小变化
+    handleResize() {
+      if (this.distributionChart) this.distributionChart.resize();
+      if (this.exceedanceChart) this.exceedanceChart.resize();
+    },
+    
     // 上传并计算
     async calculate() {
       if (!this.selectedFile) {
@@ -188,13 +431,14 @@ export default {
         this.isCalculating = true;
         this.loadingMap = true;
         this.loadingHistogram = true;
+        this.loadingStats = true;
         
         // 创建FormData
         const formData = new FormData();
         formData.append('county_name', this.countyName);
         formData.append('data_file', this.selectedFile);
         
-        // 调用有效态Cd地图接口
+        // 调用作物Cd地图接口
         const mapResponse = await axios.post(
           'https://soilgd.com:8000/api/cd-prediction/crop-cd/generate-and-get-map',
           formData,
@@ -210,14 +454,9 @@ export default {
         this.mapBlob = mapResponse.data;
         this.mapImageUrl = URL.createObjectURL(this.mapBlob);
         
-        // 更新后重新获取直方图(因为生成新数据后直方图也会更新)
+        // 更新后重新获取直方图和统计数据
         await this.fetchLatestHistogram();
-        
-        // 更新表格数据(示例)
-        this.tableData = [
-          { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
-          { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
-        ];
+        await this.fetchStatistics();
         
         this.$message.success('计算完成!');
         
@@ -226,7 +465,6 @@ export default {
         let errorMessage = '计算失败,请重试';
         
         if (error.response) {
-          // 处理不同错误状态码
           if (error.response.status === 400) {
             errorMessage = '文件格式错误:' + (error.response.data.detail || '请上传正确的CSV文件');
           } else if (error.response.status === 404) {
@@ -241,6 +479,7 @@ export default {
         this.isCalculating = false;
         this.loadingMap = false;
         this.loadingHistogram = false;
+        this.loadingStats = false;
       }
     },
     
@@ -272,29 +511,41 @@ export default {
       URL.revokeObjectURL(link.href);
     },
     
-    // 导出数据
-    exportData() {
-      if (!this.tableData.length) {
-        this.$message.warning('暂无数据可导出');
-        return;
+    // 导出数据 - 修改为获取作物Cd的CSV文件
+    async exportData() {
+      try {
+        this.$message.info('正在获取作物Cd预测数据...');
+        
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/download-final-crop-cd-csv`,
+          { responseType: 'blob' }
+        );
+        
+        const blob = new Blob([response.data], { type: 'text/csv' });
+        const link = document.createElement('a');
+        link.href = URL.createObjectURL(blob);
+        link.download = `${this.countyName}_作物Cd预测数据.csv`;
+        link.click();
+        URL.revokeObjectURL(link.href);
+        
+        this.$message.success('数据导出成功');
+      } catch (error) {
+        console.error('导出数据失败:', error);
+        this.$message.error('导出数据失败: ' + (error.response?.data?.detail || '请稍后重试'));
       }
-      
-      const workbook = XLSX.utils.book_new();
-      const worksheet = XLSX.utils.json_to_sheet(this.tableData);
-      XLSX.utils.book_append_sheet(workbook, worksheet, '作物态Cd数据');
-      const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
-      const excelData = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
-      saveAs(excelData, `${this.countyName}_作物态Cd数据.xlsx`);
     }
-  },
-  beforeDestroy() {
-    if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
-    if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
   }
 };
 </script>
 
 <style scoped>
+::v-deep .el-table th.el-table__cell {
+  text-align: center;
+  background-color: #f5f7fa !important;
+}
+::v-deep .el-table td.el-table__cell {
+  text-align: center;
+}
 .container {
   padding: 20px;
   background-color: #f5f7fa;
@@ -367,7 +618,7 @@ export default {
 
 .map-section, .histogram-section {
   flex: 1;
-  min-width: 300px; /* 最小宽度,确保在小屏幕上也能正常显示 */
+  min-width: 300px;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
@@ -384,15 +635,34 @@ export default {
   border-radius: 4px;
 }
 
-.table-area {
+.stats-area {
   width: 100%;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.stats-container {
   margin-top: 20px;
 }
 
+.charts-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+  margin-top: 30px;
+}
+
+.chart-item {
+  flex: 1;
+  min-width: 300px;
+  background: #f9f9f9;
+  padding: 15px;
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+}
+
 .loading-container {
   display: flex;
   flex-direction: column;
@@ -443,4 +713,29 @@ export default {
     flex: none;
   }
 }
+.model-info {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin: 10px 0;
+  color: #666;
+}
+
+.update-time {
+  font-size: 14px;
+}
+
+.chart-item {
+  flex: 1;
+  min-width: 400px;
+  background: white;
+  padding: 15px;
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
+}
+
+.el-table {
+  margin-top: 20px;
+}
 </style>

+ 335 - 40
src/views/User/cadmiumPrediction/EffectiveCadmiumPrediction.vue

@@ -28,7 +28,7 @@
         <el-button class="custom-button" :disabled="!histogramBlob" @click="exportHistogram">
           <el-icon class="upload-icon"><Download /></el-icon>
           导出直方图</el-button>
-        <el-button class="custom-button" :disabled="!tableData.length" @click="exportData">
+        <el-button class="custom-button" :disabled="!statisticsData.length" @click="exportData">
           <el-icon class="upload-icon"><Download /></el-icon>
           导出数据</el-button>
       </div>
@@ -67,15 +67,50 @@
         </div>
       </div>
 
-      <!-- 表格区域 -->
-      <div class="table-area">
-        <h3>表格数据</h3>
-        <el-table :data="tableData" style="width: 100%;">
-          <el-table-column prop="name" label="名称" width="180" />
-          <el-table-column prop="value" label="值" width="100" />
-          <el-table-column prop="unit" label="单位" width="100" />
-          <el-table-column prop="description" label="描述" />
-        </el-table>
+      <!-- 统计图表区域 -->
+      <div class="stats-area">
+        <h3>{{countyName}} - 有效Cd预测统计信息</h3>
+        <div class="model-info">
+          <el-tag type="info">{{currentStats?.['模型类型'] || '有效Cd模型'}}</el-tag>
+          <span class="update-time">
+            最后更新: {{currentStats?.['数据更新时间'] ? new Date(currentStats['数据更新时间']).toLocaleString() : '未知'}}
+          </span>
+        </div>
+        
+        <div v-if="loadingStats" class="loading-container">
+          <el-icon class="loading-icon"><Loading /></el-icon>
+          <span>统计数据加载中...</span>
+        </div>
+        
+        <div v-if="!loadingStats && statisticsData.length" class="stats-container">
+          <!-- 统计表格 -->
+           <el-table 
+              :data="statisticsData" 
+              style="width: 100%; margin-bottom: 20px;"
+              border
+              stripe
+            >
+              <el-table-column prop="name" label="统计项" min-width="180" />
+              <el-table-column prop="value" label="值" min-width="150" />
+              <el-table-column prop="unit" label="单位" min-width="100" />
+              <el-table-column prop="description" label="描述" min-width="200" />
+            </el-table>
+          
+          <!-- 统计图表 -->
+          <div class="charts-container">
+            <div class="chart-item">
+              <div ref="distributionChart" style="width: 100%; height: 400px;"></div>
+            </div>
+            <div class="chart-item">
+              <div ref="exceedanceChart" style="width: 100%; height: 400px;"></div>
+            </div>
+          </div>
+        </div>
+        
+        <div v-if="!loadingStats && !statisticsData.length" class="no-data">
+          <el-icon><DataAnalysis /></el-icon>
+          <p>暂无统计数据</p>
+        </div>
       </div>
     </div>
   </div>
@@ -85,28 +120,45 @@
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
 import axios from 'axios';
-import { Loading, Upload, Picture, Histogram, Download, Document } from '@element-plus/icons-vue';
+import * as echarts from 'echarts';
+import { 
+  Loading, Upload, Picture, Histogram, Download, Document, DataAnalysis 
+} from '@element-plus/icons-vue';
 
 export default {
-  name: 'EffectiveCadmiumPrediction',
-  components: { Loading, Upload, Picture, Histogram, Download, Document },
+  name: 'CropCadmiumPrediction',
+  components: { 
+    Loading, Upload, Picture, Histogram, Download, Document, DataAnalysis 
+  },
   data() {
     return {
       isCalculating: false,
       loadingMap: false,
       loadingHistogram: false,
-      tableData: [],
+      loadingStats: false,
+      statisticsData: [],
       mapImageUrl: null,
       histogramImageUrl: null,
       mapBlob: null,
       histogramBlob: null,
       selectedFile: null,
-      countyName: '乐昌市' // 默认县市名称
+      countyName: '乐昌市', // 默认县市名称
+      distributionChart: null,
+      exceedanceChart: null
     };
   },
+
   mounted() {
     // 组件挂载时获取最新数据
     this.fetchLatestResults();
+    this.fetchStatistics();
+  },
+
+  beforeDestroy() {
+    if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
+    if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
+    if (this.distributionChart) this.distributionChart.dispose();
+    if (this.exceedanceChart) this.exceedanceChart.dispose();
   },
   methods: {
     // 触发文件选择
@@ -177,6 +229,197 @@ export default {
       }
     },
     
+    // 格式化统计数据
+    formatStatisticsData(stats) {
+      return [
+        { name: '数据点总数', value: stats['基础统计']['数据点总数'], unit: '个', description: '总样本数量' },
+        { name: '平均值', value: stats['基础统计']['均值'].toFixed(4), unit: '(mg/kg)', description: '所有样本的平均Cd含量' },
+        { name: '中位数', value: stats['基础统计']['中位数'].toFixed(4), unit: '(mg/kg)', description: '样本的中位Cd含量' },
+        { name: '标准差', value: stats['基础统计']['标准差'].toFixed(4), unit: '(mg/kg)', description: 'Cd含量的标准差' },
+        { name: '最小值', value: stats['基础统计']['最小值'].toFixed(4), unit: '(mg/kg)', description: '样本中的最小Cd含量' },
+        { name: '最大值', value: stats['基础统计']['最大值'].toFixed(4), unit: '(mg/kg)', description: '样本中的最大Cd含量' },
+        { name: '偏度', value: stats['基础统计']['偏度'].toFixed(4), unit: '', description: '数据分布偏斜程度' },
+        { name: '峰度', value: stats['基础统计']['峰度'].toFixed(4), unit: '', description: '数据分布峰态' },
+        { 
+          name: '经度范围', 
+          value: `${stats['空间统计']['经度范围']['最小值'].toFixed(6)} - ${stats['空间统计']['经度范围']['最大值'].toFixed(6)}`, 
+          unit: '度', 
+          description: `跨度: ${stats['空间统计']['经度范围']['跨度'].toFixed(6)}度` 
+        },
+        { 
+          name: '纬度范围', 
+          value: `${stats['空间统计']['纬度范围']['最小值'].toFixed(6)} - ${stats['空间统计']['纬度范围']['最大值'].toFixed(6)}`, 
+          unit: '度', 
+          description: `跨度: ${stats['空间统计']['纬度范围']['跨度'].toFixed(6)}度` 
+        }
+      ];
+    },
+
+    // 初始化图表 - 根据实际数据更新
+    initCharts() {
+      if (!this.statisticsData.length || !this.currentStats) return;
+      
+      // 销毁旧图表
+      if (this.distributionChart) this.distributionChart.dispose();
+      if (this.exceedanceChart) this.exceedanceChart.dispose();
+      
+      const histData = this.currentStats['分布直方图'];
+      
+      // 1. 分布直方图
+      this.distributionChart = echarts.init(this.$refs.distributionChart);
+      this.distributionChart.setOption({
+        title: {
+          text: 'Cd含量分布直方图',
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'item',
+          formatter: params => {
+            const index = params.dataIndex;
+            const lowerBound = histData['区间边界'][index].toFixed(4);
+            const upperBound = histData['区间边界'][index + 1].toFixed(4);
+            return `区间: ${lowerBound} ~ ${upperBound}<br/>频次: ${params.value}`;
+          }
+        },
+        xAxis: {
+          type: 'category',
+          data: histData['区间中心'].map(v => v.toFixed(4)),
+          name: 'Cd含量',
+          axisLabel: {
+            rotate: 45
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '频次'
+        },
+        series: [{
+          name: '样本分布',
+          type: 'bar',
+          data: histData['频次'],
+          itemStyle: {
+            color: '#47C3B9'
+          },
+          barWidth: '80%'
+        }],
+        grid: {
+          bottom: '20%'
+        }
+      });
+      
+      // 2. 箱线图/统计图表
+      this.exceedanceChart = echarts.init(this.$refs.exceedanceChart);
+      
+      // 准备箱线图数据
+      const boxData = [
+        [
+          this.currentStats['基础统计']['最小值'],
+          this.currentStats['基础统计']['25%分位数'],
+          this.currentStats['基础统计']['中位数'],
+          this.currentStats['基础统计']['75%分位数'],
+          this.currentStats['基础统计']['最大值'],
+          // 还可以添加离群点数据(如果有)
+        ]
+      ];
+      
+      this.exceedanceChart.setOption({
+        title: {
+          text: 'Cd含量统计指标',
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'item',
+          axisPointer: {
+            type: 'shadow'
+          },
+          formatter: params => {
+            const data = boxData[0];
+            return [
+              '最大值: ' + data[4].toFixed(4),
+              '75%分位数: ' + data[3].toFixed(4),
+              '中位数: ' + data[2].toFixed(4),
+              '25%分位数: ' + data[1].toFixed(4),
+              '最小值: ' + data[0].toFixed(4)
+            ].join('<br/>');
+          }
+        },
+        xAxis: {
+          type: 'category',
+          data: ['Cd含量统计'],
+          axisLabel: {
+            rotate: 45
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: 'Cd含量'
+        },
+        series: [{
+          name: '统计值',
+          type: 'boxplot',
+          data: boxData,
+          itemStyle: {
+            color: '#47C3B9',
+            borderColor: '#2F4554'
+          },
+          emphasis: {
+            itemStyle: {
+              color: '#FF6B6B',
+              borderColor: '#C23531'
+            }
+          },
+          tooltip: {
+            formatter: param => {
+              const data = boxData[0];
+              return [
+                '最大值: ' + data[4].toFixed(4),
+                '75%分位数: ' + data[3].toFixed(4),
+                '中位数: ' + data[2].toFixed(4),
+                '25%分位数: ' + data[1].toFixed(4),
+                '最小值: ' + data[0].toFixed(4)
+              ].join('<br/>');
+            }
+          }
+        }],
+        grid: {
+          bottom: '15%'
+        }
+      });
+      
+      // 响应式调整
+      window.addEventListener('resize', this.handleResize);
+    },
+
+    // 修改fetchStatistics方法
+    async fetchStatistics() {
+      try {
+        this.loadingStats = true;
+        
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/effective-cd/statistics/${this.countyName}`
+        );
+        
+        if (response.data.success && response.data.data) {
+          this.currentStats = response.data.data; // 保存原始统计数据
+          this.statisticsData = this.formatStatisticsData(response.data.data);
+          this.$nextTick(() => {
+            this.initCharts();
+          });
+        }
+      } catch (error) {
+        console.error('获取统计信息失败:', error);
+        this.$message.warning('获取统计信息失败');
+      } finally {
+        this.loadingStats = false;
+      }
+    },
+    
+    // 处理窗口大小变化
+    handleResize() {
+      if (this.distributionChart) this.distributionChart.resize();
+      if (this.exceedanceChart) this.exceedanceChart.resize();
+    },
+    
     // 上传并计算
     async calculate() {
       if (!this.selectedFile) {
@@ -188,6 +431,7 @@ export default {
         this.isCalculating = true;
         this.loadingMap = true;
         this.loadingHistogram = true;
+        this.loadingStats = true;
         
         // 创建FormData
         const formData = new FormData();
@@ -210,14 +454,9 @@ export default {
         this.mapBlob = mapResponse.data;
         this.mapImageUrl = URL.createObjectURL(this.mapBlob);
         
-        // 更新后重新获取直方图(因为生成新数据后直方图也会更新)
+        // 更新后重新获取直方图和统计数据
         await this.fetchLatestHistogram();
-        
-        // 更新表格数据(示例)
-        this.tableData = [
-          { name: '样本1', value: 10, unit: 'mg/L', description: '描述1' },
-          { name: '样本2', value: 20, unit: 'mg/L', description: '描述2' }
-        ];
+        await this.fetchStatistics();
         
         this.$message.success('计算完成!');
         
@@ -226,7 +465,6 @@ export default {
         let errorMessage = '计算失败,请重试';
         
         if (error.response) {
-          // 处理不同错误状态码
           if (error.response.status === 400) {
             errorMessage = '文件格式错误:' + (error.response.data.detail || '请上传正确的CSV文件');
           } else if (error.response.status === 404) {
@@ -241,6 +479,7 @@ export default {
         this.isCalculating = false;
         this.loadingMap = false;
         this.loadingHistogram = false;
+        this.loadingStats = false;
       }
     },
     
@@ -273,28 +512,40 @@ export default {
     },
     
     // 导出数据
-    exportData() {
-      if (!this.tableData.length) {
-        this.$message.warning('暂无数据可导出');
-        return;
+    async exportData() {
+      try {
+        this.$message.info('正在获取有效Cd预测数据...');
+        
+        const response = await axios.get(
+          `https://soilgd.com:8000/api/cd-prediction/download-final-effective-cd-csv`,
+          { responseType: 'blob' }
+        );
+        
+        const blob = new Blob([response.data], { type: 'text/csv' });
+        const link = document.createElement('a');
+        link.href = URL.createObjectURL(blob);
+        link.download = `${this.countyName}_有效Cd预测数据.csv`;
+        link.click();
+        URL.revokeObjectURL(link.href);
+        
+        this.$message.success('数据导出成功');
+      } catch (error) {
+        console.error('导出数据失败:', error);
+        this.$message.error('导出数据失败: ' + (error.response?.data?.detail || '请稍后重试'));
       }
-      
-      const workbook = XLSX.utils.book_new();
-      const worksheet = XLSX.utils.json_to_sheet(this.tableData);
-      XLSX.utils.book_append_sheet(workbook, worksheet, '有效态Cd数据');
-      const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
-      const excelData = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
-      saveAs(excelData, `${this.countyName}_有效态Cd数据.xlsx`);
     }
-  },
-  beforeDestroy() {
-    if (this.mapImageUrl) URL.revokeObjectURL(this.mapImageUrl);
-    if (this.histogramImageUrl) URL.revokeObjectURL(this.histogramImageUrl);
   }
 };
 </script>
 
 <style scoped>
+::v-deep .el-table th.el-table__cell {
+  text-align: center;
+  background-color: #f5f7fa !important;
+}
+::v-deep .el-table td.el-table__cell {
+  text-align: center;
+}
 .container {
   padding: 20px;
   background-color: #f5f7fa;
@@ -367,7 +618,7 @@ export default {
 
 .map-section, .histogram-section {
   flex: 1;
-  min-width: 300px; /* 最小宽度,确保在小屏幕上也能正常显示 */
+  min-width: 300px;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
@@ -384,15 +635,34 @@ export default {
   border-radius: 4px;
 }
 
-.table-area {
+.stats-area {
   width: 100%;
   background-color: white;
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+}
+
+.stats-container {
   margin-top: 20px;
 }
 
+.charts-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 20px;
+  margin-top: 30px;
+}
+
+.chart-item {
+  flex: 1;
+  min-width: 300px;
+  background: #f9f9f9;
+  padding: 15px;
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+}
+
 .loading-container {
   display: flex;
   flex-direction: column;
@@ -443,4 +713,29 @@ export default {
     flex: none;
   }
 }
+.model-info {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin: 10px 0;
+  color: #666;
+}
+
+.update-time {
+  font-size: 14px;
+}
+
+.chart-item {
+  flex: 1;
+  min-width: 400px;
+  background: white;
+  padding: 15px;
+  border-radius: 8px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
+  margin-bottom: 20px;
+}
+
+.el-table {
+  margin-top: 20px;
+}
 </style>

+ 647 - 3
src/views/User/heavyMetalFluxCalculation/inputFluxCalculation/irrigationWater.vue

@@ -1,29 +1,673 @@
 <template>
   <div class="page-container">
+<<<<<<< HEAD
    <div>
     <router-view></router-view> <!-- 关键:子路由渲染位置 -->
   </div>
 
+=======
+    <!-- 上半部分:地图 + 柱状图 -->
+    <div class="top-content">
+      <!-- 灌溉水输入通量计算模块 -->
+      <div class="irrigation-form">
+        <div class="form-header">
+          <h3>灌溉水输入通量计算</h3>
+        </div>
+        
+        <div class="form-body">
+          <div class="land-form-row">
+            <!-- 水田 -->
+            <div class="land-form">
+              <h4>水田</h4>
+              <el-form :model="irrigationData.paddy" label-position="top">
+                <el-form-item label="灌溉水用量 (吨/公顷)">
+                  <el-input-number 
+                    v-model="irrigationData.paddy.usage" 
+                    :min="0" 
+                    :step="100"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="灌溉水有效利用率 (%)">
+                  <el-input-number 
+                    v-model="irrigationData.paddy.efficiency" 
+                    :min="0" 
+                    :max="100" 
+                    :step="5"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="计算通量(吨/公顷·年)">
+                  <el-input 
+                    v-model="irrigationData.paddy.flux" 
+                    readonly
+                    class="flux-input"
+                  >
+                  </el-input>
+                </el-form-item>
+                <el-button 
+                  type="primary" 
+                  @click="calculateFlux('paddy')"
+                  class="calculate-btn"
+                >计算水田通量</el-button>
+              </el-form>
+            </div>
+            
+            <!-- 水浇地 -->
+            <div class="land-form">
+              <h4>水浇地</h4>
+              <el-form :model="irrigationData.irrigated" label-position="top">
+                <el-form-item label="灌溉水用量 (吨/公顷)">
+                  <el-input-number 
+                    v-model="irrigationData.irrigated.usage" 
+                    :min="0" 
+                    :step="100"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="灌溉水有效利用率 (%)">
+                  <el-input-number 
+                    v-model="irrigationData.irrigated.efficiency" 
+                    :min="0" 
+                    :max="100" 
+                    :step="5"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="计算通量(吨/公顷·年)">
+                  <el-input 
+                    v-model="irrigationData.irrigated.flux" 
+                    readonly
+                    class="flux-input"
+                  >
+                  </el-input>
+                </el-form-item>
+                <el-button 
+                  type="primary" 
+                  @click="calculateFlux('irrigated')"
+                  class="calculate-btn"
+                >计算水浇地通量</el-button>
+              </el-form>
+            </div>
+            
+            <!-- 旱地 -->
+            <div class="land-form">
+              <h4>旱地</h4>
+              <el-form :model="irrigationData.dryland" label-position="top">
+                <el-form-item label="灌溉水用量 (吨/公顷)">
+                  <el-input-number 
+                    v-model="irrigationData.dryland.usage" 
+                    :min="0" 
+                    :step="100"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="灌溉水有效利用率 (%)">
+                  <el-input-number 
+                    v-model="irrigationData.dryland.efficiency" 
+                    :min="0" 
+                    :max="100" 
+                    :step="5"
+                  ></el-input-number>
+                </el-form-item>
+                <el-form-item label="计算通量(吨/公顷·年)">
+                  <el-input 
+                    v-model="irrigationData.dryland.flux" 
+                    readonly
+                    class="flux-input"
+                  >
+                  </el-input>
+                </el-form-item>
+                <el-button 
+                  type="primary" 
+                  @click="calculateFlux('dryland')"
+                  class="calculate-btn"
+                >计算旱地通量</el-button>
+              </el-form>
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 右侧图表区域 -->
+      <div class="graphics-container">
+        <!-- 下拉选择栏 -->
+        <div class="land-type-selector">
+          <el-select v-model="selectedLandType" placeholder="选择土地类型" @change="handleLandTypeChange">
+            <el-option label="水田" value="paddy"></el-option>
+            <el-option label="水浇地" value="irrigated"></el-option>
+            <el-option label="旱地" value="dryland"></el-option>
+          </el-select>
+        </div>
+        
+        <!-- 图表容器 -->
+        <div class="graphics-row">
+          <!-- 地图模块 -->
+          <div class="map-module">
+            <div v-if="rasterMapImage" class="map-box">
+              <img :src="rasterMapImage" alt="土地类型Cd分布图" class="raster-image">
+            </div>
+            <div v-else-if="mapLoading" class="map-box">地图加载中...</div>
+            <div v-else class="map-box error-message">
+              地图加载失败: {{ mapError }}
+              <el-button type="primary" size="small" @click="retryMap">重试</el-button>
+            </div>
+          </div>
+          
+          <!-- 图表模块 -->
+          <div class="chart-module">
+            <div v-if="histogramImage" class="chart-box">
+              <img :src="histogramImage" alt="数据分布直方图" class="histogram-image">
+            </div>
+            <div v-else-if="histogramLoading" class="chart-box">直方图加载中...</div>
+            <div v-else class="chart-box error-message">
+              直方图加载失败: {{ histogramError }}
+              <el-button type="primary" size="small" @click="retryHistogram">重试</el-button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 中间间距 -->
+    <div class="middle-gap"></div>
+
+    <!-- 下半部分:表格 -->
+    <div class="table-module">
+      <div class="table-header">
+        <h3>计算结果汇总</h3>
+        <el-button type="primary" @click="exportData">导出数据</el-button>
+      </div>
+      
+      <el-table
+        :data="tableData"
+        style="width: 100%"
+        border
+        stripe
+        class="compact-table"
+      >
+        <el-table-column prop="name" label="土地类型" width="120" />
+        <el-table-column prop="area" label="面积 (公顷)" width="100" />
+        <el-table-column prop="quality" label="质量等级" width="100" />
+        <el-table-column prop="productivity" label="生产力指数" width="120" />
+        <el-table-column prop="waterUsage" label="灌溉水用量" width="120" />
+        <el-table-column prop="waterEfficiency" label="利用率" width="100" />
+        <el-table-column prop="waterFlux" label="通量" width="120" />
+        <el-table-column label="操作" width="80">
+          <template #default="{ row }">
+            <el-button type="primary" size="small" @click="editItem(row)">修改</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+>>>>>>> ding
   </div>
 </template>
 
 <script setup>
-import { ref, onMounted, watch, computed } from 'vue';
-import * as echarts from 'echarts';
+import { ref, onMounted, reactive, watch } from 'vue';
+import axios from 'axios';
+
+// 配置API基础URL
+const BASE_URL = 'http://localhost:8000/api/water';
+
+// 创建自定义axios实例
+const http = axios.create({
+  timeout: 60000, // 60秒超时
+});
+
+// 土地类型数据映射
+const landTypeData = {
+  paddy: {
+    shp_base_name: 'lechang',
+    tif_type: '水田',
+    properties: {
+      area: 1200,
+      quality: '优',
+      productivity: 850
+    }
+  },
+  dryland: {
+    shp_base_name: 'lechang',
+    tif_type: '旱地',
+    properties: {
+      area: 800,
+      quality: '良',
+      productivity: 600
+    }
+  },
+  irrigated: {
+    shp_base_name: 'lechang',
+    tif_type: '水浇地',
+    properties: {
+      area: 950,
+      quality: '中',
+      productivity: 720
+    }
+  }
+};
+
+// 灌溉水计算数据
+const irrigationData = reactive({
+  paddy: {
+    usage: 8000,
+    efficiency: 60,
+    flux: 4800
+  },
+  irrigated: {
+    usage: 6000,
+    efficiency: 70,
+    flux: 4200
+  },
+  dryland: {
+    usage: 4000,
+    efficiency: 50,
+    flux: 2000
+  }
+});
+
+// 响应式数据
+const selectedLandType = ref('paddy');
+const rasterMapImage = ref(null);
+const histogramImage = ref(null);
+const tableData = ref([]);
+
+// 加载状态和错误信息
+const mapLoading = ref(false);
+const histogramLoading = ref(false);
+const mapError = ref('');
+const histogramError = ref('');
+
+// 初始化数据和表格
+const initTableData = () => {
+  tableData.value = [
+    {
+      id: 1,
+      name: '水田',
+      ...landTypeData.paddy.properties,
+      waterUsage: irrigationData.paddy.usage,
+      waterEfficiency: irrigationData.paddy.efficiency + '%',
+      waterFlux: irrigationData.paddy.flux
+    },
+    {
+      id: 2,
+      name: '水浇地',
+      ...landTypeData.irrigated.properties,
+      waterUsage: irrigationData.irrigated.usage,
+      waterEfficiency: irrigationData.irrigated.efficiency + '%',
+      waterFlux: irrigationData.irrigated.flux
+    },
+    {
+      id: 3,
+      name: '旱地',
+      ...landTypeData.dryland.properties,
+      waterUsage: irrigationData.dryland.usage,
+      waterEfficiency: irrigationData.dryland.efficiency + '%',
+      waterFlux: irrigationData.dryland.flux
+    }
+  ];
+};
+
+// 计算灌溉水通量
+const calculateFlux = (landType) => {
+  const data = irrigationData[landType];
+  data.flux = Math.round(data.usage * data.efficiency / 100);
+  
+  // 更新表格数据
+  const row = tableData.value.find(item => 
+    landType === 'paddy' ? item.name === '水田' : 
+    landType === 'irrigated' ? item.name === '水浇地' : 
+    item.name === '旱地'
+  );
+  
+  if (row) {
+    row.waterUsage = data.usage;
+    row.waterEfficiency = data.efficiency + '%';
+    row.waterFlux = data.flux;
+  }
+};
 
+// 导出数据功能
+const exportData = () => {
+  alert('导出数据功能已触发,数据已准备好下载');
+  // 实际应用中这里会生成并下载CSV文件
+};
 
+// 修改条目功能
+const editItem = (row) => {
+  alert(`正在修改 ${row.name} 的数据`);
+  // 实际应用中这里会打开编辑模态框
+};
 
+onMounted(() => {
+  initTableData();
+  handleLandTypeChange();
+});
 
+// 监听灌溉数据变化更新表格
+watch(irrigationData, (newVal) => {
+  tableData.value = tableData.value.map(item => {
+    if (item.name === '水田') {
+      return {...item, 
+        waterUsage: newVal.paddy.usage, 
+        waterEfficiency: newVal.paddy.efficiency + '%', 
+        waterFlux: newVal.paddy.flux};
+    } else if (item.name === '水浇地') {
+      return {...item, 
+        waterUsage: newVal.irrigated.usage, 
+        waterEfficiency: newVal.irrigated.efficiency + '%', 
+        waterFlux: newVal.irrigated.flux};
+    } else {
+      return {...item, 
+        waterUsage: newVal.dryland.usage, 
+        waterEfficiency: newVal.dryland.efficiency + '%', 
+        waterFlux: newVal.dryland.flux};
+    }
+  });
+}, { deep: true });
+
+const handleLandTypeChange = async () => {
+  const landType = selectedLandType.value;
+  const data = landTypeData[landType];
+  
+  // 重置状态
+  rasterMapImage.value = null;
+  histogramImage.value = null;
+  mapError.value = '';
+  histogramError.value = '';
+  
+  try {
+    // 设置加载状态
+    mapLoading.value = true;
+    histogramLoading.value = true;
+    
+    // 顺序请求,避免同时处理大文件导致问题
+    await generateRasterMap(data.shp_base_name, data.tif_type);
+    await generateHistogram(data.tif_type);
+  } catch (error) {
+    console.error('数据加载失败:', error);
+  } finally {
+    // 重置加载状态
+    mapLoading.value = false;
+    histogramLoading.value = false;
+  }
+};
+
+const generateRasterMap = async (shp_base_name, tif_type) => {
+  try {
+    const formData = new FormData();
+    formData.append('shp_base_name', shp_base_name);
+    formData.append('tif_type', tif_type);
+    formData.append('color_map_name', 'colormap6');
+    formData.append('title_name', `${getLandTypeName(selectedLandType.value)}Cd分布图`);
+    formData.append('output_size', '8'); // 减小输出尺寸
+    
+    const response = await http.post(`${BASE_URL}/generate-raster-map`, formData, {
+      headers: { 'Content-Type': 'multipart/form-data' },
+      responseType: 'blob'
+    });
+    
+    if (response.data.size === 0) {
+      throw new Error('后端返回空响应');
+    }
+    
+    const blob = new Blob([response.data], { type: 'image/jpeg' });
+    rasterMapImage.value = URL.createObjectURL(blob);
+    mapError.value = '';
+  } catch (error) {
+    console.error('栅格地图生成失败:', error);
+    mapError.value = error.response?.data?.message || error.message || '未知错误';
+    throw error;
+  }
+};
+
+const generateHistogram = async (tif_type) => {
+  try {
+    const formData = new FormData();
+    formData.append('tif_type', tif_type);
+    formData.append('figsize_width', '8'); // 减小宽度
+    formData.append('figsize_height', '6'); // 减小高度
+    formData.append('xlabel', '像元值');
+    formData.append('ylabel', '频率密度');
+    formData.append('title', `${getLandTypeName(selectedLandType.value)}数据分布`);
+    
+    const response = await http.post(`${BASE_URL}/generate-tif-histogram`, formData, {
+      headers: { 'Content-Type': 'multipart/form-data' },
+      responseType: 'blob'
+    });
+    
+    if (response.data.size === 0) {
+      throw new Error('后端返回空响应');
+    }
+    
+    const blob = new Blob([response.data], { type: 'image/jpeg' });
+    histogramImage.value = URL.createObjectURL(blob);
+    histogramError.value = '';
+  } catch (error) {
+    console.error('直方图生成失败:', error);
+    histogramError.value = error.response?.data?.message || error.message || '未知错误';
+    throw error;
+  }
+};
+
+const getLandTypeName = (value) => {
+  switch (value) {
+    case 'paddy': return '水田';
+    case 'dryland': return '旱地';
+    case 'irrigated': return '水浇地';
+    default: return '';
+  }
+};
+
+// 重试功能
+const retryMap = async () => {
+  const landType = selectedLandType.value;
+  const data = landTypeData[landType];
+  
+  mapLoading.value = true;
+  mapError.value = '';
+  
+  try {
+    await generateRasterMap(data.shp_base_name, data.tif_type);
+  } catch (error) {
+    console.error('重试栅格地图失败:', error);
+  } finally {
+    mapLoading.value = false;
+  }
+};
+
+const retryHistogram = async () => {
+  const landType = selectedLandType.value;
+  const data = landTypeData[landType];
+  
+  histogramLoading.value = true;
+  histogramError.value = '';
+  
+  try {
+    await generateHistogram(data.tif_type);
+  } catch (error) {
+    console.error('重试直方图失败:', error);
+  } finally {
+    histogramLoading.value = false;
+  }
+};
 </script>
 
 <style scoped>
 .page-container {
   display: flex;
   flex-direction: column;
-  height: 100vh; /* 整屏高度 */
+  height: 100vh;
   padding: 20px;
   box-sizing: border-box;
   background-color: #f5f7fa;
 }
 
+.top-content {
+  display: flex;
+  height: 45%;
+  gap: 20px; /* 增加间距 */
+}
+
+.irrigation-form {
+  flex: 0 0 45%;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+}
+
+.form-header {
+  background-color: #2c3e50;
+  color: white;
+  padding: 10px 15px;
+  text-align: center;
+  font-size: 16px;
+  font-weight: bold;
+}
+
+.form-body {
+  padding: 15px;
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+}
+
+.land-form-row {
+  display: flex;
+  gap: 20px; /* 增加间距 */
+  height: 100%;
+}
+
+.land-form {
+  flex: 1;
+  border: 1px solid #e1e4e8;
+  border-radius: 8px;
+  padding: 15px; /* 增加内边距 */
+  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+}
+
+.land-form h4 {
+  margin-top: 0;
+  margin-bottom: 15px; /* 增加下边距 */
+  color: #1a73e8;
+  border-bottom: 1px solid #e1e4e8;
+  padding-bottom: 10px; /* 增加下边距 */
+  font-size: 14px;
+}
+
+/* 修复通量数字显示不全 */
+.flux-input {
+  width: 100%; /* 确保输入框宽度填满 */
+}
+
+.flux-input >>> .el-input__inner {
+  text-align: left; /* 数字右对齐 */
+  padding-right: 10px; /* 增加右边距 */
+  font-weight: bold; /* 加粗显示 */
+}
+
+.calculate-btn {
+  margin-top: 15px; /* 增加按钮上边距 */
+}
+
+.graphics-container {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 15px; /* 增加间距 */
+}
+
+.land-type-selector {
+  margin-bottom: 15px; /* 增加下边距 */
+}
+
+.graphics-row {
+  display: flex;
+  gap: 15px; /* 增加间距 */
+  height: calc(100% - 45px); /* 减去选择器高度 */
+}
+
+.map-module, .chart-module {
+  flex: 1;
+  background: white;
+  border-radius: 8px;
+  box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  overflow: hidden;
+  height: 100%; /* 固定高度 */
+}
+
+.map-box, .chart-box {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: relative;
+  padding: 10px; /* 增加内边距 */
+}
+
+.raster-image, .histogram-image {
+  width: 100%; /* 宽度固定为容器宽度 */
+  height: 100%; /* 高度固定为容器高度 */
+  object-fit: contain; /* 保持比例 */
+}
+
+.error-message {
+  color: #f56c6c;
+  font-size: 13px;
+  padding: 10px; /* 增加内边距 */
+  text-align: center;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10px; /* 增加间距 */
+}
+
+.middle-gap {
+  height: 20px; /* 增加中间间距高度 */
+}
+
+.table-module {
+  height: 50%;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+  margin-top: 50px; /* 增加上边距 */
+}
+
+.table-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 20px; /* 增加内边距 */
+  background-color: #f8f9fa;
+  border-bottom: 1px solid #e1e4e8;
+}
+
+.table-header h3 {
+  margin: 0;
+  font-size: 16px; /* 增加字体大小 */
+  color: #2c3e50;
+}
+
+.compact-table {
+  width: 100%;
+  height: 100%;
+  font-size: 13px;
+}
+
+.compact-table >>> .el-table__cell {
+  padding: 10px 0; /* 增加单元格内边距 */
+}
+
+/* 修复表格中数字显示 */
+.compact-table >>> .el-table__cell .cell {
+  padding: 0 10px; /* 增加单元格内边距 */
+  text-align: center; /* 居中显示 */
+  white-space: nowrap; /* 防止换行 */
+  overflow: hidden; /* 隐藏溢出 */
+  text-overflow: ellipsis; /* 显示省略号 */
+}
 </style>