yangtaodemon 1 сар өмнө
parent
commit
3bc354aadf

+ 172 - 23
src/views/User/cadmiumPrediction/CropCadmiumPrediction.vue

@@ -1,8 +1,7 @@
 <template>
   <div class="container">
     <!-- 顶部操作栏 -->
-    <div class="toolbar">
-      <!-- 文件上传区域 -->
+    <!-- <div class="toolbar">
       <div class="upload-section">
         <input type="file" ref="fileInput" accept=".csv" @change="handleFileUpload" style="display: none">
         <el-button class="custom-button" @click="triggerFileUpload">
@@ -19,7 +18,6 @@
         <el-icon class="upload-icon"><Document /></el-icon>  
         上传并计算
         </el-button>
-        <!-- 添加从数据库计算按钮 -->
         <el-button 
           class="custom-button" 
           :loading="isCalculatingFromDB" 
@@ -28,7 +26,7 @@
         <el-icon class="upload-icon"><Box /></el-icon>  
         从数据库计算
         </el-button>
-      </div>
+      </div> -->
       <!-- 操作按钮 -->
       <!-- <div class="action-buttons">
         <el-button class="custom-button" :disabled="!mapBlob" @click="exportMap">
@@ -41,28 +39,14 @@
           <el-icon class="upload-icon"><Download /></el-icon>
           导出数据</el-button>
       </div> -->
-    </div>
+    <!-- </div> -->
 
     <!-- 主体内容区 -->
     <div class="content-area">
       <!-- 地图区域 - 单独一行 -->
       <div class="map-section">
         <h3>水稻Cd预测地图</h3>
-        <div v-if="loadingTownshipMap" class="loading-container">
-          <el-icon class="loading-icon"><Loading /></el-icon>
-          <span>乡镇地图加载中...</span>
-        </div>
-        <div class="township-map-wrapper">
-          <!-- Leaflet地图容器 -->
-        <div class="town-map-title">水稻Cd含量预测镇域统计分布图</div>
-        <div 
-          v-show="!loadingTownshipMap" 
-          ref="townshipMapRef" 
-          class="township-map-container"
-        ></div>
-        </div>
-        
-        <!-- 颜色图例 -->
+         <!-- 颜色图例 -->
         <div class="legend">
           <div class="legend-item">
             <div class="color-box" style="background-color: #15b392;"></div>
@@ -77,6 +61,43 @@
             <span>超标区间 (≥0.3 mg/kg)</span>
           </div>
         </div>
+        <div v-if="loadingTownshipMap" class="loading-container">
+          <el-icon class="loading-icon"><Loading /></el-icon>
+          <span>乡镇地图加载中...</span>
+        </div>
+        <div class="township-map-wrapper">
+          <!-- Leaflet地图容器 -->
+        <div class="town-map-title">水稻Cd含量预测镇域统计分布图</div>
+        <div 
+          v-show="!loadingTownshipMap" 
+          ref="townshipMapRef" 
+          class="township-map-container"
+        ></div>
+        </div>
+         <!-- 新增:要素详细信息栏 -->
+        <div v-if="currentFeatureInfo" class="feature-info-panel">
+          <h4 style="margin-top: 0; color: #0066CC; border-bottom: 1px solid #eee; padding-bottom: 10px;">
+            地块详细信息
+          </h4>
+          <ul style="list-style: none; padding: 0; margin: 0;">
+            <li style="margin-bottom: 8px; font-size: 14px;">
+              <strong>水稻镉含量:</strong>{{ currentFeatureInfo.avgmean.toFixed(4) }} mg/kg
+            </li>
+            <li style="margin-bottom: 8px; font-size: 14px;">
+              <strong>镉输入通量:</strong>{{ currentFeatureInfo.lncd.toFixed(4) }} g/ha/a
+              <!-- 若有单位可补充:{{ currentFeatureInfo.lncdUnit }} -->
+            </li>
+            <li style="margin-bottom: 8px; font-size: 14px;">
+              <strong>镉输出通量:</strong>{{ currentFeatureInfo.outcd.toFixed(4) }} g/ha/a
+            </li>
+            <li style="margin-bottom: 8px; font-size: 14px;">
+              <strong>镉净通量:</strong>{{ currentFeatureInfo.netcd.toFixed(4) }} g/ha/a
+            </li>
+            <li style="margin-bottom: 8px; font-size: 14px;">
+              <strong>当年镉浓度:</strong>{{ currentFeatureInfo.endcd.toFixed(4) }} g/ha/a
+            </li>
+          </ul>
+        </div>
         <div v-if="!loadingTownshipMap && !townshipMapInstance" class="no-data">
           <el-icon><Location /></el-icon>
           <p>暂无乡镇边界数据</p>
