Browse Source

修复数据管理部分问题

qw 1 month ago
parent
commit
b2c9c36102
48 changed files with 1884 additions and 519 deletions
  1. 11 1
      package-lock.json
  2. 1 0
      package.json
  3. 1 0
      public/data/韶关市乡镇划分图5.geojson
  4. BIN
      src/assets/videos/农业投入品.mp4
  5. BIN
      src/assets/videos/地下渗漏.mp4
  6. BIN
      src/assets/videos/地表径流.mp4
  7. BIN
      src/assets/videos/干湿沉降.mp4
  8. BIN
      src/assets/videos/灌溉水.mp4
  9. BIN
      src/assets/videos/秸秆移除.mp4
  10. BIN
      src/assets/videos/籽粒移除.mp4
  11. BIN
      src/assets/videos/输入总通量.mp4
  12. BIN
      src/assets/videos/输出总通量.mp4
  13. 1 1
      src/components/atmpollution/airsampleLine.vue
  14. 6 6
      src/components/atmpollution/atmcompanymap.vue
  15. 20 18
      src/components/atmpollution/atmsamplemap.vue
  16. 2 2
      src/components/atmpollution/heavyMetalEnterprisechart.vue
  17. 1 1
      src/components/detectionStatistics/atmsampleStatistics.vue
  18. 1 1
      src/components/detectionStatistics/irrigationstatistics.vue
  19. 2 2
      src/components/irrpollution/waterassaydata2.vue
  20. 15 15
      src/components/layout/AppLayout.vue
  21. 1 1
      src/components/soilStatictics/reducedataStatistics.vue
  22. 26 6
      src/components/soilcdStatistics/cropcdStatictics.vue
  23. 22 5
      src/components/soilcdStatistics/effcdStatistics.vue
  24. 27 56
      src/components/soilcdStatistics/fluxcdStatictics.vue
  25. 3 3
      src/locales/zh.json
  26. 4 0
      src/router/index.ts
  27. 29 22
      src/utils/request.ts
  28. 100 0
      src/views/User/HmOutFlux/agriInput/farmInputSamplingDesc.vue
  29. 22 10
      src/views/User/HmOutFlux/atmosDeposition/airSampleData.vue
  30. 21 10
      src/views/User/HmOutFlux/atmosDeposition/heavyMetalEnterprise.vue
  31. 2 3
      src/views/User/HmOutFlux/irrigationWater/crossSection.vue
  32. 26 14
      src/views/User/HmOutFlux/irrigationWater/irriWaterSampleData.vue
  33. 99 0
      src/views/User/HmOutFlux/irrigationWater/samplingMethodDevice1.vue
  34. 99 0
      src/views/User/HmOutFlux/totalInputFluxDesc.vue
  35. 788 35
      src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue
  36. 212 17
      src/views/User/cadmiumPrediction/EffectiveCadmiumPrediction.vue
  37. 9 6
      src/views/User/dataStatistics/DetectionStatistics.vue
  38. 7 1
      src/views/User/dataStatistics/LandCultivatedStatistics.vue
  39. 9 9
      src/views/User/dataStatistics/SoilCdStatistics.vue
  40. 8 8
      src/views/User/dataStatistics/SoilacidificationStatistics.vue
  41. 204 260
      src/views/User/farmlandQualityAssessment/farmlandQualityAssessment.vue
  42. 1 1
      src/views/User/hmInFlux/grainRemoval/grainRemovalInputFlux.vue
  43. 1 1
      src/views/User/hmInFlux/grainRemoval/samplingDesc1.vue
  44. 1 1
      src/views/User/hmInFlux/strawRemoval/samplingDesc2.vue
  45. 1 1
      src/views/User/hmInFlux/strawRemoval/strawRemovalInputFlux.vue
  46. 1 1
      src/views/User/hmInFlux/subsurfaceLeakage/subsurfaceLeakageInputFlux.vue
  47. 1 1
      src/views/User/hmInFlux/surfaceRunoff/surfaceRunoffInputFlux.vue
  48. 99 0
      src/views/User/hmInFlux/totalOutputFluxDesc.vue

+ 11 - 1
package-lock.json

@@ -29,6 +29,7 @@
         "leaflet": "^1.9.4",
         "leaflet-compass": "^1.5.6",
         "leaflet.chinatmsproviders": "^3.0.6",
+        "leaflet.markercluster": "^1.5.3",
         "lodash.kebabcase": "^4.1.1",
         "pinia": "^2.3.0",
         "proj4": "^2.19.10",
@@ -9140,7 +9141,7 @@
     },
     "node_modules/leaflet": {
       "version": "1.9.4",
-      "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
+      "resolved": "https://registry.npmmirror.com/leaflet/-/leaflet-1.9.4.tgz",
       "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
       "license": "BSD-2-Clause"
     },
@@ -9159,6 +9160,15 @@
       "integrity": "sha512-B4UPSn2MT//RkFoyrVjwqQyfKuf4tSmMjJDKQ6nqwCCGgirYKRWHafSH9JmA88WoG5pkuMXBcKQhY32FobxU/g==",
       "license": "MIT"
     },
+    "node_modules/leaflet.markercluster": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmmirror.com/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz",
+      "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==",
+      "license": "MIT",
+      "peerDependencies": {
+        "leaflet": "^1.3.1"
+      }
+    },
     "node_modules/levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz",

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
     "leaflet": "^1.9.4",
     "leaflet-compass": "^1.5.6",
     "leaflet.chinatmsproviders": "^3.0.6",
+    "leaflet.markercluster": "^1.5.3",
     "lodash.kebabcase": "^4.1.1",
     "pinia": "^2.3.0",
     "proj4": "^2.19.10",

File diff suppressed because it is too large
+ 1 - 0
public/data/韶关市乡镇划分图5.geojson


BIN
src/assets/videos/农业投入品.mp4


BIN
src/assets/videos/地下渗漏.mp4


BIN
src/assets/videos/地表径流.mp4


BIN
src/assets/videos/干湿沉降.mp4


BIN
src/assets/videos/灌溉水.mp4


BIN
src/assets/videos/秸秆移除.mp4


BIN
src/assets/videos/籽粒移除.mp4


BIN
src/assets/videos/输入总通量.mp4


BIN
src/assets/videos/输出总通量.mp4


+ 1 - 1
src/components/atmpollution/airsampleLine.vue

@@ -170,7 +170,7 @@ const weightColumns = [
   { key: 'Cr_particulate', label: 'Cr mg/kg', type: 'number', width: '80px' },
   { key: 'As_particulate', label: 'As mg/kg', type: 'number', width: '80px' },
   { key: 'Cd_particulate', label: 'Cd mg/kg', type: 'number', width: '80px' },
-  { key: 'Hg_particulate', label: 'Hg mg/kg', type: 'number', width: '80px' },
+  { key: 'Hg_particulate', label: 'Hg mg/kg', type: 'number', width: '85px' },
   { key: 'Pb_particulate', label: 'Pb mg/kg', type: 'number', width: '80px' },
   { key: 'particle_weight', label: '颗粒物重量 mg', type: 'number', width: '140px' },
 ];

+ 6 - 6
src/components/atmpollution/atmcompanymap.vue

