dumingliang 13 часов назад
Родитель
Сommit
3ec252e3b6

+ 56 - 0
gw-admin/src/main/java/com/goldenwater/web/controller/xajgl/StXajBController.java

@@ -114,6 +114,62 @@ public class StXajBController extends BaseController {
         return AjaxResult.success(list);
     }
 
+    /**
+     * 查询降雨统计数据
+     */
+    @GetMapping("/rainfallStat")
+    @Operation(summary = "查询降雨统计数据", description = "查询新安江流域当年累计降雨量和多年平均降雨量")
+    public AjaxResult rainfallStat(
+            @Parameter(description = "年份") @RequestParam(value = "year", required = false) String year,
+            @Parameter(description = "当前日期(MM-dd格式)") @RequestParam(value = "tm", required = false) String tm) {
+        // 如果未传入参数,使用当前日期
+        if (year == null || year.isEmpty()) {
+            year = String.valueOf(java.time.LocalDate.now().getYear());
+        }
+        if (tm == null || tm.isEmpty()) {
+            java.time.LocalDate now = java.time.LocalDate.now();
+            tm = String.format("%02d-%02d", now.getMonthValue(), now.getDayOfMonth());
+        }
+        return AjaxResult.success(stXajBService.selectRainfallStat(year, tm));
+    }
+
+    /**
+     * 查询断面下泄量统计数据
+     */
+    @GetMapping("/dischargeStat")
+    @Operation(summary = "查询断面下泄量统计数据", description = "查询断面实际下泄量、多年平均和年度计划")
+    public AjaxResult dischargeStat(
+            @Parameter(description = "测站编码") @RequestParam(value = "stcd") String stcd,
+            @Parameter(description = "年份") @RequestParam(value = "year", required = false) String year) {
+        // 如果未传入年份,使用当前年份
+        if (year == null || year.isEmpty()) {
+            year = String.valueOf(java.time.LocalDate.now().getYear());
+        }
+        return AjaxResult.success(stXajBService.selectDischargeStat(stcd, year));
+    }
+
+    /**
+     * 查询取水户区县统计数据
+     */
+    @GetMapping("/wiuCountyStat")
+    @Operation(summary = "查询取水户区县统计", description = "按区县和类型统计取水户个数和当年取水量")
+    public AjaxResult wiuCountyStat(
+            @Parameter(description = "年份") @RequestParam(value = "year", required = false) String year) {
+        if (year == null || year.isEmpty()) {
+            year = String.valueOf(java.time.LocalDate.now().getYear());
+        }
+        return AjaxResult.success(stXajBService.selectWiuCountyStat(year));
+    }
+
+    /**
+     * 查询取水户列表(含经纬度)
+     */
+    @GetMapping("/wiuList")
+    @Operation(summary = "查询取水户列表", description = "查询所有取水户基础信息,用于地图展示")
+    public AjaxResult wiuList() {
+        return AjaxResult.success(stXajBService.selectWiuList());
+    }
+
     /**
      * 新增新安江站点
      */

+ 32 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/domain/DischargeStat.java

@@ -0,0 +1,32 @@
+package com.goldenwater.xajgl.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 断面下泄量统计数据对象
+ *
+ * @author xajgl
+ */
+@Data
+public class DischargeStat implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 测站编码 */
+    private String stcd;
+
+    /** 年份 */
+    private String yr;
+
+    /** 实际下泄量(亿m³) */
+    private BigDecimal ww;
+
+    /** 多年平均下泄量(亿m³) */
+    private BigDecimal dnww;
+
+    /** 年度计划下泄量(亿m³) */
+    private BigDecimal wwSchema;
+}

+ 26 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/domain/RainfallStat.java

@@ -0,0 +1,26 @@
+package com.goldenwater.xajgl.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 降雨统计数据对象
+ *
+ * @author xajgl
+ */
+@Data
+public class RainfallStat implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 河流/流域名称 */
+    private String rvnm;
+
+    /** 平均降雨量(累计/站点数) */
+    private BigDecimal drp;
+
+    /** 多年平均降雨量 */
+    private BigDecimal dnpj;
+}

+ 29 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/domain/WiuCountyStat.java

@@ -0,0 +1,29 @@
+package com.goldenwater.xajgl.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 取水户区县统计数据对象
+ *
+ * @author xajgl
+ */
+@Data
+public class WiuCountyStat implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 区县名称 */
+    private String county;
+
+    /** 取水户类型(1:工业,2:服务业,3:公共供水企业) */
+    private String tradTp;
+
+    /** 取水户个数 */
+    private Integer cnt;
+
+    /** 当年取水量(万m³) */
+    private BigDecimal yearWw;
+}

+ 33 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/mapper/StXajBMapper.java

@@ -1,10 +1,14 @@
 package com.goldenwater.xajgl.mapper;
 
+import com.goldenwater.xajgl.domain.DischargeStat;
+import com.goldenwater.xajgl.domain.RainfallStat;
 import com.goldenwater.xajgl.domain.StXajB;
+import com.goldenwater.xajgl.domain.WiuCountyStat;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 站点基础信息Mapper接口
@@ -23,4 +27,33 @@ public interface StXajBMapper {
     int updateStXajB(StXajB stXajB);
 
     int deleteStXajBByStcd(@Param("stcd") String stcd);
+
+    /**
+     * 查询降雨统计数据
+     * @param year 年份
+     * @param tm 当前日期(MM-dd格式)
+     * @return 降雨统计数据
+     */
+    RainfallStat selectRainfallStat(@Param("year") String year, @Param("tm") String tm);
+
+    /**
+     * 查询断面下泄量统计数据
+     * @param stcd 测站编码
+     * @param year 年份
+     * @return 断面下泄量统计数据
+     */
+    DischargeStat selectDischargeStat(@Param("stcd") String stcd, @Param("year") String year);
+
+    /**
+     * 查询取水户区县统计数据(按区县和类型分组)
+     * @param year 年份
+     * @return 区县统计数据列表
+     */
+    List<WiuCountyStat> selectWiuCountyStat(@Param("year") String year);
+
+    /**
+     * 查询取水户列表(含经纬度,用于地图展示)
+     * @return 取水户列表
+     */
+    List<Map<String, Object>> selectWiuList();
 }

+ 33 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/service/IStXajBService.java

@@ -1,8 +1,12 @@
 package com.goldenwater.xajgl.service;
 
+import com.goldenwater.xajgl.domain.DischargeStat;
+import com.goldenwater.xajgl.domain.RainfallStat;
 import com.goldenwater.xajgl.domain.StXajB;