@@ -188,6 +209,7 @@ export default {
   },
   data() {
     return {
+      currentFeatureInfo: null, // 存储当前点击要素的详细信息
       mapContainerStyle: {
       width: '100%',
       height: '800px'
@@ -255,6 +277,7 @@ export default {
     // 组件销毁前移除事件监听,避免内存泄漏
     window.removeEventListener('resize', this.handleResize);
     if (this.townshipMapInstance) {
+      this.townshipMapInstance.off('click', this.handleWmsFeatureClick);
       this.townshipMapInstance.remove();
       this.townshipMapInstance = null;
     }
@@ -724,8 +747,8 @@ renderTownshipMap() {
     }).addTo(this.townshipMapInstance);
 
     // 添加GeoServer WMS图层作为底图
-    const wmsLayer = L.tileLayer.wms('https://www.soilgd.com/geoserver/soilgd/wms', {
-      layers: 'soilgd:farmland_data', // 替换为你的图层名称
+    const wmsLayer = L.tileLayer.wms('http://localhost:8080/geoserver/soilgd/wms', {
+      layers: 'soilgd:shapeMap', // 替换为你的图层名称
       format: 'image/png',
       transparent: true,
       version: '1.1.0',
@@ -749,6 +772,7 @@ renderTownshipMap() {
     }
     
     console.log('地图渲染完成');
+    this.townshipMapInstance.on('click', this.handleWmsFeatureClick);
 
   } catch (error) {
     console.error('渲染地图时发生错误:', error);
@@ -757,6 +781,74 @@ renderTownshipMap() {
 },
 
 
+async handleWmsFeatureClick(e) {
+  try {
+    const { lat, lng } = e.latlng;
+    const mapSize = this.townshipMapInstance.getSize();
+
+    // 1. 转换坐标:地理坐标 → 地图像素坐标(Leaflet 默认 EPSG:4326)
+    const containerPoint = this.townshipMapInstance.latLngToContainerPoint([lat, lng]);
+    const x = Math.round(containerPoint.x);
+    const y = Math.round(containerPoint.y);
+
+    // 2. 构造 GetFeatureInfo 请求 URL(强制 JSON + 修正参数)
+    const wmsBaseUrl = 'http://localhost:8080/geoserver/soilgd/wms'; // 确保工作区和服务名正确
+    const params = new URLSearchParams({
+      SERVICE: 'WMS',
+      VERSION: '1.1.1', // 建议用 1.1.1(GeoServer 更兼容)
+      REQUEST: 'GetFeatureInfo',
+      LAYERS: 'soilgd:shapeMap',
+      QUERY_LAYERS: 'soilgd:shapeMap',
+      FORMAT: 'image/png',
+      TRANSPARENT: 'true',
+      INFO_FORMAT: 'application/json', // 强制返回 JSON
+      bbox: this.townshipMapInstance.getBounds().toBBoxString(),
+      X: x,
+      Y: y,
+      WIDTH: mapSize.x,
+      HEIGHT: mapSize.y,
+      SRS: 'EPSG:4326', // 与地图 CRS 一致
+      FEATURE_COUNT: 1 // 限制返回 1 个要素(关键:确保日志中 FeatureCount=1)
+    });
+
+    // 打印完整请求 URL(用于调试)
+    const requestUrl = `${wmsBaseUrl}?${params.toString()}`;
+    console.log('GetFeatureInfo 完整请求 URL:', requestUrl);
+
+    // 3. 发送请求并解析 JSON
+    const response = await fetch(requestUrl);
+    if (!response.ok) throw new Error(`请求失败:${response.status} ${response.statusText}`);
+
+    // 4. 验证响应类型(必须为 JSON)
+    const contentType = response.headers.get('Content-Type');
+    if (!contentType.includes('application/json')) {
+      throw new Error(`非 JSON 响应:${contentType},请检查 GeoServer 配置`);
+    }
+    const featureData = await response.json();
+
+    if (!featureData?.features || !Array.isArray(featureData.features) || featureData.features.length === 0) {
+      this.$message.warning('该区域无要素数据');
+      return; // 无要素时直接返回,不继续处理
+    }
+
+    const properties = featureData.features[0].properties || {};
+      this.currentFeatureInfo = {
+        avgmean: properties._avgmean,       // 平均镉含量
+        lncd: properties.Ln_Cd,             // 输入镉通量
+        outcd: properties.Out_Cd,           // 输出镉通量
+        netcd: properties.Net_Cd,           // 净镉通量
+        endcd: properties.End_Cd            // 最终镉浓度
+      };
+      
+      // 打印验证(可选)
+      console.log('当前点击要素信息:', this.currentFeatureInfo);
+    console.log('WMS 要素点击信息(JSON):', featureData);
+  } catch (error) {
+    console.error('WMS 要素点击交互失败:', error);
+    this.$message.warning('获取要素信息失败:' + error.message);
+  }
+},
+
   // 新增:显示tooltip的方法
     showTooltip(layer, townName, latlng) {
       const riceData = this.dataMap[townName]; // 水稻Cd数据
@@ -1085,7 +1177,7 @@ renderTownshipMap() {
 .township-map-container {
   width: 100% !important;
   max-width: 1000px;
-  height: 800px !important;
+  height: 500px !important;
   border-radius: 4px;
   background-color: #f5f5f5;
   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
@@ -1299,4 +1391,61 @@ renderTownshipMap() {
     height: 500px !important;
   }
 }
+
+/* 地图容器包裹层:确保内部元素垂直排列 */
+.township-map-wrapper {
+  position: relative;
+  width: 90%;
+  max-width: 1000px;
+  margin: 15px auto;
+  border: 1px solid #e0e0e0;
+  border-radius: 8px;
+  background: white;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  overflow: hidden;
+  display: flex; /* 新增:包裹层使用 Flex 布局 */
+  flex-direction: column; /* 子元素垂直排列 */
+}
+
+/* 要素信息面板:水平平铺 */
+.feature-info-panel {
+  background-color: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 8px;
+  padding: 15px;
+  margin-top: 15px; /* 与地图容器间距 */
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  width: 100%; /* 占满包裹层宽度 */
+}
+
+/* 信息面板标题:占满宽度 */
+.feature-info-panel h4 {
+  width: 100%;
+  margin-bottom: 10px; /* 标题与内容间距 */
+}
+
+/* 信息列表:水平排列 */
+.feature-info-panel ul {
+  display: flex;
+  flex-wrap: wrap; /* 允许换行 */
+  gap: 15px; /* 项之间的间距 */
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+/* 信息项:水平平铺 */
+.feature-info-panel li {
+  flex: 1; /* 每项占据等宽空间 */
+  min-width: 150px; /* 最小宽度,防止过窄 */
+  margin-bottom: 0; /* 移除垂直间距 */
+  font-size: 14px;
+  color: #333;
+}
+
+/* 强调文字样式 */
+.feature-info-panel li strong {
+  color: #0066CC;
+  margin-right: 5px;
+}
 </style>