Browse Source

Merge remote-tracking branch 'origin/lili' into ding

# Conflicts:
#	src/components/cdStatictics/reducedataStatistics.vue
#	src/components/cdStatictics/refluxcdStatictics.vue
#	src/components/detectionStatistics/atmcompanyStatics.vue
#	src/components/detectionStatistics/atmsampleStatistics.vue
#	src/components/detectionStatistics/crosscetionStatistics.vue
#	src/components/detectionStatistics/irrigationstatistics.vue
#	src/components/irrpollution/crossSetionData1.vue
#	src/components/irrpollution/waterassaydata1.vue
#	src/components/irrpollution/waterassaydata3.vue
#	src/components/irrpollution/waterassaydata4.vue
#	src/components/soilcdStatistics/cropcdStatictics.vue
#	src/components/soilcdStatistics/effcdStatistics.vue
#	src/components/soilcdStatistics/fluxcdStatictics.vue
#	src/views/User/HmOutFlux/irrigationWater/crossSection.vue
yangtaodemon 3 months ago
parent
commit
f1d833e731
29 changed files with 1139 additions and 853 deletions
  1. 3 2
      components.d.ts
  2. 4 5
      src/components/atmpollution/airsampleChart.vue
  3. 3 3
      src/components/atmpollution/atmsamplemap.vue
  4. 3 5
      src/components/atmpollution/heavyMetalEnterprisechart.vue
  5. 2 21
      src/components/detectionStatistics/atmcompanyStatics.vue
  6. 130 184
      src/components/detectionStatistics/atmsampleStatistics.vue
  7. 3 3
      src/components/detectionStatistics/crosscetionStatistics.vue
  8. 35 121
      src/components/detectionStatistics/irrigationstatistics.vue
  9. 6 2
      src/components/irrpollution/crossSetionData1.vue
  10. 2 2
      src/components/irrpollution/crosssectionmap.vue
  11. 2 2
      src/components/irrpollution/irrwatermap.vue
  12. 1 1
      src/components/irrpollution/waterassaydata2.vue
  13. 349 0
      src/components/soilStatictics/reducedataStatistics.vue
  14. 214 0
      src/components/soilStatictics/refluxcedataStatictics.vue
  15. 207 182
      src/components/soilcdStatistics/cropcdStatictics.vue
  16. 38 121
      src/components/soilcdStatistics/effcdStatistics.vue
  17. 26 73
      src/components/soilcdStatistics/fluxcdStatictics.vue
  18. 7 25
      src/views/User/HmOutFlux/atmosDeposition/airSampleData.vue
  19. 6 27
      src/views/User/HmOutFlux/atmosDeposition/heavyMetalEnterprise.vue
  20. 3 6
      src/views/User/HmOutFlux/irrigationWater/crossSection.vue
  21. 5 13
      src/views/User/HmOutFlux/irrigationWater/irriWaterSampleData.vue
  22. 5 17
      src/views/User/HmOutFlux/irrigationWater/samplingMethodDevice1.vue
  23. 3 2
      src/views/User/dataStatistics/DetectionStatistics.vue
  24. 8 0
      src/views/User/dataStatistics/LandCultivatedStatistics.vue
  25. 3 0
      src/views/User/dataStatistics/SoilCdStatistics.vue
  26. 12 10
      src/views/User/dataStatistics/SoilacidificationStatistics.vue
  27. 59 0
      src/views/User/farmlandQualityAssessment/farmlandQualityAssessment.vue
  28. 0 14
      src/views/User/heavyMetalFluxCalculation/inputFluxCalculation/waterdata/rivermessage.vue
  29. 0 12
      src/views/User/introduction/Introduce.vue

+ 3 - 2
components.d.ts