+import com.goldenwater.xajgl.domain.WiuCountyStat;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 站点基础信息Service接口
@@ -22,4 +26,33 @@ public interface IStXajBService {
     int deleteStXajBByStcd(String stcd);
 
     void importStation(List<StXajB> stationList);
+
+    /**
+     * 查询降雨统计数据
+     * @param year 年份
+     * @param tm 当前日期(MM-dd格式)
+     * @return 降雨统计数据
+     */
+    RainfallStat selectRainfallStat(String year, String tm);
+
+    /**
+     * 查询断面下泄量统计数据
+     * @param stcd 测站编码
+     * @param year 年份
+     * @return 断面下泄量统计数据
+     */
+    DischargeStat selectDischargeStat(String stcd, String year);
+
+    /**
+     * 查询取水户区县统计数据
+     * @param year 年份
+     * @return 区县统计数据列表
+     */
+    List<WiuCountyStat> selectWiuCountyStat(String year);
+
+    /**
+     * 查询取水户列表
+     * @return 取水户列表
+     */
+    List<Map<String, Object>> selectWiuList();
 }

+ 24 - 0
gw-gx/src/main/java/com/goldenwater/xajgl/service/impl/StXajBServiceImpl.java

@@ -1,6 +1,9 @@
 package com.goldenwater.xajgl.service.impl;
 
+import com.goldenwater.xajgl.domain.DischargeStat;
+import com.goldenwater.xajgl.domain.RainfallStat;
 import com.goldenwater.xajgl.domain.StXajB;
+import com.goldenwater.xajgl.domain.WiuCountyStat;
 import com.goldenwater.xajgl.mapper.StXajBMapper;
 import com.goldenwater.xajgl.service.IStXajBService;
 import org.springframework.stereotype.Service;
@@ -8,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import jakarta.annotation.Resource;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 站点基础信息Service实现
@@ -57,4 +61,24 @@ public class StXajBServiceImpl implements IStXajBService {
             }
         }
     }
+
+    @Override
+    public RainfallStat selectRainfallStat(String year, String tm) {
+        return stXajBMapper.selectRainfallStat(year, tm);
+    }
+
+    @Override
+    public DischargeStat selectDischargeStat(String stcd, String year) {
+        return stXajBMapper.selectDischargeStat(stcd, year);
+    }
+
+    @Override
+    public List<WiuCountyStat> selectWiuCountyStat(String year) {
+        return stXajBMapper.selectWiuCountyStat(year);
+    }
+
+    @Override
+    public List<Map<String, Object>> selectWiuList() {
+        return stXajBMapper.selectWiuList();
+    }
 }

+ 74 - 0
gw-gx/src/main/resources/mapper/xajgl/StXajBMapper.xml

@@ -169,4 +169,78 @@
         delete from ST_XAJ_B where STCD = #{stcd}
     </delete>
 
+    <!-- 查询降雨统计数据 -->
+    <select id="selectRainfallStat" resultType="com.goldenwater.xajgl.domain.RainfallStat">
+        SELECT A.RVNM,
+               ROUND(A.drp / b.CNT, 2) DRP,
+               (C.DRP)                 DNPJ
+        FROM (SELECT '新安江流域' RVNM,
+                     SUM(DRP)     DRP
+              FROM ST_XAJ_B A
+                       LEFT JOIN ST_XAJ_DATA B ON A.STCD = B.STCD
+              WHERE TO_CHAR(B.TM, 'YYYY') = #{year}
+                AND A.TP = 'DRP') A
+                 LEFT JOIN (SELECT '新安江流域' RVNM,
+                                   COUNT(RVNM)  CNT
+                            FROM ST_XAJ_B
+                            WHERE TP = 'DRP') B ON A.RVNM = B.RVNM
+                 LEFT JOIN (SELECT STNM     RVNM,
+                                   SUM(DRP) DRP
+                            FROM ST_XAJ_PDMM
+                            WHERE DRP IS NOT NULL
+                              AND REPLACE(LPAD(MONTH, 2, '0'), ' ', '0') || '-' || REPLACE(LPAD(DAY, 2, '0'), ' ', '0') &lt;= #{tm}
+                            GROUP BY STNM) C ON C.RVNM = B.RVNM
+    </select>
+
+    <!-- 查询断面下泄量统计数据 -->
+    <select id="selectDischargeStat" resultType="com.goldenwater.xajgl.domain.DischargeStat">
+        SELECT A.STCD,
+               TO_CHAR(A.TM, 'yyyy')   YR,
+               SUM(A.Q * 8.64) / 10000 WW,
+               SUM(B.WW)               DNWW,
+               SUM(C.WW)               WW_SCHEMA
+        FROM ST_XAJ_DATA A
+                 LEFT JOIN ST_XAJ_PDMM B ON A.STCD = B.STCD
+            AND TO_CHAR(A.TM, 'mm-dd') =
+                REPLACE(LPAD(B.MONTH, 2, '0'), ' ', '0') || '-' || REPLACE(LPAD(B.DAY, 2, '0'), ' ', '0')
+                 LEFT JOIN ST_XAJ_SCHEMA C ON A.STCD = C.STCD
+            AND TO_CHAR(A.TM, 'mm-dd') = TO_CHAR(C.TM, 'mm-dd')
+        WHERE A.STCD = #{stcd}
+          AND TO_CHAR(A.TM, 'yyyy') = #{year}
+        GROUP BY A.STCD, TO_CHAR(A.TM, 'yyyy')
+        ORDER BY TO_CHAR(A.TM, 'yyyy') DESC
+    </select>
+
+    <!-- 查询取水户区县统计数据 -->
+    <select id="selectWiuCountyStat" resultType="com.goldenwater.xajgl.domain.WiuCountyStat">
+        SELECT B.COUNTY,
+               B.TRAD_TP,
+               COUNT(*) CNT,
+               COALESCE(SUM(D.YEAR_WW), 0) YEAR_WW
+        FROM ST_XAJ_B B
+                 LEFT JOIN (SELECT STCD, SUM(WW) YEAR_WW
+                            FROM ST_XAJ_DATA
+                            WHERE TO_CHAR(TM, 'yyyy') = #{year}
+                            GROUP BY STCD) D ON B.STCD = D.STCD
+        WHERE B.TP = 'WIU'
+          AND B.TRAD_TP IS NOT NULL
+        GROUP BY B.COUNTY, B.TRAD_TP
+        ORDER BY B.COUNTY, B.TRAD_TP
+    </select>
+
+    <!-- 查询取水户列表(含经纬度) -->
+    <select id="selectWiuList" resultType="java.util.HashMap">
+        SELECT STCD,
+               STNM,
+               CAST(NULLIF(TRIM(LGTD), '') AS DECIMAL(15,6)) as LGTD,
+               CAST(NULLIF(TRIM(LTTD), '') AS DECIMAL(15,6)) as LTTD,
+               COUNTY,
+               USCC,
+               TRAD_TP
+        FROM ST_XAJ_B
+        WHERE TP = 'WIU'
+          AND LGTD IS NOT NULL
+          AND LTTD IS NOT NULL
+    </select>
+
 </mapper>

+ 35 - 0
gw-ui/src/api/xajgl/station.js