@@ -62,8 +62,8 @@ onMounted(() => {
     return '#cccccc';
   }
 
-  // 只加载乡镇级GeoJSON,并根据所属区县着色
-  fetch('/data/韶关市乡镇划分图.geojson')
+  // 只加载乡镇级GeoJSON,并根据所属区县着色http://localhost:8000/api/vector/export/all?table_name=town&format=geojson
+  fetch('./data/韶关市乡镇划分图5.geojson')
     .then(res => {
       if (!res.ok) throw new Error(`乡镇划分图加载失败:${res.status}`);
       return res.json();
@@ -83,7 +83,7 @@ onMounted(() => {
         },
         
       }).addTo(map);
-      console.log('✅ 乡镇划分图加载完成,已按所属区县着色');
+      //console.log('✅ 乡镇划分图加载完成,已按所属区县着色');
     })
     .catch(err => {
       console.error('❌ 乡镇划分图加载失败:', err);
@@ -105,7 +105,7 @@ onMounted(() => {
       
       const geoJSONData = JSON.parse(fixedText);
       
-      console.log('✅ 接口数据加载完成,共', geoJSONData.features.length, '条记录');
+      //console.log('✅ 接口数据加载完成,共', geoJSONData.features.length, '条记录');
       
       let markerCount = 0;
       geoJSONData.features.forEach((feature, idx) => {
@@ -146,7 +146,7 @@ onMounted(() => {
         }
       });
 
-      console.log(`✅ 成功创建 ${markerCount} 个有效标记`);
+      //console.log(`✅ 成功创建 ${markerCount} 个有效标记`);
     })
     .catch(err => {
       console.error('❌ 接口数据加载失败:', err);
@@ -156,7 +156,7 @@ onMounted(() => {
   map.on('load', () => {
     setTimeout(() => {
       map.invalidateSize();
-      console.log('✅ 地图尺寸已重新计算');
+      //console.log('✅ 地图尺寸已重新计算');
     }, 300);
   });
 

+ 20 - 18
src/components/atmpollution/atmsamplemap.vue

@@ -149,14 +149,14 @@ onMounted(() => {
     "乳源": "#FF9F1C" // 可选:支持归一化后匹配(如GeoJSON是“乳源”时)
   };
 
-  // 加载区县边界(关键修改:匹配FXZQMC字段 + 归一化)
-  fetch('/data/韶关市乡镇划分图.geojson')
+  // 加载区县边界(关键修改:匹配FXZQMC字段 + 归一化)http://localhost:8000/api/vector/export/all?table_name=town_boundary&format=geojsonhttp://localhost:8000/api/vector/export/all?table_name=town&format=geojson
+  fetch('./data/韶关市乡镇划分图5.geojson')
     .then(res => {
       if (!res.ok) throw new Error(`区县边界加载失败:${res.status}`);
       return res.json();
     })
     .then(geojson => {
-      console.log('✅ 区县边界数据加载完成,要素数:', geojson.features.length);
+      //console.log('✅ 区县边界数据加载完成,要素数:', geojson.features.length);
       
       L.geoJSON(geojson, {
         style: (feature) => {
@@ -186,16 +186,22 @@ onMounted(() => {
           const validJsonText = text.replace(/NaN/g, 'null');
           
           try {
-            const geojsonData = JSON.parse(validJsonText);
-            const atmosphereData = geojsonData.features.map(feature => feature.properties);
-            console.log('✅ 大气数据加载完成,记录数:', atmosphereData.length);
-            markers.value = []; 
-            
-            atmosphereData.forEach((item, idx) => {
-              try {
-                // 提取经纬度(兼容 properties 和 geometry)
-                let lat = item.latitude;
-                let lng = item.longitude;
+            return JSON.parse(validJsonText);
+          } catch (err) {
+            console.error('❌ JSON 解析失败(原始数据含非法值):', err);
+            throw new Error('数据格式错误,请检查服务端返回');
+          }
+        })
+        .then(geojsonData => {
+          const atmosphereData = geojsonData.features.map(feature => feature.properties);
+          //console.log('✅ 大气数据加载完成,记录数:', atmosphereData.length);
+          markers.value = []; 
+          
+          atmosphereData.forEach((item, idx) => {
+            try {
+              // 提取经纬度(兼容 properties 和 geometry)
+              let lat = item.latitude;
+              let lng = item.longitude;
 
                 if (lat === undefined || lng === undefined) {
                   if (item.geometry && item.geometry.type === 'Point' && item.geometry.coordinates.length === 2) {
@@ -228,10 +234,6 @@ onMounted(() => {
                 console.error(`❌ 处理大气数据失败(第${idx}条):`, err);
               }
             });
-          } catch (parseErr) {
-            console.error('❌ JSON 解析失败(原始数据含非法值):', parseErr);
-            throw new Error('数据格式错误,请检查服务端返回');
-          }
         })
         .catch(err => {
           console.error('❌ 大气数据加载失败:', err);
@@ -251,7 +253,7 @@ watch(
     markers.value.forEach(({ marker, item }) => {
       marker.bindPopup(generatePopupContent(item, newMethod));
     });
-    console.log(`✅ 已切换为${newMethod === 'weight' ? '重量' : '体积'}计算方式,弹窗内容已更新`);
+    //console.log(`✅ 已切换为${newMethod === 'weight' ? '重量' : '体积'}计算方式,弹窗内容已更新`);
   }
 );
 </script>

+ 2 - 2
src/components/atmpollution/heavyMetalEnterprisechart.vue

@@ -23,7 +23,7 @@
       ref="chartRef" 
       class="chart-box"
       :style="{ 
-        height: '500px', 
+        height: '100%', 
         border: '2px solid #1890ff', 
         position: 'relative' 
       }"
@@ -371,7 +371,7 @@ onUnmounted(() => window.removeEventListener('resize', handleResize));
 /* 图表容器 */
 .chart-box {
   width: 100%;
-  min-height: 500px !important; /* 强制最小高度 */
+  min-height: 500px ; /* 强制最小高度 */
   border-radius: 8px;
   overflow: hidden;
 }

+ 1 - 1
src/components/detectionStatistics/atmsampleStatistics.vue

@@ -136,7 +136,7 @@ export default {
         log('发起新接口请求,获取统计数据...')
         // 使用 api8000 替代 axios
         const response = await api8000.get(apiUrl.value)
-        const apiData = response.data
+        const apiData = response.data.data
 
         // 从接口数据中提取每个重金属的统计量
         const stats = heavyMetals.map(metal => {

+ 1 - 1
src/components/detectionStatistics/irrigationstatistics.vue

@@ -151,7 +151,7 @@ export default {
       try {
         // 使用api8000替代axios
         const response = await api8000.get(apiUrl.value);
-        statsData.value = response.data; 
+        statsData.value = response.data.data; 
         apiTimestamp.value = new Date().toLocaleString();
         initChart();
       } catch (err) {

+ 2 - 2
src/components/irrpollution/waterassaydata2.vue

@@ -317,14 +317,14 @@ onUnmounted(() => {
 <style scoped>
 .region-average-chart {
   width: 100%;
-  height: 500px;
+  height: 100%;
   max-width: 1200px;
   margin: 0 auto;
   position: relative;
 }
 .chart-box {
   width: 100%;
-  height: 500px;
+  height: 100%;
   min-height: 400px;
   background-color: white;
   border-radius: 8px;

+ 15 - 15
src/components/layout/AppLayout.vue

@@ -275,6 +275,17 @@ const tabs = computed(() => {
         icon: "el-icon-info-filled",
         routes: ["/SoilPro", "/Overview", "/ResearchFindings", "/Unit"],
       },*/
+      {
+        name: "cadmiumPrediction",
+        label: "土壤污染物含量预测",
+        icon: "el-icon-c-scale-to-original",
+        routes: [
+          "/CropCadmiumPrediction",
+          "/EffectiveCadmiumPrediction",
+          "/netFlux",
+          "/currentYearConcentration",
+        ],
+      },
       {
         name: "HmOutFlux",
         label: "重金属输入通量",
@@ -318,17 +329,6 @@ const tabs = computed(() => {
         icon: "el-icon-map-location",
         routes: ["/mapView"],
       },*/
-      {
-        name: "cadmiumPrediction",
-        label: "土壤污染物含量预测",
-        icon: "el-icon-c-scale-to-original",
-        routes: [
-          "/netFlux",
-          "/currentYearConcentration",
-          "/EffectiveCadmiumPrediction",
-          "/CropCadmiumPrediction",
-        ],
-      },
       // {
       //   name: "cropRiskAssessment",
       //   label: "作物风险评估",
@@ -539,7 +539,7 @@ const mainStyle = computed(() => ({
 
 /* Header 样式 */
 .layout-header {
-  height: 150px;
+  height: 80px;
   display: flex;
   align-items: center;
   justify-content: space-between;
@@ -561,7 +561,7 @@ const mainStyle = computed(() => ({
 
 .title-and-user {
   display: flex;
-  flex-direction: column;
+  flex-direction: row;
   flex: 1;
 }
 
@@ -680,7 +680,7 @@ const mainStyle = computed(() => ({
 }
 
 .project-name {
-  font-size: 48px;
+  font-size: 36px;
   font-weight: bold;
   margin-top: 30px;
   color: #333; /* 深色文字 */
@@ -699,7 +699,7 @@ const mainStyle = computed(() => ({
 
 /* 侧边栏 - 白色背景 */
 .layout-aside {
-  width: 360px;
+  width: 280px;
   background: linear-gradient(to bottom, #b7f1fc, #fff8f0);
   border-right: 1px solid;
   overflow-y: auto;

+ 1 - 1
src/components/soilStatictics/reducedataStatistics.vue

@@ -173,7 +173,7 @@ export default {
         
         const option = {
           title: {
-            text: '随机样本点的pH值趋势图',
+            text: '酸化缓解样本点的pH值趋势图',
             left: 'center',
             top: 10
           },

+ 26 - 6
src/components/soilcdStatistics/cropcdStatictics.vue

@@ -48,7 +48,8 @@
 <script setup>
 import { ref, onMounted, nextTick } from 'vue';
 import * as echarts from 'echarts';
-import { api8000 } from '@/utils/request'; // 导入 api8000 实例
+import { api8000 } from '@/utils/request'; // 导入 api8000 实例import {api8000} from '@/utils/request'
+
 
 // 图表实例引用
 const cdBarChart = ref(null);
@@ -116,14 +117,33 @@ const fieldConfig = {
   ]
 };
 
-// 数据请求(作物态Cd接口)
+
+// 数据请求 - 增强错误处理和调试
 const fetchData = async () => {
   try {
-    const apiUrl = '/api/vector/stats/CropCd_input_data'; // 相对路径
-    const response = await api8000.get(apiUrl); // 使用 api8000
-    return response.data;
+    isLoading.value = true;
+    const apiUrl = '/api/vector/stats/CropCd_input_data';
+    console.log('正在请求数据:', apiUrl);
+    
+    const response = await api8000.get(apiUrl);
+    console.log('API响应:', response);
+    
+    // 调试:输出响应结构
+    console.log('响应数据:', response.data);
+    
+    // 处理不同的响应格式
+    let processedData;
+    processedData = response.data.data;
+    
+    if (!processedData) {
+      throw new Error('无法解析API返回的数据结构');
+    }
+    
+    console.log('处理后的数据:', processedData);
+    return processedData;
   } catch (err) {
-    throw new Error('数据加载失败: ' + err.message);
+    console.error('数据请求失败:', err);
+    throw new Error(`数据加载失败: ${err.message || '网络或服务器错误'}`);
   }
 };
 

+ 22 - 5
src/components/soilcdStatistics/effcdStatistics.vue

@@ -100,14 +100,31 @@ const fieldConfig = {
   ]
 };
 
-// 数据请求
 const fetchData = async () => {
   try {
-    // 使用 api8000 替代 axios
-    const res = await api8000.get("/api/vector/stats/EffCd_input_data");
-    return res.data;
+    isLoading.value = true;
+    const apiUrl = '/api/vector/stats/EffCd_input_data';
+    console.log('正在请求数据:', apiUrl);
+    
+    const response = await api8000.get(apiUrl);
+    console.log('API响应:', response);
+    
+    // 调试:输出响应结构
+    console.log('响应数据:', response.data);
+    
+    // 处理不同的响应格式
+    let processedData;
+    processedData = response.data.data;
+    
+    if (!processedData) {
+      throw new Error('无法解析API返回的数据结构');
+    }
+    
+    console.log('处理后的数据:', processedData);
+    return processedData;
   } catch (err) {
-    throw new Error('数据加载失败: ' + err.message);
+    console.error('数据请求失败:', err);
+    throw new Error(`数据加载失败: ${err.message || '网络或服务器错误'}`);
   }
 };
 

+ 27 - 56
src/components/soilcdStatistics/fluxcdStatictics.vue

@@ -85,7 +85,6 @@ const fieldConfig = {
   ]
 };
 
-// 数据请求 - 增强错误处理和调试
 const fetchData = async () => {
   try {
     isLoading.value = true;
@@ -100,24 +99,7 @@ const fetchData = async () => {
     
     // 处理不同的响应格式
     let processedData;
-    if (response.data && typeof response.data === 'object') {
-      // 情况1: 直接返回统计对象
-      if (response.data.Initial_Cd || response.data.DQCJ_Cd) {
-        processedData = response.data;
-      }
-      // 情况2: 包含features数组
-      else if (response.data.features && Array.isArray(response.data.features)) {
-        processedData = response.data.features.map(f => f.properties);
-      }
-      // 情况3: 包含data数组
-      else if (response.data.data && Array.isArray(response.data.data)) {
-        processedData = response.data.data;
-      }
-      // 情况4: 数组直接返回
-      else if (Array.isArray(response.data)) {
-        processedData = response.data;
-      }
-    }
+    processedData = response.data.data;
     
     if (!processedData) {
       throw new Error('无法解析API返回的数据结构');
@@ -131,44 +113,33 @@ const fetchData = async () => {
   }
 };
 
-// 计算统计量 - 支持原始数据和预统计数据
-const calculateFieldStats = (data, fieldKey, fieldName) => {
-  // 如果已经是预统计好的数据
-  if (data[fieldKey] && typeof data[fieldKey] === 'object') {
-    const fieldStats = data[fieldKey];
-    return {
-      key: fieldKey,
-      name: fieldName,
-      min: fieldStats.min || null,
-      q1: fieldStats.q1 || null,
-      median: fieldStats.median || null,
-      q3: fieldStats.q3 || null,
-      max: fieldStats.max || null,
-      count: fieldStats.count || 0
-    };
-  }
-  
-  // 如果是原始数据数组,需要手动计算统计量
-  if (Array.isArray(data)) {
-    const values = data
-      .map(item => parseFloat(item[fieldKey]))
-      .filter(val => !isNaN(val) && val !== null);
-    
-    if (values.length === 0) {
-      return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null, count: 0 };
-    }
-    
-    values.sort((a, b) => a - b);
-    const min = values[0];
-    const max = values[values.length - 1];
-    const median = values[Math.floor(values.length / 2)];
-    const q1 = values[Math.floor(values.length / 4)];
-    const q3 = values[Math.floor(values.length * 3 / 4)];
-    
-    return { key: fieldKey, name: fieldName, min, q1, median, q3, max, count: values.length };
+
+// 计算单个字段的统计量
+const calculateFieldStats = (statsData, fieldKey, fieldName) => {
+  // 从接口数据中获取当前字段的统计结果
+  const fieldStats = statsData[fieldKey]; 
+  if (!fieldStats) {
+    return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null };
   }
-  
-  return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null, count: 0 };
+
+  // 提取预统计值
+  let min = fieldStats.min;
+  let q1 = fieldStats.q1;
+  let median = fieldStats.median;
+  let q3 = fieldStats.q3;
+  let max = fieldStats.max;
+
+  // 强制校正统计量顺序(确保 min ≤ q1 ≤ median ≤ q3 ≤ max)
+  const sortedStats = [min, q1, median, q3, max].sort((a, b) => a - b);
+  return {
+    key: fieldKey,
+    name: fieldName,
+    min: sortedStats[0],
+    q1: sortedStats[1],
+    median: sortedStats[2],
+    q3: sortedStats[3],
+    max: sortedStats[4]
+  };
 };
 
 // 计算所有统计数据

+ 3 - 3
src/locales/zh.json

@@ -116,17 +116,17 @@
   },
   "strawRemoval": {
     "Title": "秸秆移除",
-    "samplingDesc2": "秸秆移除说明",
+    "samplingDesc2": "秸秆移除采样说明",
     "strawRemovalInputFlux": "秸秆移除输出通量"
   },
   "subsurfaceLeakage": {
     "Title": "地下渗漏",
-    "samplingDesc3": "地下渗漏说明",
+    "samplingDesc3": "地下渗漏采样说明",
     "subsurfaceLeakageInputFlux": "地下渗漏输出通量"
   },
   "surfaceRunoff": {
     "Title": "地表径流",
-    "samplingDesc4": "地表径流说明",
+    "samplingDesc4": "地表径流采样说明",
     "surfaceRunoffInputFlux": "地表径流输出通量"
   },
   "mapView": {

+ 4 - 0
src/router/index.ts

@@ -19,6 +19,10 @@ const routes = [
         path: "/:catchAll(.*)",
         redirect: "/404",
       },
+      {
+        path: '',
+        redirect: '/CropCadmiumPrediction'
+      },
       {
         path: "select-city", // remove leading slash
         name: "selectCityAndCounty",

+ 29 - 22
src/utils/request.ts

@@ -1,9 +1,9 @@
 // src/utils/request.ts
 import axios from 'axios';
-import type { 
-  AxiosInstance, 
-  AxiosRequestConfig, 
-  AxiosResponse, 
+import type {
+  AxiosInstance,
+  AxiosRequestConfig,
+  AxiosResponse,
   AxiosError,
   InternalAxiosRequestConfig,
   AxiosRequestHeaders
@@ -19,24 +19,24 @@ interface CustomAxiosInstance extends AxiosInstance {
 
 // 创建API客户端
 export const api5000: CustomAxiosInstance = axios.create({
-  baseURL: isDevelopment 
-    ? 'http://localhost:5000' 
+  baseURL: isDevelopment
+    ? 'http://localhost:5000'
     : 'https://www.soilgd.com:5000',
   timeout: 100000,
   withCredentials: true  // 关键修改:除非需要cookie,否则设为false
 });
 
 export const api8000: CustomAxiosInstance = axios.create({
-  baseURL: isDevelopment 
-    ? 'http://localhost:8000' 
+  baseURL: isDevelopment
+    ? 'http://localhost:8000'
     : 'https://www.soilgd.com:8000',
   timeout: 100000,
   withCredentials: true
 });
 
 export const apiMain: CustomAxiosInstance = axios.create({
-  baseURL: isDevelopment 
-    ? 'http://localhost' 
+  baseURL: isDevelopment
+    ? 'http://localhost'
     : 'https://www.soilgd.com',
   timeout: 100000,
   withCredentials: true
@@ -48,9 +48,9 @@ function isGeoJSONResponse(response: AxiosResponse): boolean {
   const contentType = response.headers['content-type'] || '';
   return (
     contentType.includes('application/geo+json') ||
-    (contentType.includes('application/json') && 
-     (response.data?.type === 'FeatureCollection' || 
-      response.data?.type === 'Feature'))
+    (contentType.includes('application/json') &&
+      (response.data?.type === 'FeatureCollection' ||
+        response.data?.type === 'Feature'))
   );
 }
 
@@ -65,30 +65,33 @@ const setupInterceptors = (instance: CustomAxiosInstance) => {
         }
         config.headers.set('Authorization', `Bearer ${token}`);
       }
-      
+
+      // 为GeoJSON请求设置Accept头
       if (config.url?.match(/\/geojson|\/vector/i)) {
         if (!config.headers) {
           config.headers = new axios.AxiosHeaders();
         }
         config.headers.set('Accept', 'application/geo+json, application/json');
+
+        // 为GeoJSON请求设置更长的超时时间
         if (!config.timeout || config.timeout < 180000) {
           config.timeout = 180000;
         }
       }
-      
+
       return config;
     },
     (error: AxiosError) => Promise.reject(error)
   );
-  
-  // 响应拦截器 (修改部分)
+
+  // 响应拦截器
   instance.interceptors.response.use(
     (response: AxiosResponse) => {
       const contentType = response.headers['content-type'] || '';
       const isBlob = response.config.responseType === 'blob';
       const isImage = contentType.includes('image/');
       const isJSON = contentType.includes('application/json');
-      
+
       console.log('响应处理:', {
         url: response.config.url,
         responseType: response.config.responseType,
@@ -97,20 +100,24 @@ const setupInterceptors = (instance: CustomAxiosInstance) => {
         isImage,
         isJSON
       });
-      
+
+      // 1. 处理二进制响应(图片/文件下载)
       if (isBlob || isImage) {
         return response;
       }
-      
+
+      // 2. 处理GeoJSON响应(新增部分)
       if (isGeoJSONResponse(response)) {
         console.log('检测到GeoJSON响应,返回完整响应对象');
         return response;
       }
-      
+
+      // 3. 处理普通JSON响应
       if (isJSON) {
         return response;
       }
-      
+
+      // 4. 其他类型响应
       return response;
     },
     (error: AxiosError) => {

+ 100 - 0
src/views/User/HmOutFlux/agriInput/farmInputSamplingDesc.vue

@@ -175,6 +175,22 @@
         </div>
       </div>
     </div>
+
+    <div class="process-section">
+      <div class="section-header">
+        <div class="section-number">5</div>
+        <h2>农业投入品输入过程视频演示</h2>
+      </div>
+      
+      <div class="video-section">
+        <div class="video-container">
+          <video controls class="sampling-video">
+            <source src='@/assets/videos/农业投入品.mp4' type="video/mp4">
+            您的浏览器不支持HTML5视频播放。
+          </video>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -596,4 +612,88 @@ h2 {
     max-height: 250px;
   }
 }
+/* 新增视频模块样式 */
+.video-section {
+  display: flex;
+  flex-direction: column;
+  gap: 30px;
+  margin-top: 20px;
+}
+
+.video-container {
+  border-radius: 12px;
+  overflow: hidden;
+  position: relative;
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+  max-width: 800px;
+  margin: 0 auto;
+  transition: all 0.4s ease;
+}
+
+.video-container:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
+}
+
+.sampling-video {
+  width: 100%;
+  height: auto;
+  display: block;
+  background: #f8fafc;
+  min-height: 400px;
+}
+
+.video-caption {
+  text-align: center;
+  font-size: 1.1rem;
+  color: #1a365d;
+  padding: 15px;
+  font-weight: 600;
+  background: linear-gradient(to right, rgba(248, 250, 252, 0.9), rgba(240, 248, 255, 0.9));
+  margin: 0;
+  border-top: 1px dashed #cbd5e0;
+  position: relative;
+}
+
+.video-caption::before {
+  content: "📹";
+  position: absolute;
+  left: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+.video-description {
+  background: rgba(245, 249, 255, 0.6);
+  border-radius: 12px;
+  padding: 20px;
+  border-left: 4px solid #3acfd5;
+}
+
+.video-description h3 {
+  color: #1a365d;
+  margin-top: 0;
+  margin-bottom: 15px;
+  font-size: 1.4rem;
+}
+
+.video-description ul {
+  padding-left: 25px;
+  margin: 15px 0;
+}
+
+.video-description li {
+  margin-bottom: 10px;
+  line-height: 1.7;
+  position: relative;
+}
+
+.video-description li::before {
+  content: "•";
+  color: #3acfd5;
+  font-size: 1.2rem;
+  position: absolute;
+  left: -20px;
+  top: 0;
+}
 </style>

+ 22 - 10
src/views/User/HmOutFlux/atmosDeposition/airSampleData.vue

@@ -3,6 +3,7 @@
     <!-- 系统标题区域 -->
     <div class="header-section">
       <div class="header-content">
+        <div class="section-icon">📊</div>
         <h1 class="system-title">韶关市大气重金属污染采样</h1>
         <div class="calculation-selector">
           <span class="selector-title">采样方式:</span>
@@ -99,7 +100,10 @@ const toggleMapType = () => {
 
 /* 页眉区域 */
 .header-section {
-   text-align: center;
+   display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 20px;
   position: relative;
 }
 
@@ -110,18 +114,24 @@ const toggleMapType = () => {
 }
 
 .system-title {
-  color: #1a365d;
-  font-size: 2.8rem;
-  margin-bottom: 12px;
+  font-size: 2.2rem;
   font-weight: 700;
-  letter-spacing: 0.5px;
-  text-shadow: 0 2px 4px rgba(0,0,0,0.05);
+  color: #1a365d;
+  position: relative;
+  padding-left: 15px;
+  flex-grow: 1;
+  margin-right: 260px;
 }
 
-.system-subtitle {
-  font-size: 1.3rem;
-  color: #cbd5e0;
-  margin: 0;
+.system-title::after {
+  content: "";
+  position: absolute;
+  bottom: -8px;
+  left: 0;
+  width: 100px;
+  height: 4px;
+  background: linear-gradient(90deg, #4a9ef7, #3acfd5);
+  border-radius: 2px;
 }
 
 .calculation-selector {
@@ -129,6 +139,8 @@ const toggleMapType = () => {
   align-items: center;
   gap: 15px;
   margin-top: 20px;
+  margin-left: auto;
+  margin-right: 0;
 }
 
 .selector-icon {

+ 21 - 10
src/views/User/HmOutFlux/atmosDeposition/heavyMetalEnterprise.vue

@@ -3,6 +3,7 @@
     <!-- 页面标题区域 -->
     <div class="header-section">
       <div class="header-content">
+        <div class="section-icon">📊</div>
         <h1 class="system-title">韶关市涉重企业重金属排放调查</h1>
       </div>
     </div>
@@ -83,7 +84,10 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
 
 /* 页眉区域 */
 .header-section {
- text-align: center;
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 20px;
   position: relative;
 }
 
@@ -94,20 +98,27 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
 }
 
 .system-title {
-  color: #1a365d;
-  font-size: 2.8rem;
-  margin-bottom: 12px;
+  font-size: 2.2rem;
   font-weight: 700;
-  letter-spacing: 0.5px;
-  text-shadow: 0 2px 4px rgba(0,0,0,0.05);
+  color: #1a365d;
+  margin: 0;
+  position: relative;
+  padding-left: 15px;
+  flex-grow: 1;
 }
 
-.system-subtitle {
-  font-size: 1.3rem;
-  color: #cbd5e0;
-  margin: 10px 0 0;
+.system-title::after {
+  content: "";
+  position: absolute;
+  bottom: -8px;
+  left: 0;
+  width: 100px;
+  height: 4px;
+  background: linear-gradient(90deg, #4a9ef7, #3acfd5);
+  border-radius: 2px;
 }
 
+
 .header-actions {
   display: flex;
   gap: 15px;

+ 2 - 3
src/views/User/HmOutFlux/irrigationWater/crossSection.vue

@@ -89,7 +89,7 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
   min-height: 100vh;
   background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
   padding: 25px;
-  gap: 30px;
+  gap: 20px;
   position: relative;
   overflow-x: hidden;
 }
@@ -133,7 +133,7 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 .dashboard-section {
   display: flex;
   flex-direction: column;
-  gap: 20px;
+  margin-bottom: 30px;
 }
 
 /* 卡片设计 */
@@ -211,7 +211,6 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 .chart-header p {
   font-size: 1rem;
   color: #718096;
-  margin: 0;
 }
 
 /* 组件标题 */

+ 26 - 14
src/views/User/HmOutFlux/irrigationWater/irriWaterSampleData.vue

@@ -1,13 +1,9 @@
 <template>
   <div class="page-container">
     <!-- 页眉设计 -->
-    <div class="header">
-      <div class="header-content">
-        <div class="header-left">
-          <h1>灌溉水采样点分析系统</h1>
-        </div>
-      </div>
-      <div class="header-divider"></div>
+    <div class="section-header">
+        <div class="section-icon">📊</div>
+        <h1 class="page-title">灌溉水采样点分析</h1>
     </div>
 
     <!-- 主内容区 -->
@@ -78,6 +74,27 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
   overflow-x: hidden;
 }
 
+.page-title {
+  font-size: 2.2rem;
+  font-weight: 700;
+  color: #1a365d;
+  margin: 0;
+  position: relative;
+  padding-left: 15px;
+  flex-grow: 1;
+}
+
+.page-title::after {
+  content: "";
+  position: absolute;
+  bottom: -8px;
+  left: 0;
+  width: 100px;
+  height: 4px;
+  background: linear-gradient(90deg, #4a9ef7, #3acfd5);
+  border-radius: 2px;
+}
+
 /* 页眉样式 */
 .header {
   border-radius: 16px;
@@ -135,11 +152,6 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
   font-weight: 500;
 }
 
-.header-divider {
-  height: 1px;
-  background: linear-gradient(90deg, transparent, #cbd5e0, transparent);
-}
-
 /* 主内容区 */
 .main-content {
   display: flex;
@@ -158,11 +170,11 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
   align-items: center;
   gap: 15px;
   margin-bottom: 20px;
-  padding: 0 10px;
+  position: relative;
 }
 
 .section-icon {
-  font-size: 2rem;
+  font-size: 2.5rem;
   color: #3a9fd3;
 }
 

+ 99 - 0
src/views/User/HmOutFlux/irrigationWater/samplingMethodDevice1.vue

@@ -95,6 +95,21 @@
         </div>
       </div>
     </div>
+    <div class="section-container">
+      <div class="section-header">
+        <div class="section-number">3</div>
+        <h2>灌溉水输入过程视频演示</h2>
+      </div>
+      
+      <div class="video-section">
+        <div class="video-container">
+          <video controls class="sampling-video">
+            <source src='@/assets/videos/灌溉水.mp4' type="video/mp4">
+            您的浏览器不支持HTML5视频播放。
+          </video>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -383,4 +398,88 @@ h2 {
     height: 200px;
   }
 }
+/* 新增视频模块样式 */
+.video-section {
+  display: flex;
+  flex-direction: column;
+  gap: 30px;
+  margin-top: 20px;
+}
+
+.video-container {
+  border-radius: 12px;
+  overflow: hidden;
+  position: relative;
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+  max-width: 800px;
+  margin: 0 auto;
+  transition: all 0.4s ease;
+}
+
+.video-container:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
+}
+
+.sampling-video {
+  width: 100%;
+  height: auto;
+  display: block;
+  background: #f8fafc;
+  min-height: 400px;
+}
+
+.video-caption {
+  text-align: center;
+  font-size: 1.1rem;
+  color: #1a365d;
+  padding: 15px;
+  font-weight: 600;
+  background: linear-gradient(to right, rgba(248, 250, 252, 0.9), rgba(240, 248, 255, 0.9));
+  margin: 0;
+  border-top: 1px dashed #cbd5e0;
+  position: relative;
+}
+
+.video-caption::before {
+  content: "📹";
+  position: absolute;
+  left: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+.video-description {
+  background: rgba(245, 249, 255, 0.6);
+  border-radius: 12px;
+  padding: 20px;
+  border-left: 4px solid #3acfd5;
+}
+
+.video-description h3 {
+  color: #1a365d;
+  margin-top: 0;
+  margin-bottom: 15px;
+  font-size: 1.4rem;
+}
+
+.video-description ul {
+  padding-left: 25px;
+  margin: 15px 0;
+}
+
+.video-description li {
+  margin-bottom: 10px;
+  line-height: 1.7;
+  position: relative;
+}
+
+.video-description li::before {
+  content: "•";
+  color: #3acfd5;
+  font-size: 1.2rem;
+  position: absolute;
+  left: -20px;
+  top: 0;
+}
 </style>

+ 99 - 0
src/views/User/HmOutFlux/totalInputFluxDesc.vue

@@ -32,6 +32,21 @@
         </div>
       </div>
     </div>
+    <div class="content-section">
+      <div class="section-header">
+        <div class="section-number">2</div>
+        <h2>总通量输入过程视频演示</h2>
+      </div>
+      
+      <div class="video-section">
+        <div class="video-container">
+          <video controls class="sampling-video">
+            <source src='@/assets/videos/输入总通量.mp4' type="video/mp4">
+            您的浏览器不支持HTML5视频播放。
+          </video>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -364,4 +379,88 @@ h2 {
     font-size: 1.5rem;
   }
 }
+/* 新增视频模块样式 */
+.video-section {
+  display: flex;
+  flex-direction: column;
+  gap: 30px;
+  margin-top: 20px;
+}
+
+.video-container {
+  border-radius: 12px;
+  overflow: hidden;
+  position: relative;
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+  max-width: 800px;
+  margin: 0 auto;
+  transition: all 0.4s ease;
+}
+
+.video-container:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
+}
+
+.sampling-video {
+  width: 100%;
+  height: auto;
+  display: block;
+  background: #f8fafc;
+  min-height: 400px;
+}
+
+.video-caption {
+  text-align: center;
+  font-size: 1.1rem;
+  color: #1a365d;
+  padding: 15px;
+  font-weight: 600;
+  background: linear-gradient(to right, rgba(248, 250, 252, 0.9), rgba(240, 248, 255, 0.9));
+  margin: 0;
+  border-top: 1px dashed #cbd5e0;
+  position: relative;
+}
+
+.video-caption::before {
+  content: "📹";
+  position: absolute;
+  left: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+.video-description {
+  background: rgba(245, 249, 255, 0.6);
+  border-radius: 12px;
+  padding: 20px;
+  border-left: 4px solid #3acfd5;
+}
+
+.video-description h3 {
+  color: #1a365d;
+  margin-top: 0;
+  margin-bottom: 15px;
+  font-size: 1.4rem;
+}
+
+.video-description ul {
+  padding-left: 25px;
+  margin: 15px 0;
+}
+
+.video-description li {
+  margin-bottom: 10px;
+  line-height: 1.7;
+  position: relative;
+}
+
+.video-description li::before {
+  content: "•";
+  color: #3acfd5;
+  font-size: 1.2rem;
+  position: absolute;
+  left: -20px;
+  top: 0;
+}
 </style>

File diff suppressed because it is too large
+ 788 - 35
src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue


+ 212 - 17
src/views/User/cadmiumPrediction/EffectiveCadmiumPrediction.vue

@@ -37,6 +37,9 @@
         <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="!statisticsData.length" @click="exportData">
+          <el-icon class="upload-icon"><Download /></el-icon>
+          导出数据</el-button>
       </div>
     </div>
 
@@ -56,6 +59,43 @@
         </div>
       </div>
       
+      <!-- 统计图表区域 -->
+      <div class="stats-area">
+        <h3>有效态Cd预测统计信息</h3>
+        <div class="model-info">
+          <el-tag type="info">{{ modelInfo.modelType || '有效Cd预测模型' }}</el-tag>
+          <span class="update-time">
+            最后更新: {{ modelInfo.updateTime ? new Date(modelInfo.updateTime).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>
+        
+        <div v-if="!loadingStats && !statisticsData.length" class="no-data">
+          <el-icon><DataAnalysis /></el-icon>
+          <p>暂无统计数据</p>
+        </div>
+      </div>
+    </div>
+
       <!-- 直方图区域 - 单独一行,放在统计信息下面 -->
       <div class="histogram-section">
         <h3>有效态Cd预测直方图</h3>
@@ -69,7 +109,6 @@
           <p>暂无直方图数据</p>
         </div>
       </div>
-    </div>
   </div>
 </template>
 
@@ -79,13 +118,13 @@ import { saveAs } from 'file-saver';
 import { api8000 } from '@/utils/request';
 import * as echarts from 'echarts';
 import { 
-  Loading, Upload, Picture, Histogram, Download, Document, Box 
+  Loading, Upload, Picture, Histogram, Download, Document, Box, DataAnalysis
 } from '@element-plus/icons-vue';
 
 export default {
   name: 'EffectiveCadmiumPrediction',
   components: { 
-    Loading, Upload, Picture, Histogram, Download, Document, Box 
+    Loading, Upload, Picture, Histogram, Download, Document, Box, DataAnalysis
   },
   data() {
     return {
@@ -93,6 +132,14 @@ export default {
       isCalculatingFromDB: false,
       loadingMap: false,
       loadingHistogram: false,
+      loadingStats: false,
+      statisticsData: [],
+      modelInfo: {
+        modelType: '',
+        unit: '',
+        updateTime: null,
+        dataSource: ''
+      },
       mapImageUrl: null,
       histogramImageUrl: null,
       mapBlob: null,
@@ -105,6 +152,7 @@ export default {
   mounted() {
     // 组件挂载时获取最新数据
     this.fetchLatestResults();
+    this.fetchStatistics();
   },
 
   beforeDestroy() {
@@ -126,7 +174,94 @@ export default {
         this.selectedFile = null;
       }
     },
-    
+     
+    // 格式化统计数据
+    formatStatisticsData(statsData) {
+      if (!statsData || !statsData.data) return [];
+      
+      const { 基础统计, 数据单位 } = statsData.data;
+      
+      return [
+        { 
+          name: '数据点总数', 
+          value: 基础统计.数据点总数, 
+          unit: '-', 
+          description: '样本总数' 
+        },
+        { 
+          name: '均值', 
+          value: 基础统计.均值.toFixed(4), 
+          unit: 数据单位, 
+          description: '所有样本的平均值' 
+        },
+        { 
+          name: '中位数', 
+          value: 基础统计.中位数.toFixed(4), 
+          unit: 数据单位, 
+          description: '样本的中位数值' 
+        },
+        { 
+          name: '标准差', 
+          value: 基础统计.标准差.toFixed(4), 
+          unit: 数据单位, 
+          description: '数据的离散程度' 
+        },
+        { 
+          name: '最小值', 
+          value: 基础统计.最小值.toFixed(4), 
+          unit: 数据单位, 
+          description: '样本中的最小值' 
+        },
+        { 
+          name: '最大值', 
+          value: 基础统计.最大值.toFixed(4), 
+          unit: 数据单位, 
+          description: '样本中的最大值' 
+        },
+        { 
+          name: '25%分位数', 
+          value: 基础统计['25%分位数'].toFixed(4), 
+          unit: 数据单位, 
+          description: '第一四分位数' 
+        },
+        { 
+          name: '75%分位数', 
+          value: 基础统计['75%分位数'].toFixed(4), 
+          unit: 数据单位, 
+          description: '第三四分位数' 
+        }
+      ];
+    },
+
+    // 获取统计信息
+    async fetchStatistics() {
+      try {
+        this.loadingStats = true;
+        
+        const response = await api8000.get(
+          `/api/cd-prediction/effective-cd/statistics`
+        );
+        
+        if (response.data && response.data.success) {
+          const statsData = response.data;
+          this.statisticsData = this.formatStatisticsData(statsData);
+          
+          // 设置模型信息
+          this.modelInfo = {
+            modelType: statsData.data.模型类型,
+            unit: statsData.data.数据单位,
+            updateTime: statsData.data.数据更新时间,
+            dataSource: statsData.data.数据来源
+          };
+        }
+      } catch (error) {
+        console.error('获取统计信息失败:', error);
+        this.$message.warning('获取统计信息失败');
+      } finally {
+        this.loadingStats = false;
+      }
+    },
+
     // 获取最新结果
     async fetchLatestResults() {
       try {
@@ -139,6 +274,7 @@ export default {
         // 获取最新直方图
         await this.fetchLatestHistogram();
         
+        
       } catch (error) {
         console.error('获取最新结果失败:', error);
         this.$message.error('获取最新结果失败');
@@ -216,6 +352,8 @@ export default {
         
         // 更新后重新获取直方图
         await this.fetchLatestHistogram();
+        await this.fetchStatistics();
+
         
         this.$message.success('计算完成!');
         
@@ -324,20 +462,20 @@ export default {
       URL.revokeObjectURL(link.href);
     },
     
-    // 导出数据
+     // 导出数据
     async exportData() {
       try {
-        this.$message.info('正在获取有效Cd预测数据...');
+        this.$message.info('正在获取有效Cd预测数据...');
         
         const response = await api8000.get(
-          `/api/cd-prediction/download-final-effective-cd-csv`,
+          `/api/cd-prediction/effective-cd/export-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.download = `有效Cd预测数据.csv`;
         link.click();
         URL.revokeObjectURL(link.href);
         
@@ -346,7 +484,12 @@ export default {
         console.error('导出数据失败:', error);
         this.$message.error('导出数据失败: ' + (error.response?.data?.detail || '请稍后重试'));
       }
-    }
+    },
+    
+    // 处理窗口大小变化
+    handleResize() {
+      if (this.distributionChart) this.distributionChart.resize();
+    },
   }
 };
 </script>
@@ -354,7 +497,6 @@ export default {
 <style scoped>
 .container {
   padding: 20px;
-  /* 添加70%透明度的渐变背景 */
   background: linear-gradient(
     135deg, 
     rgba(230, 247, 255, 0.7) 0%, 
@@ -370,10 +512,10 @@ export default {
   gap: 15px;
   margin-bottom: 20px;
   padding: 15px;
-  background-color: rgba(255, 255, 255, 0.8); /* 调整为半透明白色 */
+  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); /* 添加模糊效果增强半透明感 */
+  backdrop-filter: blur(5px);
 }
 
 .upload-section {
@@ -381,7 +523,7 @@ export default {
   align-items: center;
   gap: 15px;
   padding-bottom: 15px;
-  border-bottom: 1px solid rgba(0, 0, 0, 0.1); /* 调整边框透明度 */
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 }
 
 .file-name {
@@ -397,6 +539,7 @@ export default {
 .action-buttons {
   display: flex;
   gap: 10px;
+  flex-wrap: wrap;
 }
 
 .custom-button {
@@ -422,13 +565,13 @@ export default {
 
 /* 地图区域 */
 .map-section {
-  background-color: rgba(255, 255, 255, 0.8); /* 调整为半透明白色 */
+  background-color: rgba(255, 255, 255, 0.8);
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
   position: relative;
   min-height: 500px;
-  backdrop-filter: blur(5px); /* 添加模糊效果增强半透明感 */
+  backdrop-filter: blur(5px);
 }
 
 .map-image {
@@ -441,13 +584,13 @@ export default {
 
 /* 直方图区域 */
 .histogram-section {
-  background-color: rgba(255, 255, 255, 0.8); /* 调整为半透明白色 */
+  background-color: rgba(255, 255, 255, 0.8);
   border-radius: 8px;
   padding: 15px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
   position: relative;
   min-height: 500px;
-  backdrop-filter: blur(5px); /* 添加模糊效果增强半透明感 */
+  backdrop-filter: blur(5px);
 }
 
 .histogram-image {
@@ -458,6 +601,40 @@ export default {
   border-radius: 4px;
 }
 
+/* 统计区域 */
+.stats-area {
+  background-color: rgba(255, 255, 255, 0.8);
+  border-radius: 8px;
+  padding: 15px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  position: relative;
+  backdrop-filter: blur(5px);
+}
+
+.model-info {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  margin-bottom: 15px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+.update-time {
+  color: #666;
+  font-size: 14px;
+}
+
+.data-source {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-top: 15px;
+  padding-top: 15px;
+  border-top: 1px solid rgba(0, 0, 0, 0.1);
+  color: #666;
+}
+
 .loading-container {
   display: flex;
   flex-direction: column;
@@ -502,5 +679,23 @@ export default {
   .content-area {
     flex-direction: column;
   }
+  
+  .action-buttons {
+    flex-direction: column;
+    align-items: stretch;
+  }
+  
+  .custom-button {
+    justify-content: center;
+  }
+  
+  .upload-section {
+    flex-direction: column;
+    align-items: stretch;
+  }
+  
+  .file-name {
+    text-align: center;
+  }
 }
 </style>

+ 9 - 6
src/views/User/dataStatistics/DetectionStatistics.vue

@@ -41,12 +41,15 @@ export default {
 </script>
 <style scoped>
 .scale-wrapper {
-  transform: scale(0.9);
-  transform-origin: top left;
-  width: fit-content;
-  margin-left: 0;
-  margin-bottom: 0;
-  overflow: hidden;
+   padding: 20px;
+  /* 添加70%透明度的渐变背景 */
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 80vh;
+  box-sizing: border-box;
 }
 
 /* 核心:改为3列网格布局 */

+ 7 - 1
src/views/User/dataStatistics/LandCultivatedStatistics.vue

@@ -138,7 +138,13 @@ onMounted(async () => {
 
 .container {
   padding: 20px;
-  background: linear-gradient(135deg, rgba(230, 247, 255, 0.7) 0%, rgba(240, 248, 255, 0.7) 100%);
+  /* 添加70%透明度的渐变背景 */
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  box-sizing: border-box;
 }
 .chart-wrapper {
   width: 100%;

+ 9 - 9
src/views/User/dataStatistics/SoilCdStatistics.vue

@@ -40,15 +40,15 @@ export default {
 </script>
 <style scoped>
 .scale-wrapper {
-  transform: scale(0.9);
-  transform-origin: top left;
-  gap: 20px;
-  background: linear-gradient(135deg, rgba(230, 247, 255, 0.7) 0%, rgba(240, 248, 255, 0.7) 100%);
-  padding: 20px;
-  width: fit-content;
-  margin-left: 0;
-  margin-bottom: 0;
-  overflow: hidden;
+   padding: 20px;
+  /* 添加70%透明度的渐变背景 */
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 80vh;
+  box-sizing: border-box;
 }
 
 /* 核心:改为3列网格布局 */

+ 8 - 8
src/views/User/dataStatistics/SoilacidificationStatistics.vue

@@ -44,14 +44,14 @@ export default {
 
 /* 统一子组件外层容器:确保填充网格单元格 */
 .component-container {
-  width: 1000px;
-  height: 500px;
-  padding: 16px;
-  margin: 20px;
-  border: 1px solid #e5e7eb;
-  border-radius: 8px;
-  overflow: hidden;
-  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+  padding: 20px;
+  /* 添加70%透明度的渐变背景 */
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 60vh;
   box-sizing: border-box;
 }
 

+ 204 - 260
src/views/User/farmlandQualityAssessment/farmlandQualityAssessment.vue

@@ -1,80 +1,97 @@
 <template>
-  <div>
-    <!-- 顶部信息卡片区域 -->
-    <div class="dashboard">
-      <!-- 合并的统计与分布卡片 -->
-      <div class="dashboard-card combined-card">
-        <div class="card-title">统计与分布</div>
-        <div class="combined-content">
-          <!-- 左侧:单元统计 -->
-          <div class="statistics-section">
-            <h3>单元统计</h3>
-            <div class="statistics">
-              <div class="stat-item">
-                <div class="stat-value">{{ statistics.total_units }}</div>
-                <div class="stat-label">总单元数</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">{{ statistics.units_with_data }}</div>
-                <div class="stat-label">有数据单元</div>
-              </div>
-              <!-- 仅当无数据单元数不为0时显示 -->
-              <div class="stat-item" v-if="statistics.units_without_data !== 0">
-                <div class="stat-value">{{ statistics.units_without_data }}</div>
-                <div class="stat-label">无数据单元</div>
+  <div class="agricultural-input-management">
+    <div class="page-container">
+      <!-- 顶部信息卡片区域 -->
+      <div class="dashboard">
+        <!-- 合并的统计与分布卡片 -->
+        <div class="dashboard-card combined-card">
+          <div class="card-title">统计与分布</div>
+          <div class="combined-content">
+            <!-- 左侧:单元统计 -->
+            <div class="statistics-section">
+              <h3>单元统计</h3>
+              <div class="statistics">
+                <div class="stat-item">
+                  <div class="stat-value">{{ statistics.total_units }}</div>
+                  <div class="stat-label">总单元数</div>
+                </div>
+                <div class="stat-item">
+                  <div class="stat-value">{{ statistics.units_with_data }}</div>
+                  <div class="stat-label">有数据单元</div>
+                </div>
+                <!-- 仅当无数据单元数不为0时显示 -->
+                <div class="stat-item" v-if="statistics.units_without_data !== 0">
+                  <div class="stat-value">{{ statistics.units_without_data }}</div>
+                  <div class="stat-label">无数据单元</div>
+                </div>
               </div>
             </div>
-          </div>
-          
-          <!-- 右侧:分类分布 -->
-          <div class="distribution-section">
-            <h3>分类分布</h3>
-            <div class="distribution">
-              <div v-for="(count, category) in statistics.category_distribution" :key="category" 
-                  class="category-dist" :style="{ backgroundColor: categoryColors[category] }">
-                <div class="dist-category">{{ category }}</div>
-                <div class="dist-count">{{ count }}</div>
+            
+            <!-- 右侧:分类分布 -->
+            <div class="distribution-section">
+              <h3>分类分布</h3>
+              <div class="distribution">
+                <div v-for="(count, category) in statistics.category_distribution" :key="category" 
+                    class="category-dist" :style="{ backgroundColor: categoryColors[category] }">
+                  <div class="dist-category">{{ category }}</div>
+                  <div class="dist-count">{{ count }}</div>
+                </div>
               </div>
             </div>
           </div>
         </div>
+        
+        <!-- 饼图卡片 -->
+        <div class="dashboard-card chart-card">
+          <div class="card-title">点位分类分布</div>
+          <div ref="pointPieChart" class="chart"></div>
+        </div>
       </div>
       
-      <!-- 饼图卡片 -->
-      <div class="dashboard-card chart-card">
-        <div class="card-title">点位分类分布</div>
-        <div ref="pointPieChart" class="chart"></div>
+      <!-- 地图区域 -->
+      <div class="map-area">
+        <div class="map-title">土壤分类分布地图</div>
+        <div class="map-container">
+          <div v-if="loadingMap" class="loading-container">
+            <el-icon class="loading-icon"><Loading /></el-icon>
+            <span>地图加载中...</span>
+            
+          </div>
+          <div v-else-if="mapError" class="error-container">
+            <el-icon class="error-icon"><Warning /></el-icon>
+            <span>{{ mapError }}</span>
+          </div>
+          
+           <div v-else class="image-container">
+              <img :src="mapImageUrl" class="map-image"></img>
+            </div>
+        </div>
       </div>
     </div>
-    
-    <!-- 地图区域 -->
-    <div class="map-area">
-      <div class="map-title">土壤分类分布地图</div>
-      <div ref="mapContainer" class="map-container"></div>
-    </div>
   </div>
 </template>
 
 <script>
 import * as echarts from 'echarts';
-import { api8000 } from '@/utils/request';  // 导入api8000
+import { api8000 } from '@/utils/request';
+import { 
+  Loading, Picture, Warning 
+} from '@element-plus/icons-vue';
 
 // 分类颜色配置
 const categoryColors = {
-  '优先保护类': 'rgba(255, 214, 0, 0.7)', // #FFD600 转换为RGBA
-  '安全利用类': 'rgba(0, 200, 83, 0.7)', // #00C853 转换为RGBA
-  '严格管控类': 'rgba(213, 0, 0, 0.7)'   // #D50000 转换为RGBA
+  '优先保护类': 'rgba(255, 214, 0, 0.7)',
+  '安全利用类': 'rgba(0, 200, 83, 0.7)',
+  '严格管控类': 'rgba(213, 0, 0, 0.7)'
 };
 
 export default {
-  name: 'CategoryMap',
+  name: 'SoilCategoryMap',
+  components: { 
+    Loading, Picture, Warning 
+  },
   data() {
     return {
-      map: null,
-      geoJSONLayer: null,
-      shaoguanBoundaryLayer:null,
-      multiPolygon: null, 
-      categoryColors,
       statistics: {
         total_units: 0,
         units_with_data: 0,
@@ -90,225 +107,68 @@ export default {
           '严格管控类': 0
         }
       },
-      groupingData: [] // 存储接口数据
+      mapImageUrl: '',
+      loadingMap: true,
+      mapError: null,
+      pieChart: null,
+      categoryColors
     };
   },
+  
   async mounted() {
-    // 获取分类数据
-    await this.fetchGroupingData();
-    
-    // 初始化地图
-    await this.initMap();
-    
-    // 初始化点位分布饼图
+    await this.fetchStatistics();
+    await this.fetchMapImage();
     this.initPointPieChart();
   },
+  
+  beforeUnmount() {
+    if (this.mapImageUrl) {
+      URL.revokeObjectURL(this.mapImageUrl);
+    }
+    if (this.pieChart) {
+      this.pieChart.dispose();
+    }
+  },
+  
   methods: {
-    // 获取分类数据
-    async fetchGroupingData() {
+    // 从API获取统计数据
+    async fetchStatistics() {
       try {
-        const response = await api8000.get(`/api/unit-grouping/h_xtfx`);
+        const response = await api8000.get('/api/unit-grouping/statistics');
         
         if (response.data.success) {
-          this.groupingData = response.data.data;
           this.statistics = response.data.statistics;
         }
       } catch (error) {
-        console.error('获取分类数据失败:', error);
-      }
-    },
-    
-    // 初始化地图
-    async initMap() {
-      // 加载TMap SDK
-      const TMap = await this.loadSDK();
-      
-      // 创建地图实例
-      this.map = new TMap.Map(this.$refs.mapContainer, {
-        center: new TMap.LatLng(24.81088, 113.59762),
-        zoom: 12,
-        mapStyleId: 'style1'
-      });
-      
-      // 加载GeoJSON数据
-      const geojsonData = await this.loadGeoJSON('/data/单元格.geojson');
-      
-      // 初始化GeoJSON图层 - 传递TMap对象
-      this.initMapWithGeoJSON(geojsonData, TMap);
-
-      //加载并初始化韶关边界图层
-      const shaoguanBoundaryGeojson = await this.fetchShaoguanBoundary();
-      this.initShaoguanBoundaryLayer(shaoguanBoundaryGeojson,TMap);
-    },
-    
-    // 加载SDK
-    loadSDK() {
-      return new Promise((resolve, reject) => {
-        if (window.TMap) return resolve(window.TMap);
-        
-        const script = document.createElement('script');
-        script.src = `https://map.qq.com/api/gljs?v=2.exp&libraries=basic,service,vector&key=${import.meta.env.VITE_TMAP_KEY}&callback=initTMap`;
-        
-        window.initTMap = () => {
-          if (!window.TMap) {
-            reject(new Error('TMap SDK 加载失败'));
-            return;
-          }
-          resolve(window.TMap);
-        };
-        
-        script.onerror = (err) => {
-          reject(new Error('加载地图SDK失败'));
-          document.head.removeChild(script);
-        };
-        
-        document.head.appendChild(script);
-      });
-    },
-
-    // 新增:获取韶关市边界GeoJSON数据
-  async fetchShaoguanBoundary() {
-    try {
-      // 替换为用户实际的韶关市边界接口地址
-      const boundaryUrl = "http://localhost:8000/api/vector/boundary?table_name=counties&field_name=city_name&field_value=%E9%9F%B6%E5%85%B3%E5%B8%82"; 
-      const response = await fetch(boundaryUrl);
-      
-      if (!response.ok) {
-        throw new Error(`获取韶关市边界失败: ${response.statusText}`);
+        console.error('获取统计信息失败:', error);
       }
-      
-      const boundaryGeoJSON = await response.json();
-      // 验证GeoJSON格式(必须是FeatureCollection,geometry为Polygon/MultiPolygon)
-      if (boundaryGeoJSON.type !== "FeatureCollection") {
-        throw new Error("韶关市边界数据不是有效的FeatureCollection");
-      }
-      return boundaryGeoJSON;
-    } catch (error) {
-      console.error("韶关市边界数据加载失败:", error);
-      return { type: "FeatureCollection", features: [] }; // 返回空数据避免地图崩溃
-    }
-  },
-  
-  // 新增:初始化韶关市边界图层
-  initShaoguanBoundaryLayer(boundaryGeoJSON, TMap) {
-    try {
-      if (!boundaryGeoJSON.features.length) {
-        console.warn("韶关市边界数据为空,不渲染边界");
-        return;
-      }
-
-       const lightEarthYellow = "rgba(245, 222, 179, 0.4)";
-
-      // 创建边界图层(独立于单元格图层)
-      this.shaoguanBoundaryLayer = new TMap.vector.GeoJSONLayer({
-        map: this.map, // 绑定到现有地图实例
-        data: boundaryGeoJSON, // 边界GeoJSON数据
-        // 边界样式配置:突出边框,透明填充(不遮挡下方单元格)
-        polygonStyle: new TMap.PolygonStyle({
-          color: lightEarthYellow, // 填充色:透明
-          showBorder: true, // 显示边框
-          borderColor: '#000000', // 边框颜色:蓝色(醒目)
-          borderWidth: 3 // 边框宽度:3px(确保清晰)
-        })
-      });
-
-      // 确保边界图层在最上层(覆盖单元格,不遮挡交互)
-      this.shaoguanBoundaryLayer.setZIndex(1); 
-    } catch (error) {
-      console.error("初始化韶关市边界图层失败:", error);
-    }
     },
     
-    // 加载GeoJSON数据
-    async loadGeoJSON(url) {
+    // 从API获取地图图片
+    async fetchMapImage() {
       try {
-        const response = await fetch(url);
-        if (!response.ok) {
-          throw new Error(`加载GeoJSON失败: ${response.statusText}`);
-        }
-        return await response.json();
-      } catch (error) {
-        console.error('加载GeoJSON数据失败:', error);
-        return { type: 'FeatureCollection', features: [] };
-      }
-    },
-    
-    // 初始化GeoJSON图层 - 使用MultiPolygon的setStyles方法
-    initMapWithGeoJSON(geojsonData, TMap) {
-      try {
-        // 创建分类映射表
-        const categoryMap = {};
-        this.groupingData.forEach(item => {
-          categoryMap[item.OBJECTID] = item.h_xtfx;
-        });
-        
-        // 处理GeoJSON特征
-        geojsonData.features.forEach(feature => {
-          const objectId = feature.properties.OBJECTID;
-          const category = categoryMap[objectId];
-          
-          // 添加分类属性
-          feature.properties.category = category;
-        });
-        
-        // 检查TMap对象是否有效
-        if (!TMap || !TMap.PolygonStyle) {
-          throw new Error('TMap对象无效,缺少PolygonStyle');
-        }
-        
-        // 创建GeoJSON图层
-        this.geoJSONLayer = new TMap.vector.GeoJSONLayer({
-          map: this.map,
-          data: geojsonData,
-          polygonStyle: new TMap.PolygonStyle({
-            color: 'rgba(0,0,0,0)',
-            showBorder: false
-          })
-        });
-
+        this.loadingMap = true;
+        this.mapError = null;
         
-        // 获取多边形覆盖层
-        this.multiPolygon = this.geoJSONLayer.getGeometryOverlay('polygon');
-        this.multiPolygon.setMap(this.map);
-        const polygons = this.multiPolygon.getGeometries();
-        
-        // 创建样式映射
-        const styles = {};
-        
-        // 遍历所有多边形,为每个多边形设置样式和唯一ID
-        // 遍历所有多边形,为每个多边形设置样式
-        polygons.forEach((polygon) => {
-          // 直接访问properties属性
-          const properties = polygon.properties;
-          const category = properties.category;
-          
-          // 使用多边形的id作为样式ID的键
-          const styleId = `style_${polygon.id}`;
-          
-          // 根据分类设置颜色
-          const color = category ? this.categoryColors[category] : '#CCCCCC';
-          
-          // 添加样式到映射表
-          styles[styleId] = new TMap.PolygonStyle({
-            color: color,
-            showBorder: true,
-            borderColor: '#000000',
-            borderWidth: 2
-          });
-          
-          // 关键修复:为每个多边形设置样式ID(正确方式)
-          polygon.styleId = styleId; // 直接设置属性
+        // 调用visualize接口获取地图图片
+        const response = await api8000.get('/api/unit-grouping/visualize', {
+          params: {
+            area: '乐昌市',
+            level: 'county',
+            colormap: 'viridis'
+          },
+          responseType: 'blob'
         });
-        // 使用setStyles方法一次性设置所有样式
-        this.multiPolygon.setStyles(styles);
         
-        // 更新几何体以应用新样式
-        this.multiPolygon.updateGeometries(polygons);
+        // 创建图片Blob URL
+        const blob = new Blob([response.data], { type: 'image/jpeg' });
+        this.mapImageUrl = URL.createObjectURL(blob);
         
-        this.geoJSONLayer.setZIndex(100);
-      
       } catch (error) {
-        console.error('初始化GeoJSON图层失败:', error);
+        console.error('获取地图图片失败:', error);
+        this.mapError = error.response?.data?.detail || '获取地图失败';
+      } finally {
+        this.loadingMap = false;
       }
     },
     
@@ -317,10 +177,10 @@ export default {
       const chartDom = this.$refs.pointPieChart;
       if (!chartDom) return;
       
-      const chart = echarts.init(chartDom);
+      this.pieChart = echarts.init(chartDom);
       
       // 准备饼图数据
-      const pieData = Object.entries(this.statistics.category_distribution).map(([name, value]) => ({
+      const pieData = Object.entries(this.statistics.point_distribution).map(([name, value]) => ({
         name,
         value,
         itemStyle: { color: this.categoryColors[name] || '#CCCCCC' }
@@ -378,11 +238,11 @@ export default {
         ]
       };
       
-      chart.setOption(option);
+      this.pieChart.setOption(option);
       
       // 响应式调整
       window.addEventListener('resize', () => {
-        chart.resize();
+        this.pieChart.resize();
       });
     }
   }
@@ -390,11 +250,35 @@ export default {
 </script>
 
 <style scoped>
+/* 整体布局优化 */
+.agricultural-input-management {
+  padding: 20px;
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 100vh;
+  box-sizing: border-box;
+}
+
+.page-container {
+ padding: 20px;
+  /* 添加70%透明度的渐变背景 */
+  background: linear-gradient(
+    135deg, 
+    rgba(230, 247, 255, 0.7) 0%, 
+    rgba(240, 248, 255, 0.7) 100%
+  );
+  min-height: 100vh;
+  box-sizing: border-box;
+}
+
 /* 顶部信息卡片区域 */
 .dashboard {
-  display: flex;
-  flex-wrap: wrap;
+  display: grid;
   gap: 20px;
+  grid-template-columns: 1fr 1fr; /* 统计与分布占1份,饼图占1份 */
   margin-bottom: 20px;
 }
 
@@ -540,9 +424,69 @@ export default {
 
 .map-container {
   width: 100%;
-  height: 60vh; /* 调整为60vh,更紧凑 */
-  min-height: 400px; /* 降低最小高度 */
-  max-height: 700px; /* 添加最大高度限制 */
+  height: 100%;
+  min-height: 400px;
+  max-height: 700px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: #f9f9f9;
+  border-radius: 0 0 12px 12px;
+  overflow: hidden;
+}
+
+.map-image {
+  max-width: 100%;
+  max-height: 500px;
+  object-fit: contain;
+}
+
+.loading-container, .error-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  gap: 15px;
+}
+
+.loading-container {
+  color: #47C3B9;
+}
+
+.error-container {
+  color: #F56C6C;
+}
+
+.loading-icon {
+  font-size: 36px;
+  margin-bottom: 10px;
+  animation: rotate 2s linear infinite;
+}
+
+.error-icon {
+  font-size: 36px;
+  margin-bottom: 10px;
+}
+
+.no-data {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #999;
+  font-size: 16px;
+}
+
+.no-data .el-icon {
+  font-size: 48px;
+  margin-bottom: 10px;
+}
+
+@keyframes rotate {
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
 }
 
 /* 响应式调整 */

+ 1 - 1
src/views/User/hmInFlux/grainRemoval/grainRemovalInputFlux.vue

@@ -169,7 +169,7 @@ export default {
         // 获取可视化图片
         try {
           const imageResponse = await api8000.get(
-            `/api/cd-flux-removal/grain-removal/visualize?area=${encodeURIComponent(props.area)}&level=county`,
+            `/api/cd-flux-removal/grain-removal/latest-map/${encodeURIComponent(props.area)}`,
             { responseType: 'blob' }
           );
           

+ 1 - 1
src/views/User/hmInFlux/grainRemoval/samplingDesc1.vue

@@ -30,7 +30,7 @@
           
           <div class="image-card">
             <video controls class="sampling-image">
-              <source src="@/assets/videos/秸秆移除和籽粒移除.mp4" type="video/mp4">
+              <source src="@/assets/videos/籽粒移除.mp4" type="video/mp4">
               您的浏览器不支持HTML5视频播放。
             </video>
             <div class="image-info">

+ 1 - 1
src/views/User/hmInFlux/strawRemoval/samplingDesc2.vue

@@ -30,7 +30,7 @@
           
           <div class="image-card">
             <video controls class="sampling-image">
-              <source src="@/assets/videos/秸秆移除和籽粒移除.mp4" type="video/mp4">
+              <source src="@/assets/videos/秸秆移除.mp4" type="video/mp4">
               您的浏览器不支持HTML5视频播放。
             </video>
             <div class="image-info">

+ 1 - 1
src/views/User/hmInFlux/strawRemoval/strawRemovalInputFlux.vue

@@ -165,7 +165,7 @@ export default {
         // 获取可视化图片
         try {
           const imageResponse = await api8000.get(
-            `/api/cd-flux-removal/straw-removal/visualize?area=${encodeURIComponent(props.area)}&level=county`,
+            `/api/cd-flux-removal/straw-removal/latest-map/${encodeURIComponent(props.area)}`,
             { responseType: 'blob' }
           );
           

+ 1 - 1
src/views/User/hmInFlux/subsurfaceLeakage/subsurfaceLeakageInputFlux.vue

@@ -64,7 +64,7 @@ export default {
       
       try {
         const response = await api8000.get(
-          `/api/cd-flux-removal/groundwater_leaching/visualize`,
+          `/api/cd-flux-removal/groundwater_leaching/latest-map/乐昌市`,
           {
             params: {
               area: this.area,

+ 1 - 1
src/views/User/hmInFlux/surfaceRunoff/surfaceRunoffInputFlux.vue

@@ -64,7 +64,7 @@ export default {
       
       try {
         const response = await api8000.get(
-          `/api/cd-flux-removal/surface_runoff/visualize`,
+          `/api/cd-flux-removal/surface_runoff/latest-map/乐昌市`,
           {
             params: {
               area: this.area,

+ 99 - 0
src/views/User/hmInFlux/totalOutputFluxDesc.vue

@@ -33,6 +33,21 @@
         </div>
       </div>
     </div>
+     <div class="content-section">
+      <div class="section-header">
+        <div class="section-number">2</div>
+        <h2>总通量输出过程视频演示</h2>
+      </div>
+      
+      <div class="video-section">
+        <div class="video-container">
+          <video controls class="sampling-video">
+            <source src='@/assets/videos/输出总通量.mp4' type="video/mp4">
+            您的浏览器不支持HTML5视频播放。
+          </video>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -368,4 +383,88 @@ h2 {
     font-size: 1.5rem;
   }
 }
+/* 新增视频模块样式 */
+.video-section {
+  display: flex;
+  flex-direction: column;
+  gap: 30px;
+  margin-top: 20px;
+}
+
+.video-container {
+  border-radius: 12px;
+  overflow: hidden;
+  position: relative;
+  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+  max-width: 800px;
+  margin: 0 auto;
+  transition: all 0.4s ease;
+}
+
+.video-container:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
+}
+
+.sampling-video {
+  width: 100%;
+  height: auto;
+  display: block;
+  background: #f8fafc;
+  min-height: 400px;
+}
+
+.video-caption {
+  text-align: center;
+  font-size: 1.1rem;
+  color: #1a365d;
+  padding: 15px;
+  font-weight: 600;
+  background: linear-gradient(to right, rgba(248, 250, 252, 0.9), rgba(240, 248, 255, 0.9));
+  margin: 0;
+  border-top: 1px dashed #cbd5e0;
+  position: relative;
+}
+
+.video-caption::before {
+  content: "📹";
+  position: absolute;
+  left: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+.video-description {
+  background: rgba(245, 249, 255, 0.6);
+  border-radius: 12px;
+  padding: 20px;
+  border-left: 4px solid #3acfd5;
+}
+
+.video-description h3 {
+  color: #1a365d;
+  margin-top: 0;
+  margin-bottom: 15px;
+  font-size: 1.4rem;
+}
+
+.video-description ul {
+  padding-left: 25px;
+  margin: 15px 0;
+}
+
+.video-description li {
+  margin-bottom: 10px;
+  line-height: 1.7;
+  position: relative;
+}
+
+.video-description li::before {
+  content: "•";
+  color: #3acfd5;
+  font-size: 1.2rem;
+  position: absolute;
+  left: -20px;
+  top: 0;
+}
 </style>

Some files were not shown because too many files changed in this diff