@@ -76,8 +76,9 @@ declare module 'vue' {
     Irrigationstatistics: typeof import('./src/components/detectionStatistics/irrigationstatistics.vue')['default']
     Irrwatermap: typeof import('./src/components/irrpollution/irrwatermap.vue')['default']
     PaginationComponent: typeof import('./src/components/PaginationComponent.vue')['default']
-    ReducedataStatistics: typeof import('./src/components/cdStatictics/reducedataStatistics.vue')['default']
-    RefluxcdStatictics: typeof import('./src/components/cdStatictics/refluxcdStatictics.vue')['default']
+    ReducedataStatistics: typeof import('./src/components/soilStatictics/reducedataStatistics.vue')['default']
+    RefluxcdStatictics: typeof import('./src/components/soilStatictics/refluxcdStatictics.vue')['default']
+    RefluxcedataStatictics: typeof import('./src/components/soilStatictics/refluxcedataStatictics.vue')['default']
     Riverwaterassay: typeof import('./src/components/irrpollution/riverwaterassay.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']

+ 4 - 5
src/components/atmpollution/airsampleChart.vue

@@ -287,11 +287,11 @@ async function initChart() {
     const { unit, titleText } = props.calculationMethod === 'weight' 
       ? { 
           unit: 'mg/kg', 
-          titleText: '各区域空气颗粒物重量指标平均值' ,
+          titleText: '各区域重金属含量平均值' ,
         } 
       : { 
           unit: 'ug/m³',  // 体积单位为ug/m³,可根据实际需求修改
-          titleText: '各区域空气颗粒物体积指标平均值' ,
+          titleText: '各区域重金属含量平均值' ,
         };
 
     // 销毁旧图表
@@ -322,7 +322,7 @@ async function initChart() {
       xAxis: {
         type: 'category',
         data: chartData.regions,
-        axisLabel: { rotate: 45 ,fontSize:18 }
+        axisLabel: { fontSize:16 }
       },
       yAxis: { 
         type: 'value',
@@ -347,7 +347,7 @@ async function initChart() {
         textStyle:{fontSize:18}
       },
       grid: {
-        left: '5%', right: '5%', bottom: '5%', top: '25%',
+        left: '1%', right: '2%', bottom: '2%', top: '20%',
         containLabel: true,
         axisLabel:{fontSize:18}
       }
@@ -385,7 +385,6 @@ onUnmounted(() => {
   width: 100%;
   max-width: 1400px;
   margin: 0 auto;
-  padding: 20px;
   box-sizing: border-box;
   position: relative;
 }

+ 3 - 3
src/components/atmpollution/atmsamplemap.vue

@@ -29,7 +29,7 @@ function calculateConcentration(heavyMetalWeight, volume) {
   }
   const ug = heavyMetalWeight * 1000; 
   const concentration = ug / volume;
-  return concentration.toFixed(2); 
+  return concentration; 
 }
 
 function calculateParticleConcentration(particleWeight, volume) {
@@ -38,7 +38,7 @@ function calculateParticleConcentration(particleWeight, volume) {
   }
   const ug = particleWeight * 1000; 
   const concentration = ug / volume;
-  return concentration.toFixed(2);
+  return concentration;
 }
 
 // ====================== 指标映射(重量直接取数,体积动态计算) ======================
@@ -88,7 +88,7 @@ function generatePopupContent(item, method) {
     return `
       <div class="data-item">
         <span class="item-label">${metric.label}:</span>
-        <span class="item-value">${value}</span>
+        <span class="item-value">${value.toFixed(6)}</span>
       </div>
     `;
   }).join('');

+ 3 - 5
src/components/atmpollution/heavyMetalEnterprisechart.vue

@@ -206,7 +206,7 @@ const initChart = (data) => {
     myChart = echarts.init(chartRef.value);
     myChart.setOption({
       title: {
-        text: '韶关市各区县企业污染物平均值',
+        text: '韶关市各区县企业排放大气颗粒物浓度平均值',
         left: 'center',
         subtext: `基于 ${data.totalSamples} 个有效样本`,
         subtextStyle: { fontSize: 15 }
@@ -229,7 +229,7 @@ const initChart = (data) => {
       },
       yAxis: {
         type: 'value',
-        name: '浓度 (t/a)',
+        name: '颗粒物排放量 (t/a)',
         nameTextStyle: { fontSize: 15 },
         axisLabel:{fontSize:15},
       },
@@ -311,10 +311,8 @@ onUnmounted(() => window.removeEventListener('resize', handleResize));
 
 <style scoped>
 .heavy-metal-chart {
-  width: 90%;
+  width: 100%;
   max-width: 1200px;
-  margin: 20px auto;
-  padding: 20px;
   background: #fff;
   border-radius: 12px;
   box-shadow: 0 2px 8px rgba(0,0,0,0.1);

+ 2 - 21
src/components/detectionStatistics/atmcompanyStatics.vue

@@ -253,7 +253,7 @@ export default {
           left: 0,
           right: "15%",
           top: 20,
-          bottom: 10,
+          bottom: "3%",
           containLabel: true
         },
         xAxis: {
@@ -311,32 +311,13 @@ export default {
 </script>
 
 <style>
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-}
-
-body {
-  background: #f8fafc;
-  color: #34495e;
-  min-height: 100vh;
-  padding: 0px;
-}
-
 .dashboard {
-  height: 350px;
+  height: 100%;
   width: 100%;
   max-width: 1000px;
   margin: 0 auto;
 }
 
-header {
-  padding: 20px 0;
-  margin-bottom: 20px;
-}
-
 h1 {
   font-size: 24px;
   color: #2980b9;

+ 130 - 184
src/components/detectionStatistics/atmsampleStatistics.vue

@@ -2,7 +2,7 @@
   <div class="boxplot-container">
     <div class="chart-container">
       <div class="header">
-        <div class="chart-title">大气重金属浓度统计箱线图</div>
+        <div class="chart-title">灌溉水重金属浓度统计箱线图</div>
         <p>展示各重金属浓度的分布特征(最小值、四分位数、中位数、最大值)</p>
         <p class="sample-subtitle">样本来源:{{ totalPoints }}个数据</p>
       </div>
@@ -33,114 +33,72 @@ import { ref, onMounted ,computed} from 'vue'
 export default {
   components: { VChart },
   setup() {
-    // -------- 核心配置 --------
-    const apiUrl = ref('/api/vector/export/all?table_name=Atmo_sample_data') // 使用相对路径
-    const heavyMetals = [
-      { key: 'Cr_particulate', name: '铬 (Cr)', color: '#FF9800' },
-      { key: 'As_particulate', name: '砷 (As)', color: '#4CAF50' },
-      { key: 'Cd_particulate', name: '镉 (Cd)', color: '#9C27B0' },
-      { key: 'Hg_particulate', name: '汞 (Hg)', color: '#2196F3' },
-      { key: 'Pb_particulate', name: '铅 (Pb)', color: '#F44336' },
-     // { key: 'particle_weight', name:'大气污染物重量' }
-    ]
+    // -------- 基本状态 --------
+    const apiUrl = ref('/api/vector/export/all?table_name=Atmo_sample_data')
+    const apiTimestamp = ref(null)
+    const statsData = ref({}); // 新增:存储接口返回的预统计数据
+    const chartOption = ref({})
+    const isLoading = ref(true)
+    const error = ref(null)
+    
+    // 样本数统计(从预统计数据中获取)
+    const totalPoints = computed(() => {
+      const firstMetalKey = heavyMetals[0]?.key;
+      return statsData.value[firstMetalKey]?.count || 0;
+    })
 
-    // -------- 状态 --------
-    const sampleData = ref([])    // 存储 properties 数据
-    const chartOption = ref({})   // ECharts 配置
-    const isLoading = ref(true)   // 加载状态
-    const error = ref(null)       // 错误信息
-    const statsByIndex = ref([])  // 缓存统计结果(与 x 轴对齐)
-    const totalPoints = computed(() => sampleData.value.length)
+    // 缓存每个品类的统计量(与 x 轴顺序一致)
+    const statsByIndex = ref([])
 
+    // -------- 配置:金属字段 --------
+    const heavyMetals = [
+      { key: 'cr_concentration', name: '铬 (Cr)', color: '#FF9800' },
+      { key: 'as_concentration', name: '砷 (As)', color: '#4CAF50' },
+      { key: 'cd_concentration', name: '镉 (Cd)', color: '#9C27B0' },
+      { key: 'hg_concentration', name: '汞 (Hg)', color: '#2196F3' },
+      { key: 'pb_concentration', name: '铅 (Pb)', color: '#F44336' }
+    ]
 
-    // -------- 工具函数 --------
-    /** 日志工具(带颜色区分) */
+    // -------- 日志 --------
     const log = (message, metalName = '') => {
-      console.log(
-        `%c[${metalName || '全局'}] %c${message}`,
-        'color:#4CAF50;font-weight:bold',
-        'color:#333'
-      )
-    }
-
-    /** 计算百分位数(线性插值法) */
-    const calculatePercentile = (sortedArray, percentile) => {
-      const n = sortedArray.length
-      if (n === 0) return null
-      if (percentile <= 0) return sortedArray[0]
-      if (percentile >= 100) return sortedArray[n - 1]
-      const index = (n - 1) * (percentile / 100)
-      const lowerIndex = Math.floor(index)
-      const upperIndex = lowerIndex + 1
-      const fraction = index - lowerIndex
-      if (upperIndex >= n) return sortedArray[lowerIndex]
-      return sortedArray[lowerIndex] + fraction * (sortedArray[upperIndex] - sortedArray[lowerIndex])
+      console.log(`%c[${metalName || '全局'}] %c${message}`,
+        'color:#4CAF50;font-weight:bold', 'color:#333')
     }
 
-    // -------- 数据统计 --------
-    /** 计算每个重金属的箱线图统计量(min/q1/median/q3/max) */
-    const calculateBoxplotStats = () => {
-      const stats = []
-      heavyMetals.forEach((metal) => {
-        //log(`开始处理 ${metal.name}`, metal.name)
-        // 1. 提取原始值
-        const rawValues = sampleData.value.map(item => item[metal.key])
-        //log(`原始值:[${rawValues.slice(0, 5)}${rawValues.length > 5 ? ', ...' : ''}]`, metal.name)
+    // -------- 构建箱线数据 --------
+    const buildBoxplotData = () => {
+      const xAxisData = heavyMetals.map(m => m.name);
 
-        // 2. 过滤无效值(NaN、非数字)
-        const values = rawValues
-          .map((val, idx) => {
-            const num = Number(val)
-            if (isNaN(num)) {
-              log(`⚠️ 第${idx+1}条数据无效: ${val}`, metal.name)
-              return null
-            }
-            return num
-          })
-          .filter(v => v !== null)
-        //log(`有效数据量:${values.length} 条`, metal.name)
+      // 缓存每个重金属的统计量(用于tooltip)
+      statsByIndex.value = heavyMetals.map(metal => {
+        const stat = statsData.value[metal.key] || {};
+        return {
+          key: metal.key,
+          name: metal.name,
+          min: stat.min,
+          q1: stat.q1,
+          median: stat.median,
+          q3: stat.q3,
+          max: stat.max,
+          color: metal.color
+        };
+      });
 
-        // 3. 无有效数据时,记录空统计
-        if (values.length === 0) {
-          stats.push({ ...metal, min: null, q1: null, median: null, q3: null, max: null })
-          return
+      // 构建ECharts箱线图数据
+      const data = statsByIndex.value.map(s => {
+        if (s.min === undefined || s.min === null) {
+          return [null, null, null, null, null];
         }
+        return [s.min, s.q1, s.median, s.q3, s.max];
+      });
 
-        // 4. 排序并计算统计量
-        const sorted = [...values].sort((a, b) => a - b)
-        const min = sorted[0]
-        const max = sorted[sorted.length - 1]
-        const q1 = calculatePercentile(sorted, 25)
-        const median = calculatePercentile(sorted, 50)
-        const q3 = calculatePercentile(sorted, 75)
-
-        //log(`统计结果:min=${min}, q1=${q1}, median=${median}, q3=${q3}, max=${max}`, metal.name)
-        stats.push({ ...metal, min, q1, median, q3, max })
-      })
-      return stats
-    }
-
-    /** 构建 ECharts 箱线图数据 */
-    const buildBoxplotData = (stats) => {
-      const xAxisData = heavyMetals.map(m => m.name)
-      // 与 x 轴顺序对齐(确保 tooltip 能正确匹配)
-      statsByIndex.value = heavyMetals.map(m => 
-        stats.find(s => s.key === m.key) || { ...m, min: null, q1: null, median: null, q3: null, max: null }
-      )
-      // 生成箱线图数据:[min, q1, median, q3, max]
-      const data = statsByIndex.value.map(s => 
-        s.min === null ? [null, null, null, null, null] : [s.min, s.q1, s.median, s.q3, s.max]
-      )
-      return { xAxisData, data }
-    }
+      return { xAxisData, data };
+    };
 
-    // -------- 图表初始化 --------
+    // -------- 初始化图表 --------
     const initChart = () => {
-      //log('开始初始化图表')
-      const stats = calculateBoxplotStats()
-      const { xAxisData, data } = buildBoxplotData(stats)
+      const { xAxisData, data } = buildBoxplotData(); // 修复:直接调用构建函数
 
-      // ECharts 配置(重点检查 series 数据格式)
       chartOption.value = {
         tooltip: {
           trigger: 'item',
@@ -149,7 +107,6 @@ export default {
             if (!s || s.min === null) {
               return `<div style="font-weight:bold;color:#f56c6c">${xAxisData[params.dataIndex]}</div><div>无有效数据</div>`
             }
-            
             return `<div style="font-weight:bold">${xAxisData[params.dataIndex]}</div>
               <div style="margin-top:8px">
                 <div>最小值:<span style="color:#5a5;">${s.min.toFixed(4)}</span></div>
@@ -158,28 +115,29 @@ export default {
                 <div>上四分位:<span style="color:#d87a80;">${s.q3.toFixed(4)}</span></div>
                 <div>最大值:<span style="color:#5a5;">${s.max.toFixed(4)}</span></div>
               </div>`
-          }
+          },
         },
         xAxis: {
           type: 'category',
           data: xAxisData,
           name: '重金属类型',
           nameLocation: 'middle',
-          nameGap: 45,
-          axisLabel: { color: '#555', rotate: 30, fontWeight: 'bold',fontSize:11 }
+          nameGap: 30,
+          axisLabel: { color: '#555', rotate: 0, fontWeight: 'bold' ,fontSize :11}
         },
         yAxis: {
           type: 'value',
-          name: 'mg/kg',
+          name: 'ug/L',
+          nameTextStyle: { fontSize: 12 }, 
           nameLocation: 'end',
-          nameGap: 5,
-          axisLabel: { color: '#555', fontWeight: 'bold' ,fontSize:11},
+          nameGap: 8,
+          axisLabel: { color: '#555', fontWeight: 'bold',fontSize:11 },
           splitLine: { lineStyle: { color: '#f0f0f0' } }
         },
         series: [{
           name: '重金属浓度分布',
           type: 'boxplot',
-          data, // 必须是 [[min,q1,median,q3,max], ...] 格式
+          data,
           itemStyle: {
             color: (p) => (heavyMetals[p.dataIndex]?.color || '#1890ff'),
             borderWidth: 2
@@ -188,67 +146,50 @@ export default {
             itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.2)', borderWidth: 3 }
           }
         }],
-        grid: { top: '8%', right: '5%', left: '12%', bottom: '20%' }
+        grid: { top: '10%', right: '3%', left: '6%', bottom: '10%' }
       }
+
       isLoading.value = false
-      //log('图表初始化完成')
     }
 
     // -------- 接口请求 --------
-   onMounted(async () => {
-  try {
-    //log('发起API请求...')
-    const response = await api8000.get(apiUrl.value) // 使用 api8000 实例
-    //console.log('接口原始响应:', response.data) // 调试必看!
-
-    let data = response.data
-
-    // ✅ 兼容接口返回字符串的情况(比如后端没设置 application/json)
-    if (typeof data === 'string') {
+      onMounted(async () => {
       try {
-        // 兼容 NaN(非标准 JSON 值)→ 替换为 null
-        data = JSON.parse(data.replace(/\bNaN\b/g, 'null'))
-      } catch (parseErr) {
-        throw new Error('接口返回的是字符串,但 JSON 解析失败')
-      }
-    }
+        // log('发起API请求...')
+        const response = await api8000.get(apiUrl.value) // 使用 api8000 实例
+        // console.log('接口原始响应:', response.data) // 调试必看!
 
-    // 1. 分情况提取 features(严格校验结构)
-    let features = []
-    if (data?.type === 'FeatureCollection') {
-      // 情况1:标准 GeoJSON FeatureCollection
-      if (Array.isArray(data.features)) {
-        features = data.features
-      } else {
-        throw new Error('FeatureCollection 中 features 不是数组')
-      }
-    } else if (Array.isArray(data)) {
-      // 情况2:直接返回 features 数组
-      features = data
-    } else {
-      // 情况3:其他非法结构
-      throw new Error(`接口结构异常,响应:${JSON.stringify(data)}`)
-    }
-
-    // 2. 提取 properties 数据(确保非空)
-    sampleData.value = features.map(f => f.properties)
-    if (sampleData.value.length === 0) {
-      throw new Error('接口返回数据为空(properties 为空)')
-    }
-    //log(`成功提取 ${sampleData.value.length} 条数据`, '接口')
-
-    // 3. 初始化图表
-    initChart()
+        let data = response.data
 
-  } catch (err) {
-    error.value = err
-    isLoading.value = false
-    console.error('接口请求失败:', err)
-  }
-})
+        // ✅ 兼容接口返回字符串的情况(比如后端没设置 application/json)
+        if (typeof data === 'string') {
+          try {
+            // 尝试解析字符串为JSON
+            data = JSON.parse(data);
+          } catch (parseError) {
+            console.warn('接口返回字符串但解析失败,尝试重新请求', parseError);
+            // 如果解析失败,重新请求
+            const retryResponse = await api8000.get(apiUrl.value);
+            data = retryResponse.data;
+          }
+        }
 
+        // 赋值并更新UI
+        statsData.value = data;
+        apiTimestamp.value = new Date().toLocaleString();
+        initChart();
+        isLoading.value = false;
+        
+      } catch (err) {
+        error.value = err;
+        isLoading.value = false;
+        console.error('接口请求失败:', err);
+      }
+    });
 
     return {
+      apiUrl,
+      apiTimestamp,
       chartOption,
       isLoading,
       error,
@@ -267,13 +208,14 @@ export default {
 }
 .header { 
   text-align: left;
-  margin-bottom: 20px; 
-}
-.chart-title {
-  font-size: 14px;
-  color: #2980b9;
-  font-weight: 600;
+   margin-bottom: 10px; 
 }
+
+.header h2 { 
+  font-size: 0.6rem; 
+  color: #333; 
+  margin-bottom: 4px;
+ }
 .header p { 
   font-size: 0.6rem; 
   color: #666;
@@ -281,37 +223,42 @@ export default {
 }
 .loading-state { 
   text-align: center;
-  padding: 40px 0;
-  color: #666; 
+   padding: 40px 0;
+   color: #666; 
 }
 .loading-state .spinner {
-  display: inline-block; 
-  width: 24px; 
-  height: 24px; 
-  margin-right: 8px;
-  border: 3px solid #ccc; 
-  border-top-color: #1890ff; 
-  border-radius: 50%;
+  display: inline-block; width: 24px; height: 24px; margin-right: 8px;
+  border: 3px solid #ccc; border-top-color: #1890ff; border-radius: 50%;
   animation: spin 1s linear infinite;
 }
-@keyframes spin { 
-  to { transform: rotate(360deg); } 
-}
-.error-state { 
-  text-align: center; 
-  padding: 40px 0; 
-  color: #f56c6c; 
-}
-.chart-wrapper { 
-  width: 100%; 
-  height: 220px; /* 确保高度有效 */
-}
+@keyframes spin { to { transform: rotate(360deg); } }
+.error-state { text-align: center; padding: 40px 0; color: #f56c6c; }
+.chart-wrapper { width: 100%; height: 220px; }
 .chart-container {
   background: white;
   border-radius: 12px;
   box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
-  padding: 20px;
   margin-bottom: 25px;
+  height: 100%;
+  box-sizing: border-box;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 15px;
+}
+
+.chart-title {
+  font-size: 14px;
+  color: #2980b9;
+  font-weight: 600;
+}
+
+.title-group {
+    display: flex;
+    align-items: left;
 }
 
 .sample-subtitle {
@@ -319,5 +266,4 @@ export default {
   color: #888;
   margin-top: 4px;
 }
-
-</style>
+</style>

+ 3 - 3
src/components/detectionStatistics/crosscetionStatistics.vue

@@ -249,8 +249,8 @@ export default {
         grid: {
           left: 0,
           right: '15%',
-          top: 20,
-          bottom: 10,
+          top: 20, // 缩减顶部边距
+          bottom: "3%", // 缩减底部边距
           containLabel: true
         },
         xAxis: {
@@ -314,7 +314,7 @@ export default {
 /* 固定组件总高度为350px */
 .dashboard {
   width: 100%;
-  height: 300px;
+  height: 100%;
   max-width: 1000px;
   margin: 0 auto;
 }

+ 35 - 121
src/components/detectionStatistics/irrigationstatistics.vue

@@ -37,12 +37,15 @@ export default {
     const apiUrl = ref('/api/vector/export/all?table_name=water_sampling_data') // 使用相对路径
     const apiTimestamp = ref(null)
     const sampleCount = ref(0)
-
-    const sampleData = ref([])
+    const statsData = ref({}); 
     const chartOption = ref({})
     const isLoading = ref(true)
     const error = ref(null)
-    const totalPoints = computed(() => sampleData.value.length)
+    const stats = null;
+    const totalPoints = computed(() => {
+      const firstMetalKey = heavyMetals[0]?.key;
+      return statsData.value[firstMetalKey]?.count || 0;
+    })
 
     // 关键:缓存每个品类的统计量(与 x 轴顺序一致)
     const statsByIndex = ref([])
@@ -55,90 +58,38 @@ export default {
       { key: 'hg_concentration', name: '汞 (Hg)', color: '#2196F3' },
       { key: 'pb_concentration', name: '铅 (Pb)', color: '#F44336' }
     ]
-
-    // -------- 日志 --------
-    const log = (message, metalName = '') => {
-      console.log(`%c[${metalName || '全局'}] %c${message}`,
-        'color:#4CAF50;font-weight:bold', 'color:#333')
-    }
-
-    // -------- 工具:百分位(线性插值) --------
-    const calculatePercentile = (sortedArray, percentile) => {
-      const n = sortedArray.length
-      if (n === 0) return null
-      if (percentile <= 0) return sortedArray[0]
-      if (percentile >= 100) return sortedArray[n - 1]
-      const index = (n - 1) * (percentile / 100)
-      const lowerIndex = Math.floor(index)
-      const upperIndex = lowerIndex + 1
-      const fraction = index - lowerIndex
-      if (upperIndex >= n) return sortedArray[lowerIndex]
-      return sortedArray[lowerIndex] + fraction * (sortedArray[upperIndex] - sortedArray[lowerIndex])
-    }
-
-    // -------- 计算统计量 --------
-    const calculateBoxplotStats = () => {
-      const stats = []
-
-      heavyMetals.forEach((metal) => {
-        //log(`开始处理重金属: ${metal.name}`, metal.name)
-        const rawValues = sampleData.value.map(item => item[metal.key])
-        //log(`原始值(未过滤): [${rawValues.join(', ')}]`, metal.name)
-
-        const values = rawValues
-          .map((val, idx) => {
-            const num = Number(val)
-            if (isNaN(num)) log(`⚠️ 第${idx + 1}条数据无效: ${val}`, metal.name)
-            return isNaN(num) ? null : num
-          })
-          .filter(v => v !== null)
-
-        //log(`有效数值(过滤后): [${values.join(', ')}]`, metal.name)
-
-        const sorted = [...values].sort((a, b) => a - b)
-        //log(`排序后(升序): [${sorted.join(', ')}]`, metal.name)
-
-        let min = null, q1 = null, median = null, q3 = null, max = null
-        if (sorted.length > 0) {
-          min = sorted[0]
-          max = sorted[sorted.length - 1]
-          q1 = calculatePercentile(sorted, 25)
-          median = calculatePercentile(sorted, 50)
-          q3 = calculatePercentile(sorted, 75)
-          const ok = min <= q1 && q1 <= median && median <= q3 && q3 <= max
-          //log(`统计量: min=${min}, q1=${q1}, median=${median}, q3=${q3}, max=${max} → 顺序OK: ${ok}`, metal.name)
-        } else {
-          log(`⚠️ 无有效数据,跳过统计`, metal.name)
-        }
-
-        stats.push({ key: metal.key, name: metal.name, min, q1, median, q3, max, color: metal.color })
-      })
-
-      return stats
-    }
-
     // -------- 构建箱线数据(保留你自己的顺序) --------
-    const buildBoxplotData = (stats) => {
-      const xAxisData = heavyMetals.map(m => m.name)
-
-      // 与 x 轴顺序对齐的统计量缓存(**tooltip 用它,不用 params.data**)
-      statsByIndex.value = heavyMetals.map(m =>
-        stats.find(s => s.key === m.key) || { min: null, q1: null, median: null, q3: null, max: null }
-      )
-
-      const data = statsByIndex.value.map((s, i) => {
-        if (s.min === null) return [null, null, null, null, null]
-        const box = [s.min, s.q1, s.median, s.q3, s.max]
-        //log(`箱线数据(${xAxisData[i]}): [${box.join(', ')}]`, '箱线构建')
-        return box
-      })
+    const buildBoxplotData = () => {
+      const xAxisData = heavyMetals.map(m => m.name); // 保持x轴顺序与配置一致
+
+      // 缓存每个重金属的统计量(用于tooltip)
+      statsByIndex.value = heavyMetals.map(metal => {
+       const stat = statsData.value[metal.key] || {}; // 从接口数据中取当前金属的统计
+        return {
+          key: metal.key,
+          name: metal.name,
+          min: stat.min,
+          q1: stat.q1,
+          median: stat.median,
+          q3: stat.q3,
+          max: stat.max,
+          color: metal.color
+        };
+      });
+
+      // 构建ECharts箱线图所需的二维数组格式 [[min, q1, median, q3, max], ...]
+      const data = statsByIndex.value.map(s => {
+        if (s.min === undefined || s.min === null) {
+          return [null, null, null, null, null]; // 无数据时返回空数组
+        }
+        return [s.min, s.q1, s.median, s.q3, s.max];
+      });
 
-      return { xAxisData, data }
-    }
+       return { xAxisData, data };
+    };
 
     // -------- 初始化图表 --------
     const initChart = () => {
-      const stats = calculateBoxplotStats()
       const { xAxisData, data } = buildBoxplotData(stats)
 
       chartOption.value = {
@@ -199,47 +150,10 @@ export default {
     onMounted(async () => {
       try {
         //log('发起API请求...')
-        const response = await api8000.get(apiUrl.value) // 使用 api8000 实例
+        const response = await axios.get(apiUrl.value);
+        statsData.value = response.data; 
         apiTimestamp.value = new Date().toLocaleString()
-        
-        let data = response.data
-        
-        // 处理可能的字符串响应
-        if (typeof data === 'string') {
-          try {
-            // 替换 NaN 为 null
-            const cleanedData = data.replace(/\bNaN\b/g, 'null');
-            data = JSON.parse(cleanedData);
-          } catch (parseErr) {
-            throw new Error('接口返回的是字符串,但 JSON 解析失败');
-          }
-        }
-        
-        // 处理对象中的 NaN 值
-        if (typeof data === 'object' && data !== null) {
-          const replaceNaN = (obj) => {
-            for (const key in obj) {
-              if (typeof obj[key] === 'object' && obj[key] !== null) {
-                replaceNaN(obj[key]);
-              } else if (typeof obj[key] === 'number' && isNaN(obj[key])) {
-                obj[key] = null;
-              } else if (obj[key] === 'NaN') {
-                obj[key] = null;
-              }
-            }
-          };
-          replaceNaN(data);
-        }
-
-        if (data && data.features) {
-          // 你的接口:GeoJSON -> features[].properties
-          sampleData.value = data.features.map(f => f.properties)
-          sampleCount.value = sampleData.value.length
-          //log(`接口返回数据量: ${sampleCount.value} 条`, '接口')
           initChart()
-        } else {
-          throw new Error('接口返回数据格式不正确(无features字段)')
-        }
       } catch (err) {
         error.value = err
         isLoading.value = false

+ 6 - 2
src/components/irrpollution/crossSetionData1.vue

@@ -145,7 +145,8 @@ const updateChart = () => {
       formatter: '{a} <br/>{b}: {c} ug/L'
     },
     grid: {
-      right: '4%',
+      left: '5%',
+      right: '5%',
       bottom: '3%',
       containLabel: true
     },
@@ -207,7 +208,6 @@ onBeforeUnmount(() => {
 .chart-page {
   width: 100%;
   margin: 0 auto 24px;
-  background-color: white;
   border-radius: 12px;
   padding: 20px;
   box-sizing: border-box;
@@ -216,7 +216,11 @@ onBeforeUnmount(() => {
 
 .chart-container {
   width: 100%; 
+<<<<<<< HEAD
   height: 500px; /* 增加高度以容纳旋转的标签 */
+=======
+  height:400px;
+>>>>>>> origin/lili
   margin: 0 auto;
   border-radius: 12px;
 }

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

@@ -61,7 +61,7 @@ onMounted(() => {
     return '#cccccc';
   }
 
-  // 加载区县边界(保持不变)
+  // 加载区县边界(保持不变)http://localhost:8000/api/vector/boundary?table_name=counties&field_name=city_name&field_value=%E9%9F%B6%E5%85%B3%E5%B8%82
   fetch('/data/韶关市各区县边界图.geojson')
     .then(res => {
       if (!res.ok) throw new Error(`区县边界加载失败:${res.status}`);
@@ -187,7 +187,7 @@ onMounted(() => {
 /* 原有样式保持不变 */
 .map-wrapper {
   width: 100%;
-  height: 80%;
+  height: 100%;
   position: relative;
 }
 .map-container {

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

@@ -48,7 +48,7 @@ onMounted(() => {
     "南雄市": "#06D6A0",
   };
 
-  // 加载区县边界(带完整错误处理)
+  // 加载区县边界(带完整错误处理)http://localhost:8000/api/vector/boundary?table_name=counties&field_name=city_name&field_value=%E9%9F%B6%E5%85%B3%E5%B8%82
   fetch('/data/韶关市各区县边界图.geojson')
     .then(res => {
       if (!res.ok) throw new Error(`区县边界加载失败:${res.status}`);
@@ -193,7 +193,7 @@ onMounted(() => {
 }
 .map-container {
   width: 100% !important;
-  height: 500px !important;
+  height: 100% !important;
 }
 
 /*  标题和分隔线 */

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

@@ -245,7 +245,7 @@ const initChart = ({ regions, series, totalSamples }) => {
     grid: { //整个图的位置
       left: '3%', 
       right: '3%', 
-      bottom: '5%', 
+      bottom: 0, 
       containLabel: true 
     },
   };

+ 349 - 0
src/components/soilStatictics/reducedataStatistics.vue

@@ -0,0 +1,349 @@
+<template>
+  <div class="chart-container">
+    <div class="chart-controls">
+      <button @click="refreshData" class="refresh-btn">
+        <i class="fas fa-sync-alt"></i> 刷新数据
+      </button>
+      <div class="selected-ids">
+        <span>选中的ID: </span>
+        <span v-for="id in selectedIds" :key="id" class="id-tag">{{ id }}</span>
+      </div>
+    </div>
+    
+    <div v-if="loading" class="loading">
+      <p>数据加载中...</p>
+    </div>
+    
+    <div v-if="error" class="error">
+      <p>{{ error }}</p>
+    </div>
+    
+    <div ref="chartRef" class="chart" v-show="!loading && !error"></div>
+  </div>
+</template>
+
+<script>
+import { ref, onMounted, onUnmounted, nextTick } from 'vue';
+import * as echarts from 'echarts';
+
+export default {
+  name: 'PhTrendChart',
+  setup() {
+    // 接口数据 - 不同时间点的数据集
+    const interfaces = [
+      { time: '20241229_201018', url: 'http://localhost:5000/api/table-data?table_name=dataset_5' },
+      { time: '20250104_171827', url: 'http://localhost:5000/api/table-data?table_name=dataset_35' },
+      { time: '20250104_171959', url: 'http://localhost:5000/api/table-data?table_name=dataset_36' },
+      { time: '20250104_214026', url: 'http://localhost:5000/api/table-data?table_name=dataset_37' },
+      { time: '20250308_161945', url: 'http://localhost:5000/api/table-data?table_name=dataset_65' },
+      { time: '20250308_163248', url: 'http://localhost:5000/api/table-data?table_name=dataset_66' },
+    ];
+    
+    const chartRef = ref(null);
+    const loading = ref(true);
+    const error = ref(null);
+    const selectedIds = ref([]);
+    const lastUpdate = ref(new Date().toLocaleString());
+    
+    let chartInstance = null;
+    let chartData = {};
+    
+    // 生成1-43之间的6个不重复随机数
+    function generateRandomIds() {
+      const ids = new Set();
+      while (ids.size < 6) {
+        const id = Math.floor(Math.random() * 43) + 1;
+        ids.add(id);
+      }
+      return Array.from(ids).sort((a, b) => a - b);
+    }
+    
+    // 获取数据
+    async function fetchData() {
+      try {
+        loading.value = true;
+        error.value = null;
+        
+        const newSelectedIds = generateRandomIds();
+        selectedIds.value = newSelectedIds;
+        
+        // 初始化图表数据
+        const newChartData = {};
+        newSelectedIds.forEach(id => {
+          newChartData[id] = {
+            timestamps: [],
+            phValues: []
+          };
+        });
+        
+        // 按时间顺序获取每个表的数据
+        for (const intf of interfaces) {
+          const response = await fetch(intf.url);
+          if (!response.ok) throw new Error(`网络响应错误: ${response.status}`);
+          
+          const responseData = await response.json();
+          const dataArray = responseData.data || [];
+          
+          for (const id of newSelectedIds) {
+            // 确保数据存在
+            if (!newChartData[id]) {
+              newChartData[id] = {
+                timestamps: [],
+                phValues: []
+              };
+            }
+            
+            // 查找匹配的项目 ,使用小写id
+            const targetItem = dataArray.find(item => item.id === id);
+            
+            if (targetItem) {
+              // 获取pH值,使用小写pH
+              const phValue = parseFloat(targetItem.pH || 0);
+              newChartData[id].timestamps.push(intf.time);
+              newChartData[id].phValues.push(phValue);
+            } else {
+              // 如果没有找到数据,添加null值保持数据一致性
+              newChartData[id].timestamps.push(intf.time);
+              newChartData[id].phValues.push(null);
+            }
+          }
+        }
+        
+        // 更新图表数据
+        chartData = newChartData;
+        lastUpdate.value = new Date().toLocaleString();
+        
+        // 确保DOM更新后再渲染图表
+        await nextTick();
+        renderChart();
+        
+      } catch (err) {
+        error.value = err.message || '获取数据失败';
+        console.error('获取数据错误:', err);
+      } finally {
+        loading.value = false;
+      }
+    }
+    
+    // 渲染图表
+    function renderChart() {
+      if (!chartRef.value) {
+        console.error('图表容器未找到');
+        return;
+      }
+      
+      // 销毁旧的图表实例(如果存在)
+      if (chartInstance) {
+        try {
+          chartInstance.dispose();
+        } catch (e) {
+          console.warn('销毁图表实例时出错:', e);
+        }
+        chartInstance = null;
+      }
+      
+      try {
+        // 初始化新的ECharts实例
+        chartInstance = echarts.init(chartRef.value);
+        
+        // 准备系列数据
+        const series = [];
+        const xAxisData = interfaces.map(item => item.time);
+        
+        for (const id of selectedIds.value) {
+          const data = chartData[id]?.phValues || [];
+          series.push({
+            name: `ID: ${id}`,
+            type: 'line',
+            symbol: 'circle',
+            symbolSize: 8,
+            data: data,
+            lineStyle: { width: 2 },
+            emphasis: {
+              focus: 'series'
+            }
+          });
+        }
+        
+        const option = {
+          title: {
+            text: '随机样本点的pH值趋势图',
+            left: 'center',
+            top: 10
+          },
+          tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+              type: 'cross',
+              label: {
+                backgroundColor: '#6a7985'
+              }
+            }
+          },
+          legend: {
+            data: selectedIds.value.map(id => `ID: ${id}`),
+            top: 40,
+            type: 'scroll'
+          },
+          grid: {
+            left: '8%',
+            right: '5%',
+            bottom: '10%',
+            top: '100px',
+            containLabel: true
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: xAxisData,
+            axisLabel: {
+              rotate: 30,
+              interval: 0
+            },
+            name: '时间'
+          },
+          yAxis: {
+            type: 'value',
+            scale: true,
+            name: 'pH值'
+          },
+          series: series
+        };
+
+        chartInstance.setOption(option);
+        
+        // 延迟resize调用
+        setTimeout(() => {
+          if (chartInstance) {
+            chartInstance.resize();
+          }
+        }, 100);
+      } catch (e) {
+        console.error('初始化图表时出错:', e);
+        error.value = '图表初始化失败: ' + e.message;
+      }
+    }
+    
+    // 刷新数据
+    function refreshData() {
+      fetchData();
+    }
+    
+    onMounted(() => {
+      // 确保DOM完全加载后再初始化图表
+      const initChart = () => {
+        if (chartRef.value) {
+          fetchData();
+        } else {
+          // 如果DOM还未准备好,延迟执行
+          setTimeout(initChart, 100);
+        }
+      };
+      
+      initChart();
+      
+      // 窗口大小变化时重绘图表
+      const resizeHandler = () => {
+        if (chartInstance) {
+          setTimeout(() => {
+            chartInstance.resize();
+          }, 100);
+        }
+      };
+      
+      window.addEventListener('resize', resizeHandler);
+      
+      // 在卸载时移除事件监听器
+      onUnmounted(() => {
+        window.removeEventListener('resize', resizeHandler);
+        if (chartInstance) {
+          try {
+            chartInstance.dispose();
+          } catch (e) {
+            console.warn('卸载时销毁图表实例出错:', e);
+          }
+        }
+      });
+    });
+    
+    return {
+      chartRef,
+      loading,
+      error,
+      selectedIds,
+      lastUpdate,
+      refreshData
+    };
+  }
+}
+</script>
+
+<style scoped>
+.chart-container {
+  width: 100%;
+  padding: 20px;
+  height: 550px;
+  box-sizing: border-box;
+}
+
+.chart-controls {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+  padding-bottom: 10px;
+  border-bottom: 1px solid #eee;
+}
+
+.refresh-btn {
+  background-color: #42b983;
+  color: white;
+  border: none;
+  padding: 8px 16px;
+  border-radius: 4px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  transition: background-color 0.3s;
+}
+
+.refresh-btn:hover {
+  background-color: #359e75;
+}
+
+.selected-ids {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  flex-wrap: wrap;
+}
+
+.id-tag {
+  background-color: #e6f7ff;
+  color: #1890ff;
+  padding: 3px 8px;
+  border-radius: 12px;
+  font-size: 12px;
+}
+
+.chart {
+  width: 100%;
+  height: calc(100% - 60px);
+  border: 1px solid #e0e0e0;
+  border-radius: 4px;
+}
+
+.loading, .error {
+  width: 100%;
+  height: calc(100% - 60px);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  color: #666;
+}
+
+.error {
+  color: #f5222d;
+}
+</style>

+ 214 - 0
src/components/soilStatictics/refluxcedataStatictics.vue

@@ -0,0 +1,214 @@
+<template>
+  <div class="chart-container">
+    <h3 class="title">酸化加剧Delta_pH柱状图</h3>
+    <div class="echarts-box" ref="chartRef"></div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
+import * as echarts from 'echarts';
+import axios from 'axios';
+
+// 图表相关
+const chartRef = ref(null);
+let myChart = null;
+
+// 数据状态
+const chartData = ref([]);
+const isLoading = ref(false);
+const errorMessage = ref('');
+
+// 接口地址(请替换为实际接口地址)
+const API_URL = 'http://localhost:5000/api/table-data?table_name=dataset_60'; // 替换为实际接口
+
+// 获取数据函数
+const fetchData = async () => {
+  //console.log('开始获取数据...');
+  // 重置状态
+  errorMessage.value = '';
+  isLoading.value = true;
+  
+  try {
+    // 发起请求
+    const response = await axios.get(API_URL);
+    //console.log('API响应:', response);
+    
+    // 检查响应数据是否符合预期格式
+    if (response.data && response.data.success) {
+  if (Array.isArray(response.data.data) && response.data.data.length > 0) {
+    if (response.data.data[0].id !== undefined && response.data.data[0].Delta_pH !== undefined) {
+      chartData.value = response.data.data;
+    } else {
+      errorMessage.value = '数据字段缺失:缺少 id 或 Delta_pH';
+    }
+  } else {
+    errorMessage.value = '未获取到有效数据,请稍后重试';
+  }
+} else {
+  errorMessage.value = 'API返回失败状态';
+}
+  } catch (error) {
+    console.error('数据获取失败:', error);
+    // 根据错误类型显示不同信息
+    if (error.response) {
+      errorMessage.value = `请求失败 (${error.response.status}): ${error.response.statusText}`;
+    } else if (error.request) {
+      errorMessage.value = '未收到响应,请检查网络连接';
+    } else {
+      errorMessage.value = '请求发生错误,请稍后重试';
+    }
+  } finally {
+    isLoading.value = false;
+  }
+};
+
+// 初始化图表
+const initChart = () => {
+  //console.log('初始化图表,数据长度:', chartData.value.length);
+  // 确保DOM已挂载且有数据
+  if (!chartRef.value) {
+    console.error('图表容器未找到');
+    return;
+  }
+
+  if (chartData.value.length === 0) {
+    console.error('没有数据可用于渲染图表');
+    return;
+  }
+  
+  // 销毁已有实例
+  if (myChart) {
+    myChart.dispose();
+    //console.log('已销毁旧图表实例');
+  }
+  
+  // 初始化图表
+  myChart = echarts.init(chartRef.value);
+  //console.log('ECharts实例已创建');
+
+   myChart.on('rendered', () => {
+    //console.log('图表已渲染');
+  });
+  
+  // 提取数据
+  const xAxisData = chartData.value.map(item => item.id);
+  const seriesData = chartData.value.map(item => ({
+    value: item.Delta_pH,
+    itemStyle: {
+      // 根据值的正负设置不同颜色
+      color: item.Delta_pH >= 0 ? '#0F52BA' : '#F44336'
+    }
+  }));
+
+  //console.log('X轴数据:', xAxisData);
+  //console.log('系列数据:', seriesData);
+  
+  // 图表配置
+  const option = {
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow'
+      },
+      formatter: function(params) {
+        const item = chartData.value.find(d => d.id === params[0].name);
+        return `ID: ${item.id}<br/>Delta_pH: ${item.Delta_pH.toFixed(4)}`;
+      }
+    },
+    grid: {
+      left: '5%',
+      right: '1%',
+      bottom: '5%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      data: xAxisData,
+      name: 'ID',
+      nameLocation: 'middle',
+      nameGap: 30,
+    },
+    yAxis: {
+      type: 'value',
+      name: 'Delta_pH',
+      nameLocation: 'middle',
+      nameGap: 50,
+      axisLabel: {
+        formatter: '{value}'
+      }
+    },
+    series: [
+      {
+        name: 'Delta_pH',
+        type: 'bar',
+        data: seriesData,
+        barWidth: '60%',
+        label: {
+          show: false,
+          position: 'top',
+          formatter: function(params) {
+            return params.value.toFixed(4);
+          }
+        }
+      }
+    ]
+  };
+  
+  // 设置图表配置
+  myChart.setOption(option);
+};
+
+// 监听数据变化,重新渲染图表
+watch(chartData, () => {
+  nextTick(()=>{
+    initChart();  
+  })
+
+});
+
+// 窗口大小变化时重绘图表
+const handleResize = () => {
+  if (myChart) {
+    myChart.resize();
+  }
+};
+
+// 组件挂载时初始化
+onMounted(async() => {
+  // 首次加载数据
+  await fetchData();
+  initChart();
+  // 监听窗口大小变化
+  window.addEventListener('resize', handleResize);
+});
+
+// 组件卸载时清理
+onUnmounted(() => {
+  if (myChart) {
+    myChart.dispose();
+  }
+  window.removeEventListener('resize', handleResize);
+});
+</script>
+
+<style scoped>
+.chart-container {
+  width: 100%;
+  height: 470px;
+  padding: 20px;
+  box-sizing: border-box;
+}
+
+.echarts-box {
+  width: 100%;
+  height: 100%;
+  border: 1px solid #e0e0e0;
+  border-radius: 6px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.title {
+  text-align: center;
+}
+</style>

+ 207 - 182
src/components/soilcdStatistics/cropcdStatictics.vue

@@ -25,13 +25,7 @@
     <!-- 1️⃣ 作物态Cd指标 -->
     <section class="mb-4 chart-container">
       <h3 class="section-title text-base font-semibold">作物态Cd主要指标</h3>
-      <div class="flex flex-wrap mb-3">
-        <div class="legend-item" v-for="(item, index) in fieldConfig.pollution" :key="index">
-          <div class="legend-color" :style="{ backgroundColor: item.color }"></div>
-          <span>{{ item.legendName }}</span>
-        </div>
-      </div>
-      <div ref="cdBarChart" style="width: 100%; height: 320px;"></div>
+      <div ref="cdBarChart" style="width: 100%; height: 415px;"></div>
     </section>
 
     <!-- 2️⃣ 养分元素 -->
@@ -90,24 +84,21 @@ const fieldConfig = {
  pollution: [
     { 
       key: '002_0002IDW', 
-      name: '002_0002IDW',  // 横坐标保持原标识
-      legendName: '002_0002IDW:粒径在0.002~0.02mm的粉粒组分质量占比,%',  // 图例显示中文
+      name: '粉粒组分质量占比',  // 横坐标保持原标识
       color: '#5470c6' ,
       unit:"%",
       convert: false
     },
     { 
       key: '02_002IDW', 
-      name: '02_002IDW',  // 横坐标保持原标识
-      legendName: '02_002IDW:粒径在0.02~0.2mm的砂粒组分质量占比,%',  // 图例显示中文
+      name: '砂粒组分质量占比',  // 横坐标保持原标识
       color: '#91cc75' ,
       unit:"%",
       convert: false
     },
     { 
       key: '2_02IDW', 
-      name: '2_02IDW',  // 横坐标保持原标识
-      legendName: '2_02IDW:粒径大于2mm的石砾组分质量占比,%',  // 图例显示中文
+      name: '石砾组分质量占比',  // 横坐标保持原标识
       color: '#fac858' ,
       unit:"%",
       convert: false
@@ -132,121 +123,15 @@ const fieldConfig = {
 // 数据请求(作物态Cd接口)
 const fetchData = async () => {
   try {
-    const apiUrl = '/api/vector/export/all?table_name=CropCd_input_data&format=json';
-    const response = await api8000.get(apiUrl);
+    const apiUrl = 'http://localhost:8000/api/vector/stats/CropCd_input_data';
+    const response = await axios.get(apiUrl);
     
-    // 接口返回格式判断(GeoJSON或直接数组)
-    const rawData = response.data.features 
-      ? response.data.features.map(f => f.properties) 
-      : response.data;
-    return rawData;
+    return response.data;
   } catch (err) {
     throw new Error('数据加载失败: ' + err.message);
   }
 };
 
-// 分位数计算(采用QUARTILE.INC算法)
-const calculatePercentile = (sortedArray, percentile) => {
-  const n = sortedArray.length;
-  if (n === 0) return null;
-  if (percentile <= 0) return sortedArray[0];
-  if (percentile >= 100) return sortedArray[n - 1];
-  
-  const index = (n - 1) * (percentile / 100);
-  const lowerIndex = Math.floor(index);
-  const upperIndex = lowerIndex + 1;
-  const fraction = index - lowerIndex;
-  
-  if (upperIndex >= n) return sortedArray[lowerIndex];
-  return sortedArray[lowerIndex] + fraction * (sortedArray[upperIndex] - sortedArray[lowerIndex]);
-};
-
-// 计算单个字段的统计量
-const calculateFieldStats = (data, fieldKey, fieldName) => {
-  // 获取字段配置
-  const fieldConfigItem = [
-    ...fieldConfig.pollution,
-    ...fieldConfig.nutrient,
-    ...fieldConfig.extra
-  ].find(f => f.key === fieldKey);
-  
-  // 提取并清洗数据
-  const rawValues = data.map(item => item[fieldKey]);
-  const values = rawValues
-    .map((val, idx) => {
-      let num = Number(val);
-      
-      // 处理无效值
-      if (isNaN(num)) {
-        return null;
-      }
-      
-      // 应用单位转换
-      if (fieldConfigItem?.convert && fieldConfigItem.conversionFactor) {
-        num = num * fieldConfigItem.conversionFactor;
-      }
-      
-      return num;
-    })
-    .filter(v => v !== null);
-  
-  if (values.length === 0) {
-    return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null };
-  }
-  
-  // 排序并计算统计量
-  const sorted = [...values].sort((a, b) => a - b);
-  const min = sorted[0];
-  const max = sorted[sorted.length - 1];
-  const q1 = calculatePercentile(sorted, 25);
-  const median = calculatePercentile(sorted, 50);
-  const q3 = calculatePercentile(sorted, 75);
-  
-  // 强制校正顺序
-  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],
-    avg: values.reduce((sum, val) => sum + val, 0) / values.length // 计算平均值
-  };
-};
-
-// 批量计算所有统计量
-const calculateAllStats = (data) => {
-  // 1. 作物态Cd指标统计
-  pollutionStats.value = fieldConfig.pollution.map(field => {
-     const stats = calculateFieldStats(data, field.key, field.name);
-     return stats;
-  });
-  
-  // 2. 养分元素统计
-  nutrientStats.value = fieldConfig.nutrient.map(field => 
-    calculateFieldStats(data, field.key, field.name)
-  );
-  
-  // 3. 其他理化性质统计
-  extraStats.value = fieldConfig.extra.map(field => 
-    calculateFieldStats(data, field.key, field.name)
-  );
-  
-  // 更新平均值统计
-  const cd002Stats = pollutionStats.value.find(s => s.key === '002_0002IDW');
-  const cd02Stats = pollutionStats.value.find(s => s.key === '02_002IDW');
-  const cd2Stats = pollutionStats.value.find(s => s.key === '2_02IDW');
-  
-  stats.value = {
-    cd002Avg: cd002Stats?.avg || 0,
-    cd02Avg: cd02Stats?.avg || 0,
-    cd2Avg: cd2Stats?.avg || 0,
-    samples: data.length
-  };
-};
-
 // 构建箱线图数据
 const buildBoxplotData = (statsArray) => {
   return statsArray.map(stat => {
@@ -257,68 +142,74 @@ const buildBoxplotData = (statsArray) => {
 
 // 初始化作物态Cd指标图表
 const initPollutionChart = () => {
-  if (chartInstanceCd) chartInstanceCd.dispose();
-  chartInstanceCd = echarts.init(cdBarChart.value);
-  
-  const xAxisData = fieldConfig.pollution.map(f => f.name);
-  const barData = pollutionStats.value.map(stat => stat.avg || 0);
-  
-  chartInstanceCd.setOption({
-    title: { },
-    tooltip: {
-      trigger: 'axis',
-      formatter: (params) => `${params[0].name}<br/>平均值: ${params[0].value.toFixed(4)}`
-    },
-    grid: { top: 40, right: 15, bottom: 50, left: 40 },
-    xAxis: { type: "category", data: xAxisData, axisLabel: { fontSize: 12,rotate:30 } },
-    yAxis: { type: "value", name: '%', nameTextStyle: { fontSize: 12 }, axisLabel: { fontSize: 11 } },
-    series: [{
-      name: '平均值', type: "bar",
-      itemStyle: { color: (p) => fieldConfig.pollution[p.dataIndex].color },
-      data: barData
-    }]
+  nextTick(() => {
+    // 若图表实例已存在,先销毁避免内存泄漏
+    if (chartInstanceCd) chartInstanceCd.dispose();
+    // 校验 DOM 存在性(防止 ref 未关联到有效 DOM)
+    if (!cdBarChart.value) return;
+    // 初始化 ECharts 实例
+    chartInstanceCd = echarts.init(cdBarChart.value);
+    
+    const xAxisData = fieldConfig.pollution.map(f => f.name);
+    const barData = pollutionStats.value.map(stat => stat.avg || 0);
+    
+    chartInstanceCd.setOption({
+      title: {},
+      tooltip: {
+        trigger: 'axis',
+        formatter: (params) => `${params[0].name}<br/>平均值: ${params[0].value.toFixed(4)}`
+      },
+      grid: { top: 40, right: 15, bottom: '18%', left: '10%' },
+      xAxis: { type: "category", data: xAxisData, axisLabel: { fontSize: 12, rotate: 30 } },
+      yAxis: { type: "value", name: '%', nameTextStyle: { fontSize: 12 }, axisLabel: { fontSize: 11 } },
+      series: [{
+        name: '平均值', type: "bar",
+        itemStyle: { color: (p) => fieldConfig.pollution[p.dataIndex].color },
+        data: barData
+      }]
+    });
   });
 };
 
 // 初始化养分元素图表
 const initNutrientChart = () => {
-  if (chartInstanceNutrient) chartInstanceNutrient.dispose();
-  chartInstanceNutrient = echarts.init(nutrientBoxChart.value);
-  
-  const xAxisData = fieldConfig.nutrient.map(f => f.name);
-  const boxData = buildBoxplotData(nutrientStats.value);
-  
-  chartInstanceNutrient.setOption({
-    title: { text: "主要养分元素分布", left: 'center', textStyle: { fontSize: 14 } },
-    tooltip: {
-      trigger: "item",
-      formatter: (params) => {
-        const stat = nutrientStats.value[params.dataIndex];
-        const fieldConfigItem = fieldConfig.nutrient.find(f => f.key === stat.key);
-        return formatTooltip(stat, fieldConfigItem?.unit);
-      }
-    },
-    grid: { top: 40, right: 15, bottom: 45, left: 40 },
-    xAxis: { 
-      type: "category", 
-      data: xAxisData, 
-      axisLabel: { 
-        fontSize: 11, 
-        rotate: 30,
-      } 
-    },
-    yAxis: { 
-      type: "value", 
-      name: 'mg/kg', 
-      nameTextStyle: { fontSize: 12 }, 
-      axisLabel: { fontSize: 11 } 
-    },
-    series: [{
-      name: '养分元素', 
-      type: "boxplot",
-      itemStyle: { color: '#ee6666', borderColor: '#fac858' },
-      data: boxData
-    }]
+  nextTick(() => {
+    if (chartInstanceNutrient) chartInstanceNutrient.dispose();
+    if (!nutrientBoxChart.value) return;
+    chartInstanceNutrient = echarts.init(nutrientBoxChart.value);
+    
+    const xAxisData = fieldConfig.nutrient.map(f => f.name);
+    const boxData = buildBoxplotData(nutrientStats.value);
+    
+    chartInstanceNutrient.setOption({
+      title: { text: "主要养分元素分布", left: 'center', textStyle: { fontSize: 14 } },
+      tooltip: {
+        trigger: "item",
+        formatter: (params) => {
+          const stat = nutrientStats.value[params.dataIndex];
+          const fieldConfigItem = fieldConfig.nutrient.find(f => f.key === stat.key);
+          return formatTooltip(stat, fieldConfigItem?.unit);
+        }
+      },
+      grid: { top: 40, right: 15, bottom: 45, left: 40 },
+      xAxis: { 
+        type: "category", 
+        data: xAxisData, 
+        axisLabel: { fontSize: 11, rotate: 30 } 
+      },
+      yAxis: { 
+        type: "value", 
+        name: 'mg/kg', 
+        nameTextStyle: { fontSize: 12 }, 
+        axisLabel: { fontSize: 11 } 
+      },
+      series: [{
+        name: '养分元素', 
+        type: "boxplot",
+        itemStyle: { color: '#ee6666', borderColor: '#fac858' },
+        data: boxData
+      }]
+    });
   });
 };
 
@@ -337,7 +228,7 @@ const initExtraChart = () => {
            formatter: (params) => formatTooltip(extraStats.value[params.dataIndex])
         },
          grid: { top: 40, right: 15, bottom: 40, left: 40 },
-         xAxis: { type: "category", data: xAxisData, axisLabel: { fontSize: 11,rotate:30} },
+         xAxis: { type: "category", data: xAxisData, axisLabel: { fontSize: 11} },
         yAxis: { type: "value", name: '%', nameTextStyle: { fontSize: 12 }, axisLabel: { fontSize: 11 } },
         series: [{
           name: '理化性质', type: "boxplot",
@@ -369,9 +260,143 @@ const initCharts = async () => {
     isLoading.value = true;
     error.value = null;
     
-    const data = await fetchData();
-    calculateAllStats(data);
+    const statsData = await fetchData(); // 新接口返回的统计数据
     
+    // -------- 1. 处理「作物态Cd指标」统计 --------
+    pollutionStats.value = fieldConfig.pollution.map(field => {
+      const fieldStats = statsData[field.key]; // 从接口数据中取对应字段的统计
+      if (!fieldStats) {
+        return { 
+          key: field.key, 
+          name: field.name, 
+          min: null, 
+          q1: null, 
+          median: null, 
+          q3: null, 
+          max: null, 
+          avg: null 
+        };
+      }
+      // (可选)单位转换:若接口返回原始值,需按fieldConfig的convert规则转换
+      let min = fieldStats.min;
+      let q1 = fieldStats.q1;
+      let median = fieldStats.median;
+      let q3 = fieldStats.q3;
+      let max = fieldStats.max;
+      let avg = fieldStats.mean;
+      if (field.convert && field.conversionFactor) {
+        min *= field.conversionFactor;
+        q1 *= field.conversionFactor;
+        median *= field.conversionFactor;
+        q3 *= field.conversionFactor;
+        max *= field.conversionFactor;
+        avg *= field.conversionFactor;
+      }
+      return {
+        key: field.key,
+        name: field.name,
+        min,
+        q1,
+        median,
+        q3,
+        max,
+        avg
+      };
+    });
+
+    // -------- 2. 处理「主要养分元素」统计 --------
+    nutrientStats.value = fieldConfig.nutrient.map(field => {
+      const fieldStats = statsData[field.key];
+      if (!fieldStats) {
+        return { 
+          key: field.key, 
+          name: field.name, 
+          min: null, 
+          q1: null, 
+          median: null, 
+          q3: null, 
+          max: null, 
+          avg: null 
+        };
+      }
+      // (可选)单位转换
+      let min = fieldStats.min;
+      let q1 = fieldStats.q1;
+      let median = fieldStats.median;
+      let q3 = fieldStats.q3;
+      let max = fieldStats.max;
+      let avg = fieldStats.mean;
+      if (field.convert && field.conversionFactor) {
+        min *= field.conversionFactor;
+        q1 *= field.conversionFactor;
+        median *= field.conversionFactor;
+        q3 *= field.conversionFactor;
+        max *= field.conversionFactor;
+        avg *= field.conversionFactor;
+      }
+      return {
+        key: field.key,
+        name: field.name,
+        min,
+        q1,
+        median,
+        q3,
+        max,
+        avg
+      };
+    });
+
+    // -------- 3. 处理「其他理化性质」统计 --------
+    extraStats.value = fieldConfig.extra.map(field => {
+      const fieldStats = statsData[field.key];
+      if (!fieldStats) {
+        return { 
+          key: field.key, 
+          name: field.name, 
+          min: null, 
+          q1: null, 
+          median: null, 
+          q3: null, 
+          max: null, 
+          avg: null 
+        };
+      }
+      // (可选)单位转换
+      let min = fieldStats.min;
+      let q1 = fieldStats.q1;
+      let median = fieldStats.median;
+      let q3 = fieldStats.q3;
+      let max = fieldStats.max;
+      let avg = fieldStats.mean;
+      if (field.convert && field.conversionFactor) {
+        min *= field.conversionFactor;
+        q1 *= field.conversionFactor;
+        median *= field.conversionFactor;
+        q3 *= field.conversionFactor;
+        max *= field.conversionFactor;
+        avg *= field.conversionFactor;
+      }
+      return {
+        key: field.key,
+        name: field.name,
+        min,
+        q1,
+        median,
+        q3,
+        max,
+        avg
+      };
+    });
+
+    // -------- 更新「样本数量」等汇总统计 --------
+    const firstFieldKey = fieldConfig.pollution[0]?.key;
+    stats.value = {
+      cd002Avg: pollutionStats.value.find(s => s.key === '002_0002IDW')?.avg || 0,
+      cd02Avg: pollutionStats.value.find(s => s.key === '02_002IDW')?.avg || 0,
+      cd2Avg: pollutionStats.value.find(s => s.key === '2_02IDW')?.avg || 0,
+      samples: statsData[firstFieldKey]?.count || 0 // 从接口的count字段取样本数
+    };
+
     // 初始化图表
     initPollutionChart();
     initNutrientChart();

+ 38 - 121
src/components/soilcdStatistics/effcdStatistics.vue

@@ -57,6 +57,7 @@ const extraBoxChart = ref(null);
 let chartInstanceCd = null;
 let chartInstanceNutrient = null;
 let chartInstanceExtra = null;
+const chartInstancePopup =null;
 
 // 响应式状态
 const isLoading = ref(true);
@@ -103,112 +104,42 @@ const fieldConfig = {
 // 数据请求
 const fetchData = async () => {
   try {
-    const apiUrl = '/api/vector/export/all?table_name=EffCd_input_data&format=json';
-    const response = await api8000.get(apiUrl); // 使用 api8000 实例
-    
-    let data = response.data;
-    
-    // 处理可能的字符串响应
-    if (typeof data === 'string') {
-      try {
-        // 替换 NaN 为 null
-        const cleanedData = data.replace(/\bNaN\b/g, 'null');
-        data = JSON.parse(cleanedData);
-      } catch (parseErr) {
-        throw new Error('接口返回的是字符串,但 JSON 解析失败');
-      }
-    }
-    
-    // 处理对象中的 NaN 值
-    if (typeof data === 'object' && data !== null) {
-      const replaceNaN = (obj) => {
-        for (const key in obj) {
-          if (typeof obj[key] === 'object' && obj[key] !== null) {
-            replaceNaN(obj[key]);
-          } else if (typeof obj[key] === 'number' && isNaN(obj[key])) {
-            obj[key] = null;
-          } else if (obj[key] === 'NaN') {
-            obj[key] = null;
-          }
-        }
-      };
-      replaceNaN(data);
-    }
-    
-    // 接口返回格式判断(GeoJSON或直接数组)
-    const rawData = data.features 
-      ? data.features.map(f => f.properties) 
-      : data;
-      
-    return rawData;
+    // 实际项目中替换为真实API
+     const res = await axios.get("http://localhost:8000/api/vector/stats/EffCd_input_data");
+     return res.data;
+
   } catch (err) {
     throw new Error('数据加载失败: ' + err.message);
   }
 };
 
-// 核心:分位数计算(参考灌溉水的精准计算逻辑)
-const calculatePercentile = (sortedArray, percentile) => {
-  const n = sortedArray.length;
-  if (n === 0) return null;
-  if (percentile <= 0) return sortedArray[0];
-  if (percentile >= 100) return sortedArray[n - 1];
-  
-  // 采用与Excel QUARTILE.INC一致的算法
-  const index = (n - 1) * (percentile / 100);
-  const lowerIndex = Math.floor(index);
-  const upperIndex = lowerIndex + 1;
-  const fraction = index - lowerIndex;
-  
-  if (upperIndex >= n) return sortedArray[lowerIndex];
-  return sortedArray[lowerIndex] + fraction * (sortedArray[upperIndex] - sortedArray[lowerIndex]);
-};
-
 // 计算单个字段的箱线图统计量(带顺序校正)
-const calculateFieldStats = (data, fieldKey, fieldName) => {
-  // 获取字段配置
-  const fieldConfigItem = [
-    ...fieldConfig.pollution,
-    ...fieldConfig.nutrient,
-    ...fieldConfig.extra
-  ].find(f => f.key === fieldKey);
-  
-  // 提取并清洗数据
-  const rawValues = data.map(item => item[fieldKey]);
-  const values = rawValues
-    .map((val, idx) => {
-      let num = Number(val);
-      
-      // 处理无效值
-      if (isNaN(num)) {
-        return null;
-      }
-      
-      // 应用单位转换
-      if (fieldConfigItem?.convert && fieldConfigItem.conversionFactor) {
-        num = num * fieldConfigItem.conversionFactor;
-      }
-      
-      return num;
-    })
-    .filter(v => v !== null);
-  
-  if (values.length === 0) {
-    return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null };
+const calculateFieldStats = (statsData, fieldKey, fieldName, fieldConfigItem) => {
+  const fieldStats = statsData[fieldKey]; // 从接口数据中取当前字段的统计结果
+  if (!fieldStats) {
+    return { key: fieldKey, name: fieldName, min: null, q1: null, median: null, q3: null, max: null, mean: null };
   }
-  
-  // 排序并计算统计量
-  const sorted = [...values].sort((a, b) => a - b);
-  const min = sorted[0];
-  const max = sorted[sorted.length - 1];
-  const q1 = calculatePercentile(sorted, 25);
-  const median = calculatePercentile(sorted, 50);
-  const q3 = calculatePercentile(sorted, 75);
 
-  const mean = values.reduce((sum,val)=>sum+val,0)/values.length;
-  
-  // 强制校正顺序(核心修复)
+  // 提取原始统计值
+  let min = fieldStats.min;
+  let q1 = fieldStats.q1;
+  let median = fieldStats.median;
+  let q3 = fieldStats.q3;
+  let max = fieldStats.max;
+  let mean = fieldStats.mean;
+
+  // 处理「单位转换」(与原代码逻辑一致,若配置了convert则乘以系数)
+  if (fieldConfigItem?.convert && fieldConfigItem.conversionFactor) {
+    min *= fieldConfigItem.conversionFactor;
+    q1 *= fieldConfigItem.conversionFactor;
+    median *= fieldConfigItem.conversionFactor;
+    q3 *= fieldConfigItem.conversionFactor;
+    max *= fieldConfigItem.conversionFactor;
+    mean *= fieldConfigItem.conversionFactor;
+  }
+
+  // 强制校正统计量顺序(确保 min ≤ q1 ≤ median ≤ q3 ≤ max)
   const sortedStats = [min, q1, median, q3, max].sort((a, b) => a - b);
-  
   return {
     key: fieldKey,
     name: fieldName,
@@ -222,29 +153,29 @@ const calculateFieldStats = (data, fieldKey, fieldName) => {
 };
 
 // 批量计算所有字段的统计量(按图表类型缓存)
-const calculateAllStats = (data) => {
+const calculateAllStats = (statsData) => {
   // 1. 污染指标统计(与x轴顺序一致)
   pollutionStats.value = fieldConfig.pollution.map(field => 
-    calculateFieldStats(data, field.key, field.name)
+    calculateFieldStats(statsData, field.key, field.name, field)
   );
   
   // 2. 养分元素统计(与x轴顺序一致)
   nutrientStats.value = fieldConfig.nutrient.map(field => 
-    calculateFieldStats(data, field.key, field.name)
+    calculateFieldStats(statsData, field.key, field.name, field)
   );
   
   // 3. 其他理化性质统计(与x轴顺序一致)
   extraStats.value = fieldConfig.extra.map(field => 
-    calculateFieldStats(data, field.key, field.name)
+    calculateFieldStats(statsData, field.key, field.name, field)
   );
   
-  // 更新平均值统计
-  const totalCdStats = pollutionStats.value.find(s => s.key === 'TCd_IDW');
-  const effCdStats = pollutionStats.value.find(s => s.key === 'Cdsolution');
+  // 更新「样本数量、平均值统计(从接口数据中取mean更准确)
+  const totalCdStats = pollutionStats.value.find(s => s.key === 'TCd_IDW'); // 替换为实际「总Cd」字段名
+  const effCdStats = pollutionStats.value.find(s => s.key === 'Cdsolution'); // 替换为实际「有效态Cd」字段名
   stats.value = {
     totalCdAvg: totalCdStats ? totalCdStats.mean : 0,
     effCdAvg: effCdStats ? effCdStats.mean : 0,
-    samples: data.length
+    samples: statsData[Object.keys(statsData)[0]]?.count || 0 // 取第一个字段的count作为样本数
   };
 };
 
@@ -350,22 +281,8 @@ const initExtraChart = () => {
             formatter: (params) => formatTooltip(extraStats.value[params.dataIndex])
           },
           grid: { top: 40, right: 15, bottom: 40, left: 40 },
-          xAxis: { 
-            type: "category", 
-            data: xAxisData, 
-            axisLabel: { 
-              fontSize: 11, 
-              rotate: 30,
-              interval: 0, // 强制显示所有标签
-              formatter: (value) => value.length > 8 ? value.substring(0, 8) + '...' : value
-            } 
-          },
-          yAxis: { 
-            type: "value", 
-            name: '%', 
-            nameTextStyle: { fontSize: 12 }, 
-            axisLabel: { fontSize: 11 } 
-          },
+          xAxis: { type: "category", data: xAxisData, axisLabel: { fontSize: 11 } },
+          yAxis: { type: "value", name: '%', nameTextStyle: { fontSize: 12 }, axisLabel: { fontSize: 11 } },
           series: [{
             name: '理化性质', type: "boxplot",
             itemStyle: { color: (params) => fieldConfig.extra[params.dataIndex].color },

+ 26 - 73
src/components/soilcdStatistics/fluxcdStatictics.vue

@@ -89,43 +89,11 @@ const fieldConfig = {
 // 数据请求
 const fetchData = async () => {
   try {
-    const apiUrl = '/api/vector/export/all?table_name=FluxCd_input_data&format=json';
-    const response = await api8000.get(apiUrl); // 使用 api8000 实例
-    
-    let data = response.data;
-    
-    // 处理可能的字符串响应
-    if (typeof data === 'string') {
-      try {
-        // 替换 NaN 为 null
-        const cleanedData = data.replace(/\bNaN\b/g, 'null');
-        data = JSON.parse(cleanedData);
-      } catch (parseErr) {
-        throw new Error('接口返回的是字符串,但 JSON 解析失败');
-      }
-    }
-    
-    // 处理对象中的 NaN 值
-    if (typeof data === 'object' && data !== null) {
-      const replaceNaN = (obj) => {
-        for (const key in obj) {
-          if (typeof obj[key] === 'object' && obj[key] !== null) {
-            replaceNaN(obj[key]);
-          } else if (typeof obj[key] === 'number' && isNaN(obj[key])) {
-            obj[key] = null;
-          } else if (obj[key] === 'NaN') {
-            obj[key] = null;
-          }
-        }
-      };
-      replaceNaN(data);
-    }
-    
-    // 接口返回格式判断(GeoJSON或直接数组)
-    const rawData = data.features 
-      ? data.features.map(f => f.properties) 
-      : data;
-      
+    const apiUrl = 'http://localhost:8000/api/vector/stats/FluxCd_input_data';
+    const response = await axios.get(apiUrl);
+    const rawData = response.data.features 
+      ? response.data.features.map(f => f.properties) 
+      : response.data;
     return rawData;
   } catch (err) {
     throw new Error('数据加载失败: ' + err.message);
@@ -149,37 +117,21 @@ const calculatePercentile = (sortedArray, percentile) => {
 };
 
 // 计算单个字段的统计量
-const calculateFieldStats = (data, fieldKey, fieldName) => {
-  const rawValues = data.map(item => item[fieldKey]);
-  const values = rawValues
-    .map((val, idx) => {
-      // 更严格的数值校验
-      if (val === null || val === undefined || val === '' || isNaN(Number(val))) {
-        return null;
-      }
-      const num = Number(val);
-      // 过滤极端值(根据业务需求调整阈值)
-      if (num < -1000000 || num > 1000000) {
-        return null;
-      }
-      return num;
-    })
-    .filter(v => v !== null);
-  
-  // 处理无有效数据的情况
-  if (values.length === 0) {
+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 };
   }
-  
-  // 排序并计算分位数(保持原逻辑)
-  const sorted = [...values].sort((a, b) => a - b);
-  const min = sorted[0];
-  const max = sorted[sorted.length - 1];
-  const q1 = calculatePercentile(sorted, 25);
-  const median = calculatePercentile(sorted, 50);
-  const q3 = calculatePercentile(sorted, 75);
-  
-  // 强制校正顺序
+
+  // 提取预统计值
+  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,
@@ -193,19 +145,20 @@ const calculateFieldStats = (data, fieldKey, fieldName) => {
 };
 
 // 计算所有统计数据(拆分两组)
-const calculateAllStats = (data) => {
-  // 初始Cd统计
+const calculateAllStats = (statsData) => {
+  // 1. 初始Cd统计(与配置顺序一致)
   initialCdStats.value = fieldConfig.initialCd.map(indicator => 
-    calculateFieldStats(data, indicator.key, indicator.name)
+    calculateFieldStats(statsData, indicator.key, indicator.name)
   );
   
-  // 其他指标统计
+  // 2. 其他指标统计(与配置顺序一致)
   otherIndicatorsStats.value = fieldConfig.otherIndicators.map(indicator => 
-    calculateFieldStats(data, indicator.key, indicator.name)
+    calculateFieldStats(statsData, indicator.key, indicator.name)
   );
   
-  // 更新样本数
-  stats.value.samples = data.length;
+  // 3. 更新样本数(从预统计数据中取第一个字段的count)
+  const firstFieldKey = fieldConfig.initialCd[0]?.key || fieldConfig.otherIndicators[0]?.key;
+  stats.value.samples = statsData[firstFieldKey]?.count || 0;
 };
 
 // 构建箱线图数据(通用函数)

+ 7 - 25
src/views/User/HmOutFlux/atmosDeposition/airSampleData.vue

@@ -3,22 +3,22 @@
     <!-- 系统标题区域 -->
     <div class="header-section">
       <div class="header-content">
-        <h1 class="system-title">韶关市大气污染监测系统</h1>
+        <h1 class="system-title">韶关市大气重金属污染采样</h1>
         <div class="calculation-selector">
-          <span class="selector-title">计算方式:</span>
+          <span class="selector-title">采样方式:</span>
           <select 
             v-model="calculationMethod" 
             class="calculation-select"
           >
-            <option value="weight">按重量计算</option>
-            <option value="volume">按体积计算</option>
+            <option value="weight">按重量采样</option>
+            <option value="volume">按体积采样</option>
           </select>
         </div>
       </div>
     </div>
     
     <!-- 地图展示区域 -->
-    <div class="dashboard-section map-section">
+    <div class="dashboard-section ">
       <div class="section-header">
         <div class="section-icon">🗺️</div>
         <h2 class="section-title">采样点地理分布</h2>
@@ -38,7 +38,7 @@
           <div class="section-icon">📋</div>
           <h2 class="section-title">采样点数据详情</h2>
           <div class="data-info">
-            <span class="info-item">当前计算方式: {{ calculationMethod === 'weight' ? '按重量' : '按体积' }}</span>
+            <span class="info-item">当前采样方式: {{ calculationMethod === 'weight' ? '按重量' : '按体积' }}</span>
             <span class="info-item">最后更新: 2025-08-16</span>
           </div>
         </div>
@@ -58,7 +58,6 @@
         <div class="dashboard-card chart-card">
           <div class="chart-header">
             <h3>各区县平均大气重金属污染柱状图</h3>
-            <p>大气污染物区域分布情况 ({{ calculationMethod === 'weight' ? 'mg/m³' : 'μg/m³' }})</p>
           </div>
           <div class="chart-container">
             <AirsampleChart :calculation-method="calculationMethod"/>
@@ -87,20 +86,13 @@ const toggleMapType = () => {
 
 <style scoped>
 /* 基础样式重置 */
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border极;
-  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-}
-
 .page-container {
   display: flex;
   flex-direction: column;
   min-height: 100vh;
   background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
   padding: 25px;
-  gap: 30px;
+  gap: 20px;
   position: relative;
   overflow-x: hidden;
 }
@@ -108,7 +100,6 @@ const toggleMapType = () => {
 /* 页眉区域 */
 .header-section {
    text-align: center;
-  padding: 30px 0 20px;
   position: relative;
 }
 
@@ -216,13 +207,6 @@ const toggleMapType = () => {
   margin-bottom: 20px;
 }
 
-.map-section {
-  background: white;
-  border-radius: 16px;
-  padding: 25px;
-  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
-}
-
 .section-header {
   display: flex;
   align-items: center;
@@ -411,8 +395,6 @@ const toggleMapType = () => {
 }
 
 .chart-header {
-  margin-bottom: 15px;
-  padding-bottom: 10px;
   border-bottom: 1px solid #e2e8f0;
 }
 

+ 6 - 27
src/views/User/HmOutFlux/atmosDeposition/heavyMetalEnterprise.vue

@@ -3,12 +3,12 @@
     <!-- 页面标题区域 -->
     <div class="header-section">
       <div class="header-content">
-        <h1 class="system-title">韶关市涉重企业环境数据监测系统</h1>
+        <h1 class="system-title">韶关市涉重企业重金属排放调查</h1>
       </div>
     </div>
     
     <!-- 地图展示区域 -->
-    <div class="dashboard-section map-section">
+    <div class="dashboard-section ">
       <div class="section-header">
         <div class="section-icon">🗺️</div>
         <h2 class="section-title">涉重企业地理分布</h2>
@@ -42,7 +42,7 @@
       <div class="dashboard-section chart-section">
         <div class="section-header">
           <div class="section-icon">📊</div>
-          <h2 class="section-title">大气颗粒物排放分析</h2>
+          <h2 class="section-title">大气颗粒物排放统计</h2>
           <div class="emission-info">
             <span class="info-item">单位: 吨/年 (t/a)</span>
             <span class="info-item">统计周期: 2025年</span>
@@ -51,17 +51,11 @@
         <div class="chart-card">
           <div class="chart-header">
             <h3>各区县企业平均大气颗粒物排放量</h3>
-            <p>重金属企业大气污染物排放分布情况</p>
           </div>
           <div class="chart-container">
             <HeavyMetalEnterprisechart/>
           </div>
-          <div class="chart-legend">
-            <div class="legend-item">
-              <div class="legend-color primary"></div>
-              <span>颗粒物排放量</span>
-            </div>
-          </div>
+          
         </div>
       </div>
     </div>
@@ -76,20 +70,13 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
 
 <style scoped>
 /* 基础样式重置 */
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-}
-
 .page-container {
   display: flex;
   flex-direction: column;
   min-height: 100vh;
   background: linear-gradient(135deg, #f0f9ff 0%, #e9ecef 100%);
   padding: 25px;
-  gap: 30px;
+  gap: 20px;
   position: relative;
   overflow-x: hidden;
 }
@@ -97,7 +84,6 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
 /* 页眉区域 */
 .header-section {
  text-align: center;
-  padding: 30px 0 20px;
   position: relative;
 }
 
@@ -195,13 +181,6 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
   margin-bottom: 20px;
 }
 
-.map-section {
-  background: white;
-  border-radius: 16px;
-  padding: 25px;
-  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
-}
-
 .section-header {
   display: flex;
   align-items: center;
@@ -324,7 +303,7 @@ import HeavyMetalEnterprisechart from '@/components/atmpollution/heavyMetalEnter
 
 /* 图表区域 - 固定高度 */
 .chart-card {
-  height: 750px;
+  height: 600px;
   padding: 20px;
   background: white;
   border-radius: 16px;

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

@@ -3,7 +3,7 @@
     <!-- 页面标题 -->
     <div class="section-header">
       <div class="section-icon">📊</div>
-      <h1 class="page-title">韶关市河流断面水质监测分析系统</h1>
+      <h1 class="page-title">韶关市河流断面采样</h1>
     </div>
     
     <!-- 地图展示区域 -->
@@ -25,7 +25,7 @@
       <div class="dashboard-section table-section">
         <div class="section-header">
           <div class="section-icon">📋</div>
-          <h2 class="component-title">断面水质数据详情</h2>
+          <h2 class="component-title">断面采样数据详情</h2>
           <div class="table-info">
             <span class="info-item">数据更新时间: 2025-08-16</span>
           </div>
@@ -83,7 +83,6 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 
 <style scoped>
 /* 基础样式重置 */
-
 .cross-container {
   display: flex;
   flex-direction: column;
@@ -174,7 +173,6 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 /* 数据卡片 - 添加滚动条 */
 .data-card {
   height: 550px;
-  padding: 0; /* 移除内边距 */
   display: flex;
   flex-direction: column;
 }
@@ -188,7 +186,6 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 /* 图表卡片 */
 .chart-card {
   height: 600px;
-  padding: 0; /* 移除内边距 */
   display: flex;
   flex-direction: column;
 }
@@ -196,7 +193,7 @@ import crosssectionmap from '@/components/irrpollution/crosssectionmap.vue';
 .chart-container {
   flex: 1;
   overflow: hidden; /* 确保图表不会溢出 */
-  padding: 20px;
+  padding: 25px;
 }
 
 .chart-header {

+ 5 - 13
src/views/User/HmOutFlux/irrigationWater/irriWaterSampleData.vue

@@ -67,13 +67,6 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
 
 <style scoped>
 /* 基础样式重置 */
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-}
-
 .page-container {
   display: flex;
   flex-direction: column;
@@ -88,14 +81,13 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
 /* 页眉样式 */
 .header {
   border-radius: 16px;
-  padding: 25px;
+  padding: 0 0 25px ; 
 }
 
 .header-content {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 20px;
 }
 
 .header-left h1 {
@@ -459,13 +451,13 @@ import irrwatermap from '@/components/irrpollution/irrwatermap.vue';
     height: 400px;
   }
 }
-
-@media (max-width: 768px) {
-  .page-container {
-    padding: 15px;
+.page-container {
+    padding: 25px;
     gap: 20px;
   }
   
+@media (max-width: 768px) {
+  
   .header {
     padding: 20px;
   }

+ 5 - 17
src/views/User/HmOutFlux/irrigationWater/samplingMethodDevice1.vue

@@ -38,7 +38,7 @@
           <div class="image-card">
             <el-image :src="image3" alt="采样容器" class="sampling-image"></el-image>
             <div class="image-info">
-              <h3>样容器</h3>
+              <h3>样容器</h3>
               <p>500mL白色聚乙烯瓶,符合水质采样标准</p>
             </div>
           </div>
@@ -83,26 +83,14 @@
         <div class="field-gallery">
           <div class="field-card">
             <el-image :src="fieldImage1" alt="工作人员采样现场" class="sampling-image"></el-image>
-            <div class="field-info">
-              <!--<h3>河流采样现场</h3>
-              <p>多云天气下的河流采样工作</p>-->
-            </div>
           </div>
           
           <div class="field-card">
             <el-image :src="fieldImage2" alt="工作人员采样现场" class="sampling-image"></el-image>
-            <div class="field-info">
-              <!--<h3>水渠采样现场</h3>
-              <p>小雨天气下的水渠采样工作</p>-->
-            </div>
           </div>
           
           <div class="field-card">
             <el-image :src="fieldImage3" alt="工作人员采样现场" class="sampling-image"></el-image>
-            <div class="field-info">
-              <!--<h3>瀑布区域采样</h3>
-              <p>特殊地形条件下的采样工作</p>-->
-            </div>
           </div>
         </div>
       </div>
@@ -244,7 +232,7 @@ h2 {
 
 .sampling-image {
   width: 100%;
-  height: 230px;
+  height: 250px;
   display: block;
   object-fit: cover;
   transition: transform 0.4s ease;
@@ -255,18 +243,18 @@ h2 {
   transform: scale(1.05);
 }
 
-.image-info, .field-info {
+.image-info {
   padding: 20px;
 }
 
-.image-info h3, .field-info h3 {
+.image-info h3,  h3 {
   color: #1a365d;
   font-size: 1.25rem;
   margin-top: 0;
   margin-bottom: 10px;
 }
 
-.image-info p, .field-info p {
+.image-info p p {
   font-size: 0.95rem;
   color: #4a5568;
   margin: 0;

+ 3 - 2
src/views/User/dataStatistics/DetectionStatistics.vue

@@ -53,8 +53,9 @@ export default {
 .layout-container {
   display: grid;
   grid-template-columns: 1fr 1fr; /* 三列等宽 */
-  gap: 4px; /* 列之间的间距 */
-  padding: 0 0px;
+  gap: 20px; /* 列之间的间距 */
+  padding: 20px;
+  background: linear-gradient(135deg, rgba(230, 247, 255, 0.7) 0%, rgba(240, 248, 255, 0.7) 100%);
   box-sizing: border-box;
   justify-items: start;
   align-items: start;    /* 垂直对齐顶部,避免拉伸变形 */

+ 8 - 0
src/views/User/dataStatistics/LandCultivatedStatistics.vue

@@ -1,5 +1,8 @@
 <template>
+  <div class="container">
     <div class="chart-wrapper" ref="chartRef"></div>  
+  </div>
+    
 </template>
 
 <script setup>
@@ -132,6 +135,11 @@ onMounted(async () => {
 </script>
 
 <style scoped>
+
+.container {
+  padding: 20px;
+  background: linear-gradient(135deg, rgba(230, 247, 255, 0.7) 0%, rgba(240, 248, 255, 0.7) 100%);
+}
 .chart-wrapper {
   width: 100%;
   height: 500px;

+ 3 - 0
src/views/User/dataStatistics/SoilCdStatistics.vue

@@ -42,6 +42,9 @@ export default {
 .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;

+ 12 - 10
src/views/User/dataStatistics/SoilacidificationStatistics.vue

@@ -10,42 +10,44 @@
     <!-- 第二列:酸化加剧数据组件 -->
     <div class="column column-2">
       <div class="component-container">
-        <RefluxcdStatictics />
+        <refluxcedataStatictics />
       </div>
     </div>
   </div>
 </template>
 
 <script>
-import ReducedataStatistics from '@/components/cdStatictics/reducedataStatistics.vue';
-import RefluxcdStatictics from '@/components/cdStatictics/refluxcdStatictics.vue';
+
+import ReducedataStatistics from '@/components/soilStatictics/reducedataStatistics.vue';
+import refluxcedataStatictics from '@/components/soilStatictics/refluxcedataStatictics.vue'
 
 export default {
   components: {
     ReducedataStatistics,
-    RefluxcdStatictics,
+    refluxcedataStatictics
   }
 }
 </script>
 
 <style scoped>
-/* 核心:网格布局统一控制尺寸 */
+/* 核心:网格布局统一控制尺寸 
 .layout-container {
   display: grid;
-  grid-template-columns: 1fr 1fr;  /* 两列等宽 */
+  grid-template-columns: 1fr 1fr;  /* 两列等宽 
   height: 400px;
-  gap: 16px;                      /* 列/行间距 */
-  padding: 16px;                  /* 内边距 */
+  gap: 16px;                      /* 列/行间距 
+  padding: 16px;                  /* 内边距 
   box-sizing: border-box;
   width: 100%;
   min-height: 100vh;
-}
+}*/
 
 /* 统一子组件外层容器:确保填充网格单元格 */
 .component-container {
-  width: 500px;
+  width: 1000px;
   height: 500px;
   padding: 16px;
+  margin: 20px;
   border: 1px solid #e5e7eb;
   border-radius: 8px;
   overflow: hidden;

+ 59 - 0
src/views/User/farmlandQualityAssessment/farmlandQualityAssessment.vue

@@ -72,6 +72,7 @@ export default {
     return {
       map: null,
       geoJSONLayer: null,
+      shaoguanBoundaryLayer:null,
       multiPolygon: null, 
       categoryColors,
       statistics: {
@@ -134,6 +135,10 @@ export default {
       
       // 初始化GeoJSON图层 - 传递TMap对象
       this.initMapWithGeoJSON(geojsonData, TMap);
+
+      //加载并初始化韶关边界图层
+      const shaoguanBoundaryGeojson = await this.fetchShaoguanBoundary();
+      this.initShaoguanBoundaryLayer(shaoguanBoundaryGeojson,TMap);
     },
     
     // 加载SDK
@@ -160,6 +165,59 @@ export default {
         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}`);
+      }
+      
+      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) {
@@ -247,6 +305,7 @@ export default {
         // 更新几何体以应用新样式
         this.multiPolygon.updateGeometries(polygons);
         
+        this.geoJSONLayer.setZIndex(100);
       
       } catch (error) {
         console.error('初始化GeoJSON图层失败:', error);

+ 0 - 14
src/views/User/heavyMetalFluxCalculation/inputFluxCalculation/waterdata/rivermessage.vue

@@ -77,20 +77,6 @@ onMounted(() => {
 </script>
 
 <style scoped>
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-}
-
-body {
-  background-color: #f5f9fc;
-  color: #333;
-  line-height: 1.6;
-  padding: 20px;
-}
-
 .container {
   max-width: 1200px;
   margin: 0 auto;

+ 0 - 12
src/views/User/introduction/Introduce.vue

@@ -103,18 +103,6 @@ const setVideoStyle = (video: HTMLVideoElement) => {
 </script>
 
 <style scoped lang="scss">
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-}
-
-body {
-  background-color: white;
-  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* 更美观的字体 */
-  padding: 0;
-}
-
 .software-intro-container {
   width: 95%;
   margin: 0 auto;