@@ -72,6 +72,41 @@ export function getLatestDataByBiz(bizCode) {
   })
 }
 
+// 查询降雨统计数据
+export function getRainfallStat(year, tm) {
+  return request({
+    url: '/xajgl/station/rainfallStat',
+    method: 'get',
+    params: { year, tm }
+  })
+}
+
+// 查询断面下泄量统计数据
+export function getDischargeStat(stcd, year) {
+  return request({
+    url: '/xajgl/station/dischargeStat',
+    method: 'get',
+    params: { stcd, year }
+  })
+}
+
+// 查询取水户区县统计数据
+export function getWiuCountyStat(year) {
+  return request({
+    url: '/xajgl/station/wiuCountyStat',
+    method: 'get',
+    params: { year }
+  })
+}
+
+// 查询取水户列表(含经纬度)
+export function getWiuList() {
+  return request({
+    url: '/xajgl/station/wiuList',
+    method: 'get'
+  })
+}
+
 // 新增站点
 export function addStation(data) {
   return request({

+ 2 - 0
gw-ui/src/assets/mapJSON/xaj_mapdata.js

@@ -162747,3 +162747,5 @@ var xajCountyJson2 = {
         }
     ]
 }
+
+export { xajCountyJson, xajCountyJson2 }

+ 1 - 0
gw-ui/src/views/front/Xaj.vue

@@ -494,6 +494,7 @@ function initDefaultChart() {
   display: flex;
   flex-direction: column;
   overflow: hidden;
+  position: relative;
 }
 
 /* 弹框内部样式 */

+ 3 - 0
gw-ui/src/views/front/xaj/FeedbackModule.vue

@@ -53,6 +53,9 @@ function resetFeedback() {
   flex: 1;
   padding: 16px;
   overflow: auto;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
 }
 
 .feedback-container {

+ 665 - 85
gw-ui/src/views/front/xaj/GisModule.vue

@@ -10,22 +10,24 @@
             <div class="stat-item">
               <div class="stat-label">新安江流域平均降雨量</div>
               <div class="stat-value-row">
-                <span class="stat-value">累计降雨 <b>1393.4mm</b></span>
-                <span class="stat-compare less">较多年平均 -3.20%</span>
+                <span class="stat-value">累计降雨 <b>{{ rainfallStat.drp }}mm</b></span>
+                <span class="stat-compare" :class="rainfallStat.drp > rainfallStat.dnpj ? 'more' : 'less'">
+                  较多年平均 {{ rainfallStat.dnpj > 0 ? ((rainfallStat.drp - rainfallStat.dnpj) / rainfallStat.dnpj * 100).toFixed(2) : 0 }}%
+                </span>
               </div>
             </div>
             <div class="stat-item">
               <div class="stat-label">新安江水库罗桐埠断面</div>
               <div class="stat-value-row">
-                <span class="stat-value">实际下泄量 <b>56.85亿m³</b></span>
-                <span class="stat-compare">年度计划 <b>77.90亿m³</b></span>
+                <span class="stat-value">实际下泄量 <b>{{ luotongbuStat.ww.toFixed(2) }}亿m³</b></span>
+                <span class="stat-compare">年度计划 <b>{{ luotongbuStat.wwSchema.toFixed(2) }}亿m³</b></span>
               </div>
             </div>
             <div class="stat-item">
               <div class="stat-label">浙皖省界接口断面</div>
               <div class="stat-value-row">
-                <span class="stat-value">实际下泄量 <b>55.99亿m³</b></span>
-                <span class="stat-compare more">年度计划 <b>42.00亿m³</b></span>
+                <span class="stat-value">实际下泄量 <b>{{ jiekouStat.ww.toFixed(2) }}亿m³</b></span>
+                <span class="stat-compare" :class="jiekouStat.ww > jiekouStat.wwSchema ? 'more' : 'less'">年度计划 <b>{{ jiekouStat.wwSchema.toFixed(2) }}亿m³</b></span>
               </div>
             </div>
           </div>
@@ -79,10 +81,78 @@
       </el-tab-pane>
 
       <el-tab-pane label="开发利用情况" name="utilization">
-        <div class="utilization-placeholder">
-          <el-icon :size="48" color="#c0c4cc"><DataLine /></el-icon>
-          <p>开发利用情况数据展示区域</p>
-          <el-empty description="暂无开发利用数据" />
+        <div class="utilization-wrapper">
+          <div class="utilization-map-container" id="utilization-map"></div>
+          
+          <!-- 开发利用统计面板 -->
+          <div class="stats-panel utilization-stats">
+            <div class="panel-title">开发利用统计情况</div>
+            <div class="stat-item">
+              <div class="stat-label">工业自备水源</div>
+              <div class="stat-value-row">
+                <span class="stat-value">个数 <b>{{ wiuSummary.industrial.cnt }}</b></span>
+                <span class="stat-compare">当年取水量 <b>{{ wiuSummary.industrial.ww.toFixed(2) }}万m³</b></span>
+              </div>
+            </div>
+            <div class="stat-item">
+              <div class="stat-label">公共供水企业</div>
+              <div class="stat-value-row">
+                <span class="stat-value">个数 <b>{{ wiuSummary.publicSupply.cnt }}</b></span>
+                <span class="stat-compare">当年取水量 <b>{{ wiuSummary.publicSupply.ww.toFixed(2) }}万m³</b></span>
+              </div>
+            </div>
+            <div class="stat-item">
+              <div class="stat-label">服务业自备水源</div>
+              <div class="stat-value-row">
+                <span class="stat-value">个数 <b>{{ wiuSummary.service.cnt }}</b></span>
+                <span class="stat-compare">当年取水量 <b>{{ wiuSummary.service.ww.toFixed(2) }}万m³</b></span>
+              </div>
+            </div>
+            <div class="stat-item" style="border-bottom: none;">
+              <div class="stat-label">合计</div>
+              <div class="stat-value-row">
+                <span class="stat-value">个数 <b>{{ wiuSummary.total.cnt }}</b></span>
+                <span class="stat-compare">当年取水量 <b>{{ wiuSummary.total.ww.toFixed(2) }}万m³</b></span>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 取水户图例 -->
+          <div class="legend-panel legend-left utilization-legend">
+            <div class="legend-title">取水户类型</div>
+            <div class="legend-item">
+              <span class="legend-dot" style="background: #e6a23c;"></span>
+              <span class="legend-text">工业自备水源</span>
+            </div>
+            <div class="legend-item">
+              <span class="legend-dot" style="background: #67c23a;"></span>
+              <span class="legend-text">公共供水企业</span>
+            </div>
+            <div class="legend-item">
+              <span class="legend-dot" style="background: #f56c6c;"></span>
+              <span class="legend-text">服务业自备水源</span>
+            </div>
+          </div>
+          
+          <!-- 悬浮提示 -->
+          <div v-if="wiuTooltipData.visible" class="map-tooltip wiu-tooltip" :style="wiuTooltipStyle">
+            <!-- 区县悬浮 -->
+            <template v-if="wiuTooltipData.type === 'county'">
+              <div class="tooltip-title">{{ wiuTooltipData.name }}</div>
+              <div class="tooltip-row">工业自备水源:<b>{{ wiuTooltipData.industrial.cnt }}</b>个,取水量 <b>{{ wiuTooltipData.industrial.ww.toFixed(2) }}</b>万m³</div>
+              <div class="tooltip-row">公共供水企业:<b>{{ wiuTooltipData.publicSupply.cnt }}</b>个,取水量 <b>{{ wiuTooltipData.publicSupply.ww.toFixed(2) }}</b>万m³</div>
+              <div class="tooltip-row">服务业自备水源:<b>{{ wiuTooltipData.service.cnt }}</b>个,取水量 <b>{{ wiuTooltipData.service.ww.toFixed(2) }}</b>万m³</div>
+              <div class="tooltip-divider"></div>
+              <div class="tooltip-row">合计:<b>{{ wiuTooltipData.total.cnt }}</b>个,取水量 <b>{{ wiuTooltipData.total.ww.toFixed(2) }}</b>万m³</div>
+            </template>
+            <!-- 取水户悬浮 -->
+            <template v-if="wiuTooltipData.type === 'wiu'">
+              <div class="tooltip-title">{{ wiuTooltipData.name }}</div>
+              <div class="tooltip-row">社会信用代码:{{ wiuTooltipData.uscc }}</div>
+              <div class="tooltip-row">取水户类型:{{ wiuTooltipData.tradTp }}</div>
+              <div class="tooltip-row">区县:{{ wiuTooltipData.county }}</div>
+            </template>
+          </div>
         </div>
       </el-tab-pane>
     </el-tabs>
@@ -150,7 +220,8 @@ import * as echarts from 'echarts'
 import { DataLine, Search, DataAnalysis } from '@element-plus/icons-vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { xajfqGeoJson } from '@/assets/mapJSON/xajfq_geojson'
-import { listMapStations, getLatestData, listData } from '@/api/xajgl/station'
+import { xajCountyJson } from '@/assets/mapJSON/xaj_mapdata'
+import { listMapStations, getLatestData, getLatestDataByBiz, listData, getRainfallStat, getDischargeStat, getWiuCountyStat, getWiuList } from '@/api/xajgl/station'
 
 const props = defineProps({
   active: { type: Boolean, default: false }
@@ -161,6 +232,25 @@ const emit = defineEmits(['open-station-dialog'])
 const activeTab = ref('situation')
 const mapContainer = ref(null)
 
+// 降雨统计数据
+const rainfallStat = ref({
+  drp: 0,
+  dnpj: 0
+})
+
+// 断面下泄量统计数据
+const luotongbuStat = ref({
+  ww: 0,
+  dnww: 0,
+  wwSchema: 0
+})
+
+const jiekouStat = ref({
+  ww: 0,
+  dnww: 0,
+  wwSchema: 0
+})
+
 // 历史数据弹框相关
 const historyDialogVisible = ref(false)
 const historyDialogTitle = ref('')
@@ -171,25 +261,50 @@ const currentStation = ref(null)
 const historyChartRef = ref(null)
 let historyChart = null
 
-// 站点类型对应的业务域配置
-const STATION_BIZ_CONFIG = {
-  DRP: { bizCode: 'AH_SL_YL', columns: ['stnm', 'tm', 'drp', 'prov', 'city', 'county'], historyChart: ['drp'] },
-  ZZ: { bizCode: 'AH_SL_JL', columns: ['stnm', 'tm', 'z', 'q', 'prov', 'city', 'county'], historyChart: ['z', 'q'] },
-  DYP: { bizCode: 'AH_SL_ZF', columns: ['stnm', 'tm', 'dyp', 'prov', 'city', 'county'], historyChart: ['dyp'] },
-  SK: { bizCode: 'FD_XAJ', columns: ['stnm', 'tm', 'z', 'dwz', 'inq', 'outq'], historyChart: ['z', 'inq', 'outq'] }
+// bizCode对应的列显示配置
+const BIZ_CODE_COLUMNS = {
+  'AH_SL_YL': ['stnm', 'tm', 'drp'],                              // 安徽省雨量
+  'ZJ_SL_YL': ['stnm', 'tm', 'drp'],                              // 浙江省雨量
+  'AH_SL_JL': ['stnm', 'tm', 'z', 'q'],                           // 安徽省水文
+  'ZJ_SL_JL': ['stnm', 'tm', 'z', 'q'],                           // 浙江省水文
+  'TBA_SW_XAJ': ['stnm', 'tm', 'q'],                         // 太湖局水文
+  'AH_SL_ZF': ['stnm', 'tm', 'dyp'],                              // 安徽省蒸发
+  'DW_XAJ_ST': ['stnm', 'tm', 'z', 'inq', 'outq'],                          // 单位新安江站点
+  'FD_XAJ': ['stnm', 'tm', 'z', 'dwz', 'inq', 'outq'], // 水库
+  'HS_SK_XAJ': ['stnm', 'tm','ww'], // 黄山水库
+  'CA_SK_XAJ': ['stnm', 'tm', 'ww']  // 常山水库
+}
+
+// bizCode对应的图表字段配置
+const BIZ_CODE_CHART = {
+  'AH_SL_YL': ['drp'],
+  'ZJ_SL_YL': ['drp'],
+  'AH_SL_JL': ['z', 'q'],
+  'ZJ_SL_JL': ['z', 'q'],
+  'TBA_SW_XAJ': ['q'],
+  'AH_SL_ZF': ['dyp'],
+  'DW_XAJ_ST': ['z',  'inq', 'outq'],
+  'FD_XAJ': ['z', 'dwz', 'inq', 'outq'],
+  'HS_SK_XAJ': ['ww'],
+  'CA_SK_XAJ': ['ww']
 }
 
 // 历史数据列配置
 const historyColumns = [
-  { prop: 'stnm', label: '站点名称', width: 150, fixed: 'left' },
-  { prop: 'tm', label: '时间', width: 150, formatter: fmtDateTime },
-  { prop: 'z', label: '水位(m)', width: 100 },
+  { prop: 'stnm', label: '站点名称', width: 120, fixed: 'left' },
+  { prop: 'tm', label: '监测时间', width: 150, formatter: fmtDateTime },
+  { prop: 'z', label: '水位/坝上水位(m)', width: 140 },
   { prop: 'dwz', label: '坝下水位(m)', width: 110 },
-  { prop: 'q', label: '流量(m³/s)', width: 110 },
+  { prop: 'q', label: '流量(m³/s)', width: 100 },
   { prop: 'inq', label: '入库流量(m³/s)', width: 120 },
   { prop: 'outq', label: '出库流量(m³/s)', width: 120 },
-  { prop: 'drp', label: '降雨量(mm)', width: 110 },
-  { prop: 'dyp', label: '蒸发量(mm)', width: 110 }
+  { prop: 'ww', label: '下泄水量(万m³)', width: 120 },
+  { prop: 'w', label: '蓄水量(万m³)', width: 110 },
+  { prop: 'drp', label: '降雨量(mm)', width: 100 },
+  { prop: 'dyp', label: '蒸发量(mm)', width: 100 },
+  { prop: 'prov', label: '省份', width: 80 },
+  { prop: 'city', label: '地市', width: 80 },
+  { prop: 'county', label: '区县', width: 80 }
 ]
 
 const stationColorMap = {
@@ -221,8 +336,29 @@ let baseLayer = null
 let labelLayer = null
 let resizeObserver = null
 let currentHoverStcd = null
+let countyLayer = null
+let wiuLayer = null
 const currentLayer = ref('vec')
 
+// 开发利用相关状态
+const wiuCountyStats = ref([])
+const wiuList = ref([])
+const wiuTooltipData = reactive({
+  visible: false,
+  type: '',  // 'county' 或 'wiu'
+  name: '',
+  // 区县悬浮信息
+  industrial: { cnt: 0, ww: 0 },
+  publicSupply: { cnt: 0, ww: 0 },
+  service: { cnt: 0, ww: 0 },
+  total: { cnt: 0, ww: 0 },
+  // 取水户悬浮信息
+  uscc: '',
+  tradTp: '',
+  county: ''
+})
+const wiuTooltipStyle = ref({})
+
 // 天地图图层配置
 const layerConfig = {
   vec: {
@@ -317,11 +453,24 @@ function switchLayer(type) {
 function loadAreaGeoJson() {
   const source = areaLayer.getSource()
   try {
+    // 处理GeoJSON数据,清理坐标中的多余维度(原数据有4个值,需要清理为2个值)
+    const geoJsonData = JSON.parse(JSON.stringify(xajfqGeoJson))
+    if (geoJsonData.features) {
+      geoJsonData.features.forEach(feature => {
+        if (feature.geometry && feature.geometry.coordinates) {
+          feature.geometry.coordinates = cleanCoordinates(feature.geometry.coordinates)
+        }
+      })
+    }
+    
     const format = new GeoJSON()
-    const features = format.readFeatures(xajfqGeoJson, {
-      dataProjection: 'EPSG:4490',
+    const features = format.readFeatures(geoJsonData, {
+      dataProjection: 'EPSG:4326',
       featureProjection: 'EPSG:3857'
     })
+    
+    console.log('加载子流域features数量:', features.length)
+    
     features.forEach(f => {
       const name = f.get('name') || ''
       f.setStyle(new Style({
@@ -342,6 +491,17 @@ function loadAreaGeoJson() {
   }
 }
 
+// 清理坐标数据,移除多余维度
+function cleanCoordinates(coords) {
+  if (!Array.isArray(coords)) return coords
+  // 如果是坐标点 [lng, lat, ...],只保留前两个值
+  if (typeof coords[0] === 'number') {
+    return [coords[0], coords[1]]
+  }
+  // 如果是数组的数组,递归处理
+  return coords.map(item => cleanCoordinates(item))
+}
+
 async function loadStations() {
   try {
     const res = await listMapStations()
@@ -349,6 +509,8 @@ async function loadStations() {
       const rows = (res.rows || []).filter(s =>
         ['DRP', 'SK', 'ZZ', 'DYP'].includes(s.tp) && s.lgtd && s.lttd
       )
+      // 批量获取所有站点的最新数据
+      await loadAllLatestData(rows)
       renderStations(rows)
     }
   } catch (e) {
@@ -356,6 +518,88 @@ async function loadStations() {
   }
 }
 
+// 批量加载所有站点的最新数据
+async function loadAllLatestData() {
+  try {
+    // 使用所有业务域编码获取最新数据(使用MAX方法)
+    const bizCodes = [
+      'AH_SL_JL',   // 安徽省水文
+      'AH_SL_ZF',   // 安徽省蒸发
+      'ZJ_SL_JL',   // 浙江省水文
+      'TBA_SW_XAJ', // 太湖局水文
+      'AH_SL_YL',   // 安徽省雨量
+      'ZJ_SL_YL',   // 浙江省雨量
+      'DW_XAJ_ST',  // 单位新安江站点
+      'FD_XAJ',     // 水库
+      'HS_SK_XAJ',  // 黄山水库
+      'CA_SK_XAJ'   // 常山水库
+    ]
+    const promises = bizCodes.map(bizCode => getLatestDataByBiz(bizCode))
+    const results = await Promise.all(promises)
+    
+    // 将结果存入缓存(同一站点可能有多个业务域的数据,保留最新的)
+    results.forEach(res => {
+      if (res.code === 200 && res.data) {
+        res.data.forEach(item => {
+          if (item.stcd) {
+            const existing = latestDataCache[item.stcd]
+            // 如果没有缓存或者新数据时间更新,则更新缓存
+            if (!existing || (item.tm && existing.tm && new Date(item.tm) > new Date(existing.tm))) {
+              latestDataCache[item.stcd] = item
+            }
+          }
+        })
+      }
+    })
+  } catch (e) {
+    console.error('加载最新数据失败', e)
+  }
+}
+
+// 加载降雨统计数据
+async function loadRainfallStat() {
+  try {
+    const res = await getRainfallStat()
+    if (res.code === 200 && res.data) {
+      rainfallStat.value = {
+        drp: res.data.drp || 0,
+        dnpj: res.data.dnpj || 0
+      }
+    }
+  } catch (e) {
+    console.error('加载降雨统计数据失败', e)
+  }
+}
+
+// 加载断面下泄量统计数据
+async function loadDischargeStats() {
+  try {
+    // 并行查询两个断面的数据
+    const [luotongbuRes, jiekouRes] = await Promise.all([
+      getDischargeStat('70112100'),  // 罗桐埠断面
+      getDischargeStat('70111400')   // 街口断面
+    ])
+    
+    if (luotongbuRes.code === 200 && luotongbuRes.data) {
+      luotongbuStat.value = {
+        ww: luotongbuRes.data.ww || 0,
+        dnww: luotongbuRes.data.dnww || 0,
+        wwSchema: luotongbuRes.data.wwSchema || 0
+      }
+    }
+    
+    if (jiekouRes.code === 200 && jiekouRes.data) {
+      jiekouStat.value = {
+        ww: jiekouRes.data.ww || 0,
+        dnww: jiekouRes.data.dnww || 0,
+        wwSchema: jiekouRes.data.wwSchema || 0
+      }
+    }
+  } catch (e) {
+    console.error('加载断面下泄量数据失败', e)
+  }
+}
+
 function renderStations(stations) {
   const source = stationLayer.getSource()
   stations.forEach(station => {
@@ -369,18 +613,6 @@ function renderStations(stations) {
   })
 }
 
-async function getLatestDataWithCache(stcd) {
-  if (latestDataCache[stcd]) return latestDataCache[stcd]
-  try {
-    const res = await getLatestData(stcd)
-    const data = res.data && res.data.length > 0 ? res.data[0] : null
-    latestDataCache[stcd] = data
-    return data
-  } catch (e) {
-    return null
-  }
-}
-
 function buildLatestValues(tp, data) {
   const values = []
   if (tp === 'DRP') {
@@ -427,10 +659,12 @@ function formatDate(date) {
 
 // 计算当前历史数据列配置
 const currentHistoryColumns = computed(() => {
-  if (!currentStation.value) return historyColumns
-  const config = STATION_BIZ_CONFIG[currentStation.value.tp]
-  if (!config) return historyColumns
-  return historyColumns.filter(col => config.columns.includes(col.prop))
+  if (!currentStation.value) return historyColumns.slice(0, 2) // 至少显示站名和时间
+  const bizCode = currentStation.value.bizCode
+  if (!bizCode) return historyColumns.slice(0, 2)
+  const columns = BIZ_CODE_COLUMNS[bizCode]
+  if (!columns) return historyColumns.slice(0, 2)
+  return historyColumns.filter(col => columns.includes(col.prop))
 })
 
 function handleMapClick(event) {
@@ -456,7 +690,14 @@ function openHistoryDialog(station) {
   historyDateRange.value = [formatDate(start), formatDate(end)]
   historyData.value = []
   historyDialogVisible.value = true
-  loadHistoryData()
+  // 销毁旧的echart实例
+  if (historyChart) {
+    historyChart.dispose()
+    historyChart = null
+  }
+  nextTick(() => {
+    loadHistoryData()
+  })
 }
 
 // 加载历史数据
@@ -464,9 +705,10 @@ function loadHistoryData() {
   if (!currentStation.value || !historyDateRange.value || historyDateRange.value.length !== 2) return
   historyLoading.value = true
   const [startTm, endTm] = historyDateRange.value
-  const config = STATION_BIZ_CONFIG[currentStation.value.tp]
-  const bizCode = config ? config.bizCode : null
-  listData(currentStation.value.stcd, startTm, endTm, bizCode).then(res => {
+  // 从站点基础信息中获取stcd和bizCode
+  const stcd = currentStation.value.stcd
+  const bizCode = currentStation.value.bizCode || null
+  listData(stcd, startTm, endTm, bizCode).then(res => {
     if (res.code === 200) {
       historyData.value = res.data || []
     } else {
@@ -480,9 +722,46 @@ function loadHistoryData() {
   })
 }
 
+// 字段类型分组:用于y轴分配
+const Y_AXIS_LEFT_FIELDS = ['z', 'dwz']  // 水位类,左y轴
+const Y_AXIS_RIGHT_FIELDS = ['q', 'inq', 'outq', 'ww', 'w', 'drp', 'dyp']  // 流量/水量/雨量类,右y轴
+
+// 水位类字段(使用折线图)
+const LINE_FIELDS = ['z', 'dwz']
+// 流量/水量类字段(使用柱状图)
+const BAR_FIELDS = ['q', 'inq', 'outq', 'ww', 'w', 'drp', 'dyp']
+
+// 获取字段的图表类型
+function getChartType(field) {
+  if (LINE_FIELDS.includes(field)) return 'line'
+  if (BAR_FIELDS.includes(field)) return 'bar'
+  return 'line'
+}
+
+// 获取字段的y轴索引
+function getYAxisIndex(field) {
+  if (Y_AXIS_LEFT_FIELDS.includes(field)) return 0
+  if (Y_AXIS_RIGHT_FIELDS.includes(field)) return 1
+  return 0
+}
+
+// 获取字段的单位
+function getFieldUnit(field) {
+  const units = {
+    'z': 'm', 'dwz': 'm',
+    'q': 'm³/s', 'inq': 'm³/s', 'outq': 'm³/s',
+    'ww': '万m³', 'w': '万m³',
+    'drp': 'mm', 'dyp': 'mm'
+  }
+  return units[field] || ''
+}
+
 // 初始化历史数据图表
 function initHistoryChart() {
-  if (!historyChartRef.value) return
+  if (!historyChartRef.value) {
+    console.warn('historyChartRef is not ready')
+    return
+  }
   if (!historyChart) {
     historyChart = echarts.init(historyChartRef.value)
   }
@@ -490,39 +769,94 @@ function initHistoryChart() {
     historyChart.clear()
     return
   }
-  const config = STATION_BIZ_CONFIG[currentStation.value.tp]
-  if (!config || !config.historyChart || config.historyChart.length === 0) {
+  if (!currentStation.value) {
+    historyChart.clear()
+    return
+  }
+  const bizCode = currentStation.value.bizCode
+  if (!bizCode) {
     historyChart.clear()
     return
   }
-  const chartFields = config.historyChart
+  const chartFields = BIZ_CODE_CHART[bizCode]
+  if (!chartFields || chartFields.length === 0) {
+    historyChart.clear()
+    return
+  }
+
+  // 判断是否需要双y轴
+  const hasLeftAxis = chartFields.some(f => Y_AXIS_LEFT_FIELDS.includes(f))
+  const hasRightAxis = chartFields.some(f => Y_AXIS_RIGHT_FIELDS.includes(f))
+  const useDualAxis = hasLeftAxis && hasRightAxis
+
   const sortedData = [...historyData.value].sort((a, b) => new Date(a.tm) - new Date(b.tm))
   const xData = sortedData.map(d => fmtDateTime(null, null, d.tm))
+
   const series = chartFields.map(field => {
     const col = historyColumns.find(c => c.prop === field)
-    return {
+    const chartType = getChartType(field)
+    const baseConfig = {
       name: col ? col.label : field,
-      type: 'line',
-      data: sortedData.map(d => d[field] ?? null),
-      smooth: true,
-      symbol: 'circle',
-      symbolSize: 4,
-      lineStyle: { width: 2 }
+      type: chartType,
+      yAxisIndex: useDualAxis ? getYAxisIndex(field) : 0,
+      data: sortedData.map(d => d[field] ?? null)
+    }
+    // 折线图额外配置
+    if (chartType === 'line') {
+      return {
+        ...baseConfig,
+        smooth: true,
+        symbol: 'circle',
+        symbolSize: 4,
+        lineStyle: { width: 2 }
+      }
+    }
+    // 柱状图额外配置
+    return {
+      ...baseConfig,
+      barMaxWidth: 30
     }
   })
+
+  // 获取左右y轴的单位
+  const leftFields = chartFields.filter(f => Y_AXIS_LEFT_FIELDS.includes(f))
+  const rightFields = chartFields.filter(f => Y_AXIS_RIGHT_FIELDS.includes(f))
+  const leftUnit = leftFields.length > 0 ? getFieldUnit(leftFields[0]) : ''
+  const rightUnit = rightFields.length > 0 ? getFieldUnit(rightFields[0]) : ''
+
+  const yAxis = useDualAxis ? [
+    {
+      type: 'value',
+      position: 'left',
+      name: leftUnit,
+      axisLabel: { formatter: '{value}' }
+    },
+    {
+      type: 'value',
+      position: 'right',
+      name: rightUnit,
+      axisLabel: { formatter: '{value}' }
+    }
+  ] : {
+    type: 'value',
+    name: getFieldUnit(chartFields[0]) || ''
+  }
+
   const option = {
     tooltip: { trigger: 'axis' },
     legend: { data: series.map(s => s.name), bottom: 0 },
-    grid: { left: '10%', right: '5%', top: '10%', bottom: '15%' },
+    grid: { left: '10%', right: '10%', top: '10%', bottom: '15%' },
     xAxis: {
       type: 'category',
       data: xData,
       axisLabel: { rotate: 30, fontSize: 11 }
     },
-    yAxis: { type: 'value' },
+    yAxis,
     series
   }
   historyChart.setOption(option, true)
+  // 调整图表大小
+  historyChart.resize()
 }
 
 function handlePointerMove(event) {
@@ -545,11 +879,17 @@ function handlePointerMove(event) {
         tooltipData.stnm = station.stnm
         tooltipData.stcd = station.stcd
         tooltipData.unit = station.unit || '-'
-        tooltipData.tm = ''
-        tooltipData.values = []
-        tooltipData.loading = true
+        // 直接从缓存获取数据,不需要查询数据库
+        const data = latestDataCache[station.stcd]
+        if (data) {
+          tooltipData.tm = fmtDate(data.tm)
+          tooltipData.values = buildLatestValues(station.tp, data)
+        } else {
+          tooltipData.tm = '暂无数据'
+          tooltipData.values = []
+        }
+        tooltipData.loading = false
         tooltipData.visible = true
-        loadTooltipData(station)
       } else {
         tooltipData.visible = true
       }
@@ -562,19 +902,6 @@ function handlePointerMove(event) {
   }
 }
 
-async function loadTooltipData(station) {
-  const data = await getLatestDataWithCache(station.stcd)
-  if (currentHoverStcd !== station.stcd) return
-  if (data) {
-    tooltipData.tm = fmtDate(data.tm)
-    tooltipData.values = buildLatestValues(station.tp, data)
-  } else {
-    tooltipData.tm = '暂无数据'
-    tooltipData.values = []
-  }
-  tooltipData.loading = false
-}
-
 onMounted(() => {
   nextTick(() => {
     if (mapContainer.value) initMap()
@@ -587,6 +914,10 @@ onMounted(() => {
       resizeObserver.observe(mapContainer.value)
     }
   })
+  // 加载降雨统计数据
+  loadRainfallStat()
+  // 加载断面下泄量统计数据
+  loadDischargeStats()
 })
 
 onUnmounted(() => {
@@ -609,7 +940,243 @@ watch(() => props.active, (val) => {
 watch(activeTab, (val) => {
   if (val === 'situation') {
     nextTick(() => { if (olMap) olMap.updateSize() })
+  } else if (val === 'utilization') {
+    initUtilizationMap()
+  }
+})
+
+// ============ 开发利用情况相关函数 ============
+
+// 初始化开发利用地图
+function initUtilizationMap() {
+  nextTick(async () => {
+    const container = document.getElementById('utilization-map')
+    if (!container) return
+    // 如果已经初始化过,更新尺寸
+    if (container._olMap) {
+      container._olMap.updateSize()
+      return
+    }
+    // 创建新的地图实例
+    const utilBaseLayer = new TileLayer({ source: new XYZ({ url: layerConfig.vec.base }) })
+    const utilLabelLayer = new TileLayer({ source: new XYZ({ url: layerConfig.vec.label }) })
+    
+    const utilMap = new OlMap({
+      target: container,
+      view: new View({
+        center: fromLonLat([119.05, 29.5]),
+        zoom: 9,
+        minZoom: 8,
+        maxZoom: 18
+      }),
+      layers: [utilBaseLayer, utilLabelLayer]
+    })
+    container._olMap = utilMap
+    
+    // 加载区县图层
+    countyLayer = new VectorLayer({ source: new VectorSource() })
+    wiuLayer = new VectorLayer({ source: new VectorSource() })
+    utilMap.addLayer(countyLayer)
+    utilMap.addLayer(wiuLayer)
+    
+    // 加载数据
+    await loadWiuData()
+    renderCountyLayer()
+    renderWiuLayer()
+    
+    // 监听鼠标移动
+    utilMap.on('pointermove', handleWiuPointerMove)
+  })
+}
+
+// 加载取水户数据
+async function loadWiuData() {
+  try {
+    const [statRes, listRes] = await Promise.all([
+      getWiuCountyStat(),
+      getWiuList()
+    ])
+    if (statRes.code === 200) wiuCountyStats.value = statRes.data || []
+    if (listRes.code === 200) wiuList.value = listRes.data || []
+  } catch (e) {
+    console.error('加载取水户数据失败', e)
+  }
+}
+
+// 渲染区县图层
+function renderCountyLayer() {
+  if (!countyLayer) return
+  const source = countyLayer.getSource()
+  source.clear()
+  try {
+    const geoJsonData = JSON.parse(JSON.stringify(xajCountyJson))
+    // 清理坐标
+    if (geoJsonData.features) {
+      geoJsonData.features.forEach(feature => {
+        if (feature.geometry && feature.geometry.coordinates) {
+          feature.geometry.coordinates = cleanCoordinates(feature.geometry.coordinates)
+        }
+      })
+    }
+    const format = new GeoJSON()
+    const features = format.readFeatures(geoJsonData, {
+      dataProjection: 'EPSG:4326',
+      featureProjection: 'EPSG:3857'
+    })
+    
+    // 按区县统计数据
+    const statsMap = {}
+    wiuCountyStats.value.forEach(s => {
+      if (!statsMap[s.county]) {
+        statsMap[s.county] = { industrial: { cnt: 0, ww: 0 }, publicSupply: { cnt: 0, ww: 0 }, service: { cnt: 0, ww: 0 }, total: { cnt: 0, ww: 0 } }
+      }
+      const item = { cnt: s.cnt || 0, ww: Number(s.yearWw) || 0 }
+      statsMap[s.county].total.cnt += item.cnt
+      statsMap[s.county].total.ww += item.ww
+      if (s.tradTp === '1') statsMap[s.county].industrial = item
+      else if (s.tradTp === '2') statsMap[s.county].service = item
+      else if (s.tradTp === '3') statsMap[s.county].publicSupply = item
+    })
+    
+    // 随机颜色数组
+    const colors = [
+      'rgba(28, 151, 231, 0.25)', 'rgba(23, 194, 199, 0.25)', 'rgba(103, 194, 58, 0.25)',
+      'rgba(230, 162, 60, 0.25)', 'rgba(245, 108, 108, 0.25)', 'rgba(144, 147, 153, 0.25)',
+      'rgba(28, 109, 231, 0.25)', 'rgba(22, 174, 237, 0.25)'
+    ]
+    
+    features.forEach((f, i) => {
+      const name = f.get('NAME99') || ''
+      f.set('_stats', statsMap[name] || null)
+      f.setStyle(new Style({
+        fill: new Fill({ color: colors[i % colors.length] }),
+        stroke: new Stroke({ color: 'rgba(28, 151, 231, 0.8)', width: 1.5 }),
+        text: name ? new TextStyle({
+          text: name,
+          font: 'bold 12px Microsoft YaHei',
+          fill: new Fill({ color: '#303133' }),
+          stroke: new Stroke({ color: '#fff', width: 3 }),
+          overflow: true
+        }) : undefined
+      }))
+    })
+    source.addFeatures(features)
+  } catch (e) {
+    console.error('加载区县GeoJSON失败', e)
+  }
+}
+
+// 渲染取水户点位
+function renderWiuLayer() {
+  if (!wiuLayer) return
+  const source = wiuLayer.getSource()
+  source.clear()
+  
+  const tradTpMap = { '1': '#e6a23c', '2': '#f56c6c', '3': '#67c23a' }
+  
+  wiuList.value.forEach(wiu => {
+    if (!wiu.lgtd || !wiu.lttd) return
+    const coord = fromLonLat([Number(wiu.lgtd), Number(wiu.lttd)])
+    const feature = new Feature({
+      geometry: new Point(coord),
+      wiuData: wiu
+    })
+    const color = tradTpMap[wiu.tradTp] || '#1c97e7'
+    feature.setStyle(new Style({
+      image: new CircleStyle({
+        radius: 5,
+        fill: new Fill({ color }),
+        stroke: new Stroke({ color: '#fff', width: 1.5 })
+      })
+    }))
+    source.addFeature(feature)
+  })
+}
+
+// 处理开发利用地图鼠标移动
+function handleWiuPointerMove(e) {
+  const container = e.target.getTarget()
+  if (!container) return
+  
+  const pixel = e.pixel
+  let found = false
+  
+  // 先检查取水户点
+  e.target.forEachFeatureAtPixel(pixel, (feature) => {
+    if (found) return
+    const wiuData = feature.get('wiuData')
+    if (wiuData) {
+      found = true
+      const tradTpNames = { '1': '工业自备水源', '2': '服务业自备水源', '3': '公共供水企业' }
+      wiuTooltipData.visible = true
+      wiuTooltipData.type = 'wiu'
+      wiuTooltipData.name = wiuData.stnm || ''
+      wiuTooltipData.uscc = wiuData.uscc || '-'
+      wiuTooltipData.tradTp = tradTpNames[wiuData.tradTp] || wiuData.tradTp || '-'
+      wiuTooltipData.county = wiuData.county || '-'
+      wiuTooltipStyle.value = {
+        left: (pixel[0] + 15) + 'px',
+        top: (pixel[1] - 10) + 'px'
+      }
+      container.style.cursor = 'pointer'
+    }
+  })
+  
+  // 再检查区县面
+  if (!found) {
+    e.target.forEachFeatureAtPixel(pixel, (feature) => {
+      if (found) return
+      const name = feature.get('NAME99')
+      if (name) {
+        found = true
+        const stats = feature.get('_stats')
+        wiuTooltipData.visible = true
+        wiuTooltipData.type = 'county'
+        wiuTooltipData.name = name
+        if (stats) {
+          wiuTooltipData.industrial = stats.industrial
+          wiuTooltipData.publicSupply = stats.publicSupply
+          wiuTooltipData.service = stats.service
+          wiuTooltipData.total = stats.total
+        } else {
+          wiuTooltipData.industrial = { cnt: 0, ww: 0 }
+          wiuTooltipData.publicSupply = { cnt: 0, ww: 0 }
+          wiuTooltipData.service = { cnt: 0, ww: 0 }
+          wiuTooltipData.total = { cnt: 0, ww: 0 }
+        }
+        wiuTooltipStyle.value = {
+          left: (pixel[0] + 15) + 'px',
+          top: (pixel[1] - 10) + 'px'
+        }
+        container.style.cursor = 'pointer'
+      }
+    })
+  }
+  
+  if (!found) {
+    wiuTooltipData.visible = false
+    container.style.cursor = ''
+  }
+}
+
+// 计算开发利用统计汇总
+const wiuSummary = computed(() => {
+  const summary = {
+    industrial: { cnt: 0, ww: 0 },
+    publicSupply: { cnt: 0, ww: 0 },
+    service: { cnt: 0, ww: 0 },
+    total: { cnt: 0, ww: 0 }
   }
+  wiuCountyStats.value.forEach(s => {
+    const cnt = s.cnt || 0
+    const ww = Number(s.yearWw) || 0
+    summary.total.cnt += cnt
+    summary.total.ww += ww
+    if (s.tradTp === '1') { summary.industrial.cnt += cnt; summary.industrial.ww += ww }
+    else if (s.tradTp === '2') { summary.service.cnt += cnt; summary.service.ww += ww }
+    else if (s.tradTp === '3') { summary.publicSupply.cnt += cnt; summary.publicSupply.ww += ww }
+  })
+  return summary
 })
 </script>
 
@@ -620,6 +1187,9 @@ watch(activeTab, (val) => {
   flex-direction: column;
   padding: 16px;
   overflow: hidden;
+  width: 100%;
+  height: 100%;
+  min-height: 0;
 }
 
 .xaj-tabs {
@@ -869,20 +1439,30 @@ watch(activeTab, (val) => {
   font-style: italic;
 }
 
-.utilization-placeholder {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
+.utilization-wrapper {
+  position: relative;
   height: 100%;
-  min-height: 400px;
-  background: #fff;
   border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
 }
 
-.utilization-placeholder p {
-  color: #909399;
-  margin: 12px 0;
+.utilization-map-container {
+  width: 100%;
+  height: 100%;
+  min-height: 500px;
+}
+
+.utilization-stats {
+  width: 300px;
+}
+
+.utilization-legend {
+  bottom: 16px;
+}
+
+.wiu-tooltip {
+  min-width: 220px;
 }
 
 @media (max-width: 768px) {

+ 3 - 0
gw-ui/src/views/front/xaj/QueryModule.vue

@@ -1141,6 +1141,9 @@ onMounted(() => {
   flex: 1;
   padding: 16px;
   overflow: auto;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
 }
 
 .query-container {

+ 3 - 0
gw-ui/src/views/front/xaj/ShareModule.vue

@@ -41,6 +41,9 @@ onMounted(() => {
   flex: 1;
   padding: 16px;
   overflow: auto;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
 }
 
 .share-container {