LAPTOP-JI2IUVG1\26646 3 nedēļas atpakaļ
vecāks
revīzija
71c90aed1f

+ 66 - 0
src/api/drainage.js

@@ -0,0 +1,66 @@
+import request from '@/utils/request'
+
+// ============ 排水分区 ============
+export function getPartitionPage(pageNum, pageSize, params) {
+  return request({ url: '/api/drainage/partition/page', method: 'get', params: { pageNum, pageSize, ...params } })
+}
+export function getPartitionById(id) {
+  return request({ url: '/api/drainage/partition/' + id, method: 'get' })
+}
+export function getPartitionList() {
+  return request({ url: '/api/drainage/partition/list', method: 'get' })
+}
+export function addPartition(data) {
+  return request({ url: '/api/drainage/partition', method: 'post', data })
+}
+export function updatePartition(data) {
+  return request({ url: '/api/drainage/partition', method: 'put', data })
+}
+export function deletePartition(id) {
+  return request({ url: '/api/drainage/partition/' + id, method: 'delete' })
+}
+export function batchDeletePartition(ids) {
+  return request({ url: '/api/drainage/partition/batch', method: 'delete', data: ids })
+}
+
+// ============ 排水管网 ============
+export function getPipeNetworkPage(pageNum, pageSize, params) {
+  return request({ url: '/api/drainage/pipeNetwork/page', method: 'get', params: { pageNum, pageSize, ...params } })
+}
+export function addDrainagePipeNetwork(data) {
+  return request({ url: '/api/drainage/pipeNetwork', method: 'post', data })
+}
+export function updateDrainagePipeNetwork(data) {
+  return request({ url: '/api/drainage/pipeNetwork', method: 'put', data })
+}
+export function deleteDrainagePipeNetwork(id) {
+  return request({ url: '/api/drainage/pipeNetwork/' + id, method: 'delete' })
+}
+
+// ============ 工程设施 ============
+export function getFacilityPage(pageNum, pageSize, params) {
+  return request({ url: '/api/drainage/facility/page', method: 'get', params: { pageNum, pageSize, ...params } })
+}
+export function addFacility(data) {
+  return request({ url: '/api/drainage/facility', method: 'post', data })
+}
+export function updateFacility(data) {
+  return request({ url: '/api/drainage/facility', method: 'put', data })
+}
+export function deleteFacility(id) {
+  return request({ url: '/api/drainage/facility/' + id, method: 'delete' })
+}
+
+// ============ 易积水点 ============
+export function getWaterloggingPage(pageNum, pageSize, params) {
+  return request({ url: '/api/drainage/waterlogging/page', method: 'get', params: { pageNum, pageSize, ...params } })
+}
+export function addWaterlogging(data) {
+  return request({ url: '/api/drainage/waterlogging', method: 'post', data })
+}
+export function updateWaterlogging(data) {
+  return request({ url: '/api/drainage/waterlogging', method: 'put', data })
+}
+export function deleteWaterlogging(id) {
+  return request({ url: '/api/drainage/waterlogging/' + id, method: 'delete' })
+}

+ 290 - 371
src/views/subSystem/drainage/jcsj/gcssgl.vue

@@ -1,13 +1,31 @@
 <template>
   <div class="app-container">
+    <!-- GIS 地图展示区 -->
+    <div class="map-section" style="margin-bottom: 16px;">
+      <div class="map-tabs">
+        <div class="map-tab" :class="{ active: mainMapTab === 'all' }" @click="switchMainMapTab('all')">全部</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'gate' }" @click="switchMainMapTab('gate')">闸门</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'storage' }" @click="switchMainMapTab('storage')">调蓄设施</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'pump' }" @click="switchMainMapTab('pump')">泵站</div>
+      </div>
+      <div id="gcssglMainMap" class="map-container" style="height: 350px;"></div>
+    </div>
+
     <!-- 搜索区域 -->
     <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
-      <el-form-item label="监测点名称">
+      <el-form-item label="设施名称">
         <el-input v-model="queryParams.name" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
       <el-form-item label="行政区域">
         <el-input v-model="queryParams.area" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
+      <el-form-item label="设施类型">
+        <el-select v-model="queryParams.facilityType" placeholder="请选择" clearable style="width: 200px">
+          <el-option label="闸门" value="闸门" />
+          <el-option label="调蓄设施" value="调蓄设施" />
+          <el-option label="泵站" value="泵站" />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="handleQuery">搜索</el-button>
       </el-form-item>
@@ -20,14 +38,13 @@
     </div>
 
     <!-- 数据表格 -->
-    <el-table :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="监测点名称" prop="name" min-width="160" />
       <el-table-column label="行政区域" prop="area" min-width="100" />
+      <el-table-column label="设施类型" prop="facilityType" min-width="100" />
       <el-table-column label="数据时间" prop="time" min-width="120" />
-      <el-table-column label="闸门数量" prop="gateCount" min-width="80" />
-      <el-table-column label="调蓄数量" prop="storageCount" min-width="80" />
-      <el-table-column label="泵站数量" prop="pumpCount" min-width="80" />
+      <el-table-column label="标记数量" prop="pointCount" min-width="80" />
       <el-table-column label="操作" width="180" align="center">
         <template #default="{ row }">
           <el-button link type="primary" @click="handleView(row)">查看</el-button>
@@ -37,6 +54,18 @@
       </el-table-column>
     </el-table>
 
+    <!-- 分页 -->
+    <el-pagination
+      v-model:current-page="pageNum"
+      v-model:page-size="pageSize"
+      :total="total"
+      :page-sizes="[10, 20, 50, 100]"
+      layout="total, sizes, prev, pager, next, jumper"
+      style="margin-top: 16px; justify-content: flex-end;"
+      @size-change="loadData"
+      @current-change="loadData"
+    />
+
     <!-- 查看详情对话框 -->
     <el-dialog v-model="dialogVisible" title="详情" width="700px" :before-close="handleClose" @opened="onDialogOpened">
       <div class="detail-info">
@@ -57,28 +86,22 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">数据时间:</span>
-              <span class="info-value">{{ currentRow.time }}</span>
+              <span class="info-label">设施类型:</span>
+              <span class="info-value">{{ currentRow.facilityType }}</span>
             </div>
           </el-col>
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">闸门数量:</span>
-              <span class="info-value">{{ (currentRow.gatePoints || []).length }}</span>
+              <span class="info-label">数据时间:</span>
+              <span class="info-value">{{ currentRow.time }}</span>
             </div>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">调蓄数量:</span>
-              <span class="info-value">{{ (currentRow.storagePoints || []).length }}</span>
-            </div>
-          </el-col>
-          <el-col :span="12">
-            <div class="info-item">
-              <span class="info-label">泵站数量:</span>
-              <span class="info-value">{{ (currentRow.pumpPoints || []).length }}</span>
+              <span class="info-label">标记数量:</span>
+              <span class="info-value">{{ currentRowPointCount }}</span>
             </div>
           </el-col>
         </el-row>
@@ -87,12 +110,7 @@
       <!-- 地图区域 -->
       <div class="map-section">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: viewMapTab === 'gate' }"
-            @click="switchViewMapTab('gate')">闸门</div>
-          <div class="map-tab" :class="{ active: viewMapTab === 'storage' }"
-            @click="switchViewMapTab('storage')">调蓄设施</div>
-          <div class="map-tab" :class="{ active: viewMapTab === 'pump' }"
-            @click="switchViewMapTab('pump')">泵站</div>
+          <div class="map-tab active">{{ currentRow.facilityType || '位置标记' }}</div>
         </div>
         <div id="gcssglViewMap" class="map-container"></div>
       </div>
@@ -115,6 +133,16 @@
           </el-col>
         </el-row>
         <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="设施类型" prop="facilityType">
+              <el-select v-model="editForm.facilityType" placeholder="请选择设施类型" style="width:100%"
+                @change="onFacilityTypeChange">
+                <el-option label="闸门" value="闸门" />
+                <el-option label="调蓄设施" value="调蓄设施" />
+                <el-option label="泵站" value="泵站" />
+              </el-select>
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="数据时间" prop="time">
               <el-date-picker v-model="editForm.time" type="date" placeholder="请选择日期" value-format="YYYY-MM-DD"
@@ -123,19 +151,9 @@
           </el-col>
         </el-row>
         <el-row :gutter="20">
-          <el-col :span="8">
-            <el-form-item label="闸门数量">
-              <el-input :model-value="editGatePoints.length" disabled />
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="调蓄数量">
-              <el-input :model-value="editStoragePoints.length" disabled />
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="泵站数量">
-              <el-input :model-value="editPumpPoints.length" disabled />
+          <el-col :span="12">
+            <el-form-item label="标记数量">
+              <el-input :model-value="editPoints.length" disabled />
             </el-form-item>
           </el-col>
         </el-row>
@@ -144,17 +162,12 @@
       <!-- 地图标点区域 -->
       <div class="map-section" style="margin-top: 16px;">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: editMapTab === 'gate' }"
-            @click="switchEditMapTab('gate')">闸门</div>
-          <div class="map-tab" :class="{ active: editMapTab === 'storage' }"
-            @click="switchEditMapTab('storage')">调蓄设施</div>
-          <div class="map-tab" :class="{ active: editMapTab === 'pump' }"
-            @click="switchEditMapTab('pump')">泵站</div>
+          <div class="map-tab active">{{ editForm.facilityType || '位置标记' }}</div>
           <div class="map-tab-action" @click="clearEditMarkers">清除所有标记</div>
         </div>
         <div id="gcssglEditMap" class="map-container" style="height: 350px;"></div>
         <div class="marker-count">
-          已标记 {{ currentEditPoints.length }} 个{{ editMapTabLabel }}
+          已标记 {{ editPoints.length }} 个{{ editForm.facilityType || '标记' }}
         </div>
       </div>
 
@@ -167,14 +180,21 @@
 </template>
 
 <script setup name="Gcssgl">
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import locationIcon from '@/assets/images/location.png'
+import {
+  getFacilityPage,
+  addFacility,
+  updateFacility,
+  deleteFacility
+} from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
-function createMapMarker(map, bPoint, name) {
+function createMapMarker(map, bPoint, name, bgColor) {
+  const color = bgColor || '#409eff'
   const html = `<div style="text-align:center;cursor:pointer;">
-    <div style="color:#fff;background:#409eff;border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
+    <div style="color:#fff;background:${color};border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
     <div><img src="${locationIcon}" style="width:28px;height:28px;display:block;margin:0 auto;"/></div>
   </div>`
   const label = new BMapGL.Label(html, {
@@ -190,77 +210,106 @@ function createMapMarker(map, bPoint, name) {
   return label
 }
 
+// 解析坐标数据(兼容JSON字符串和数组)
+function parsePoints(data) {
+  if (!data) return []
+  if (typeof data === 'string') {
+    try { return JSON.parse(data) } catch (e) { return [] }
+  }
+  return Array.isArray(data) ? data : []
+}
+
+// ==================== 顶部主地图 ====================
+let mainMapInstance = null
+const mainMapTab = ref('all')
+
+function switchMainMapTab(tab) {
+  mainMapTab.value = tab
+  renderMainMapMarkers()
+}
+
+function initMainMap() {
+  const container = document.getElementById('gcssglMainMap')
+  if (!container) return
+  try {
+    mainMapInstance = new BMapGL.Map('gcssglMainMap')
+    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    mainMapInstance.centerAndZoom(centerPoint, 12)
+    mainMapInstance.enableScrollWheelZoom(true)
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('顶部百度地图初始化失败:', e)
+  }
+}
+
+function renderMainMapMarkers() {
+  if (!mainMapInstance) return
+  mainMapInstance.clearOverlays()
+
+  const allPoints = []
+  const tab = mainMapTab.value
+  const typeMap = { gate: '闸门', storage: '调蓄设施', pump: '泵站' }
+  const colorMap = { '闸门': '#409eff', '调蓄设施': '#e6a23c', '泵站': '#67c23a' }
+  const targetType = tab === 'all' ? null : typeMap[tab]
+
+  tableData.value.forEach(row => {
+    if (targetType && row.facilityType !== targetType) return
+    const points = parsePoints(row.points)
+    const color = colorMap[row.facilityType] || '#409eff'
+
+    points.forEach(p => {
+      if (p.lng && p.lat) {
+        const bPoint = new BMapGL.Point(p.lng, p.lat)
+        createMapMarker(mainMapInstance, bPoint, p.name || row.name, color)
+        allPoints.push(bPoint)
+      }
+    })
+  })
+
+  if (allPoints.length > 0) {
+    mainMapInstance.setViewport(allPoints)
+  }
+}
+
 // ==================== 搜索参数 ====================
 const queryParams = ref({
   name: '',
-  area: ''
+  area: '',
+  facilityType: ''
 })
 
 // ==================== 表格数据 ====================
-let nextId = 5
-const tableData = ref([
-  {
-    id: 1, name: '沅陵北路1号工程设施', area: '沅陵县', time: '2025-12-31',
-    gateCount: 3, storageCount: 2, pumpCount: 2,
-    gatePoints: [
-      { name: '闸门1', lng: 110.393, lat: 28.452 },
-      { name: '闸门2', lng: 110.398, lat: 28.455 },
-      { name: '闸门3', lng: 110.402, lat: 28.450 }
-    ],
-    storagePoints: [
-      { name: '调蓄设施1', lng: 110.395, lat: 28.448 },
-      { name: '调蓄设施2', lng: 110.400, lat: 28.460 }
-    ],
-    pumpPoints: [
-      { name: '泵站1', lng: 110.390, lat: 28.445 },
-      { name: '泵站2', lng: 110.408, lat: 28.458 }
-    ]
-  },
-  {
-    id: 2, name: '沅陵南路1号工程设施', area: '沅陵县', time: '2025-12-30',
-    gateCount: 2, storageCount: 1, pumpCount: 1,
-    gatePoints: [
-      { name: '闸门1', lng: 110.385, lat: 28.446 },
-      { name: '闸门2', lng: 110.390, lat: 28.444 }
-    ],
-    storagePoints: [
-      { name: '调蓄设施1', lng: 110.388, lat: 28.450 }
-    ],
-    pumpPoints: [
-      { name: '泵站1', lng: 110.392, lat: 28.442 }
-    ]
-  },
-  {
-    id: 3, name: '沅陵东路2号工程设施', area: '沅陵县', time: '2025-12-29',
-    gateCount: 2, storageCount: 2, pumpCount: 3,
-    gatePoints: [
-      { name: '闸门1', lng: 110.400, lat: 28.456 },
-      { name: '闸门2', lng: 110.405, lat: 28.458 }
-    ],
-    storagePoints: [
-      { name: '调蓄设施1', lng: 110.403, lat: 28.454 },
-      { name: '调蓄设施2', lng: 110.409, lat: 28.461 }
-    ],
-    pumpPoints: [
-      { name: '泵站1', lng: 110.413, lat: 28.461 },
-      { name: '泵站2', lng: 110.396, lat: 28.457 },
-      { name: '泵站3', lng: 110.410, lat: 28.453 }
-    ]
-  },
-  {
-    id: 4, name: '沅陵西路1号工程设施', area: '沅陵县', time: '2025-12-28',
-    gateCount: 1, storageCount: 1, pumpCount: 1,
-    gatePoints: [
-      { name: '闸门1', lng: 110.380, lat: 28.450 }
-    ],
-    storagePoints: [
-      { name: '调蓄设施1', lng: 110.382, lat: 28.448 }
-    ],
-    pumpPoints: [
-      { name: '泵站1', lng: 110.378, lat: 28.446 }
-    ]
+const tableData = ref([])
+const total = ref(0)
+const pageNum = ref(1)
+const pageSize = ref(10)
+const loading = ref(false)
+
+// 加载分页数据
+async function loadData() {
+  loading.value = true
+  try {
+    const res = await getFacilityPage(pageNum.value, pageSize.value, queryParams.value)
+    const pageData = res.code !== undefined ? res.data : res
+    const records = pageData.records || []
+    records.forEach(row => {
+      const pts = parsePoints(row.points)
+      row.pointCount = pts.length
+    })
+    tableData.value = records
+    total.value = pageData.total || 0
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('加载工程设施数据失败', e)
+  } finally {
+    loading.value = false
   }
-])
+}
+
+onMounted(() => {
+  loadData()
+  setTimeout(() => { initMainMap() }, 500)
+})
 
 // 多选
 const selectedIds = ref([])
@@ -268,49 +317,39 @@ function handleSelectionChange(selection) {
   selectedIds.value = selection.map(item => item.id)
 }
 
-// 过滤后的列表
-const filteredList = computed(() => {
-  return tableData.value.filter(item => {
-    const nameMatch = !queryParams.value.name || item.name.includes(queryParams.value.name)
-    const areaMatch = !queryParams.value.area || item.area.includes(queryParams.value.area)
-    return nameMatch && areaMatch
-  })
-})
+const filteredList = computed(() => tableData.value)
 
-// 搜索
 function handleQuery() {
-  queryParams.value = { ...queryParams.value }
+  pageNum.value = 1
+  loadData()
 }
 
 // ==================== 查看详情对话框 ====================
 const dialogVisible = ref(false)
 const currentRow = ref({})
-const viewMapTab = ref('gate')
 let viewMapInstance = null
 
+const currentRowPointCount = computed(() => {
+  return parsePoints(currentRow.value.points).length
+})
+
 function handleView(row) {
   currentRow.value = { ...row }
-  viewMapTab.value = 'gate'
   dialogVisible.value = true
 }
 
 function handleClose() {
   dialogVisible.value = false
-  if (viewMapInstance) {
-    viewMapInstance = null
-  }
+  if (viewMapInstance) { viewMapInstance = null }
 }
 
 function onDialogOpened() {
-  setTimeout(() => {
-    initViewMap()
-  }, 300)
+  setTimeout(() => { initViewMap() }, 300)
 }
 
 function initViewMap() {
   const container = document.getElementById('gcssglViewMap')
   if (!container) return
-
   try {
     viewMapInstance = new BMapGL.Map('gcssglViewMap')
     const centerPoint = new BMapGL.Point(110.393, 28.452)
@@ -322,22 +361,17 @@ function initViewMap() {
   }
 }
 
-function getViewPoints() {
-  const tab = viewMapTab.value
-  if (tab === 'gate') return currentRow.value.gatePoints || []
-  if (tab === 'storage') return currentRow.value.storagePoints || []
-  return currentRow.value.pumpPoints || []
-}
-
 function renderViewMarkers() {
   if (!viewMapInstance) return
   viewMapInstance.clearOverlays()
 
-  const points = getViewPoints()
+  const points = parsePoints(currentRow.value.points)
+  const colorMap = { '闸门': '#409eff', '调蓄设施': '#e6a23c', '泵站': '#67c23a' }
+  const color = colorMap[currentRow.value.facilityType] || '#409eff'
 
   points.forEach(point => {
     const bPoint = new BMapGL.Point(point.lng, point.lat)
-    createMapMarker(viewMapInstance, bPoint, point.name)
+    createMapMarker(viewMapInstance, bPoint, point.name, color)
   })
 
   if (points.length > 0) {
@@ -346,11 +380,6 @@ function renderViewMarkers() {
   }
 }
 
-function switchViewMapTab(tab) {
-  viewMapTab.value = tab
-  renderViewMarkers()
-}
-
 // ==================== 新增/修改对话框 ====================
 const editDialogVisible = ref(false)
 const editDialogTitle = ref('新增监测点')
@@ -361,60 +390,38 @@ const editRowId = ref(null)
 const editForm = ref({
   name: '',
   area: '',
+  facilityType: '',
   time: '',
-  gateCount: '',
-  storageCount: '',
-  pumpCount: ''
+  pointCount: 0,
+  points: []
 })
 
 const editRules = {
   name: [{ required: true, message: '请输入监测点名称', trigger: 'blur' }],
   area: [{ required: true, message: '请输入行政区域', trigger: 'blur' }],
+  facilityType: [{ required: true, message: '请选择设施类型', trigger: 'change' }],
   time: [{ required: true, message: '请选择数据时间', trigger: 'change' }]
 }
 
 // 编辑弹窗地图相关
-const editMapTab = ref('gate')
 let editMapInstance = null
-let editGatePoints = ref([])
-let editStoragePoints = ref([])
-let editPumpPoints = ref([])
-let editGateMarkerCount = ref(0)
-let editStorageMarkerCount = ref(0)
-let editPumpMarkerCount = ref(0)
-
-// tab 中文名称
-const editMapTabLabel = computed(() => {
-  const map = { gate: '闸门', storage: '调蓄设施', pump: '泵站' }
-  return map[editMapTab.value] || ''
-})
+let editPoints = ref([])
+let editMarkerCount = ref(0)
 
-// 当前 tab 对应的点列表
-const currentEditPoints = computed(() => {
-  if (editMapTab.value === 'gate') return editGatePoints.value
-  if (editMapTab.value === 'storage') return editStoragePoints.value
-  return editPumpPoints.value
-})
+// 设施类型变更时,清空已有标记
+function onFacilityTypeChange() {
+  editPoints.value = []
+  editMarkerCount.value = 0
+  renderEditMarkers()
+}
 
 function handleAdd() {
   isEditMode.value = false
   editDialogTitle.value = '新增监测点'
   editRowId.value = null
-  editForm.value = {
-    name: '',
-    area: '',
-    time: '',
-    gateCount: '',
-    storageCount: '',
-    pumpCount: ''
-  }
-  editMapTab.value = 'gate'
-  editGatePoints.value = []
-  editStoragePoints.value = []
-  editPumpPoints.value = []
-  editGateMarkerCount.value = 0
-  editStorageMarkerCount.value = 0
-  editPumpMarkerCount.value = 0
+  editForm.value = { name: '', area: '', facilityType: '', time: '', pointCount: 0, points: [] }
+  editPoints.value = []
+  editMarkerCount.value = 0
   editDialogVisible.value = true
 }
 
@@ -425,88 +432,70 @@ function handleEdit(row) {
   editForm.value = {
     name: row.name,
     area: row.area,
+    facilityType: row.facilityType,
     time: row.time,
-    gateCount: row.gateCount,
-    storageCount: row.storageCount,
-    pumpCount: row.pumpCount
+    pointCount: row.pointCount || 0,
+    points: []
   }
-  editMapTab.value = 'gate'
-  // 深拷贝标记点数据
-  editGatePoints.value = (row.gatePoints || []).map(p => ({ ...p }))
-  editStoragePoints.value = (row.storagePoints || []).map(p => ({ ...p }))
-  editPumpPoints.value = (row.pumpPoints || []).map(p => ({ ...p }))
-  editGateMarkerCount.value = editGatePoints.value.length
-  editStorageMarkerCount.value = editStoragePoints.value.length
-  editPumpMarkerCount.value = editPumpPoints.value.length
+  const pts = parsePoints(row.points)
+  editPoints.value = pts.map(p => ({ ...p }))
+  editMarkerCount.value = editPoints.value.length
   editDialogVisible.value = true
 }
 
 function handleEditClose() {
   editDialogVisible.value = false
-  if (editMapInstance) {
-    editMapInstance = null
-  }
+  if (editMapInstance) { editMapInstance = null }
 }
 
 function onEditDialogOpened() {
-  setTimeout(() => {
-    initEditMap()
-  }, 300)
+  setTimeout(() => { initEditMap() }, 300)
 }
 
 function initEditMap() {
   const container = document.getElementById('gcssglEditMap')
   if (!container) return
-
   try {
     editMapInstance = new BMapGL.Map('gcssglEditMap')
     const centerPoint = new BMapGL.Point(110.393, 28.452)
     editMapInstance.centerAndZoom(centerPoint, 15)
     editMapInstance.enableScrollWheelZoom(true)
 
-    // 点击地图添加标记
     editMapInstance.addEventListener('click', function (e) {
       addEditMarker(e.latlng)
     })
 
-    // 渲染已有标记
     renderEditMarkers()
   } catch (e) {
     console.error('百度地图初始化失败:', e)
   }
 }
 
-function getCurrentEditPointList() {
-  if (editMapTab.value === 'gate') return editGatePoints.value
-  if (editMapTab.value === 'storage') return editStoragePoints.value
-  return editPumpPoints.value
-}
-
 function addEditMarker(point) {
-  const tab = editMapTab.value
-  let pointList, count, labelPrefix
-
-  if (tab === 'gate') {
-    pointList = editGatePoints.value
-    count = ++editGateMarkerCount.value
-    labelPrefix = '闸门'
-  } else if (tab === 'storage') {
-    pointList = editStoragePoints.value
-    count = ++editStorageMarkerCount.value
-    labelPrefix = '调蓄设施'
-  } else {
-    pointList = editPumpPoints.value
-    count = ++editPumpMarkerCount.value
-    labelPrefix = '泵站'
+  const facilityType = editForm.value.facilityType
+  if (!facilityType) {
+    ElMessage.warning('请先选择设施类型')
+    return
   }
 
-  pointList.push({
-    name: `${labelPrefix}${count}`,
+  // 单点类型:再次点击重新定位
+  if (editPoints.value.length >= 1) {
+    editPoints.value[0] = {
+      name: editPoints.value[0].name,
+      lng: point.lng,
+      lat: point.lat
+    }
+    renderEditMarkers(false)
+    return
+  }
+
+  const count = ++editMarkerCount.value
+  editPoints.value.push({
+    name: `${facilityType}${count}`,
     lng: point.lng,
     lat: point.lat
   })
 
-  // 统一重绘,保证地图与数据完全一致
   renderEditMarkers(false)
 }
 
@@ -514,7 +503,7 @@ function renderEditMarkers(shouldCenter = true) {
   if (!editMapInstance) return
   editMapInstance.clearOverlays()
 
-  const points = getCurrentEditPointList()
+  const points = editPoints.value
   if (shouldCenter) {
     const center = points.length > 0
       ? new BMapGL.Point(points[0].lng, points[0].lat)
@@ -522,69 +511,63 @@ function renderEditMarkers(shouldCenter = true) {
     editMapInstance.centerAndZoom(center, 15)
   }
 
+  const colorMap = { '闸门': '#409eff', '调蓄设施': '#e6a23c', '泵站': '#67c23a' }
+  const color = colorMap[editForm.value.facilityType] || '#409eff'
+
   points.forEach((point, index) => {
     const bPoint = new BMapGL.Point(point.lng, point.lat)
-    const label = createMapMarker(editMapInstance, bPoint, point.name)
+    const label = createMapMarker(editMapInstance, bPoint, point.name, color)
 
-    // 右键删除标记
     label.addEventListener('rightclick', () => {
-      const list = getCurrentEditPointList()
-      list.splice(index, 1)
+      editPoints.value.splice(index, 1)
       renderEditMarkers(false)
     })
   })
 }
 
-function switchEditMapTab(tab) {
-  editMapTab.value = tab
-  renderEditMarkers()
-}
-
 function clearEditMarkers() {
-  if (editMapTab.value === 'gate') {
-    editGatePoints.value = []
-    editGateMarkerCount.value = 0
-  } else if (editMapTab.value === 'storage') {
-    editStoragePoints.value = []
-    editStorageMarkerCount.value = 0
-  } else {
-    editPumpPoints.value = []
-    editPumpMarkerCount.value = 0
-  }
+  editPoints.value = []
+  editMarkerCount.value = 0
   renderEditMarkers()
 }
 
 function handleEditSubmit() {
-  editFormRef.value.validate(valid => {
+  editFormRef.value.validate(async valid => {
     if (!valid) return
 
     const formData = {
-      ...editForm.value,
-      gatePoints: editGatePoints.value.map(p => ({ ...p })),
-      storagePoints: editStoragePoints.value.map(p => ({ ...p })),
-      pumpPoints: editPumpPoints.value.map(p => ({ ...p })),
-      gateCount: editGatePoints.value.length,
-      storageCount: editStoragePoints.value.length,
-      pumpCount: editPumpPoints.value.length
+      name: editForm.value.name,
+      area: editForm.value.area,
+      facilityType: editForm.value.facilityType,
+      time: editForm.value.time,
+      pointCount: editPoints.value.length,
+      points: JSON.stringify(editPoints.value.map(p => ({ name: p.name, lng: p.lng, lat: p.lat })))
     }
-
-    if (isEditMode.value) {
-      // 修改
-      const index = tableData.value.findIndex(item => item.id === editRowId.value)
-      if (index !== -1) {
-        tableData.value[index] = { ...tableData.value[index], ...formData }
+    try {
+      if (isEditMode.value) {
+        formData.id = editRowId.value
+        const res = await updateFacility(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('修改成功')
+        } else {
+          ElMessage.error(res.msg || '修改失败')
+          return
+        }
+      } else {
+        const res = await addFacility(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('新增成功')
+        } else {
+          ElMessage.error(res.msg || '新增失败')
+          return
+        }
       }
-      ElMessage.success('修改成功')
-    } else {
-      // 新增
-      formData.id = nextId++
-      tableData.value.push(formData)
-      ElMessage.success('新增成功')
-    }
-
-    editDialogVisible.value = false
-    if (editMapInstance) {
-      editMapInstance = null
+      editDialogVisible.value = false
+      if (editMapInstance) { editMapInstance = null }
+      loadData()
+    } catch (e) {
+      console.error('提交失败', e)
+      ElMessage.error('操作失败')
     }
   })
 }
@@ -595,13 +578,19 @@ function handleDelete(row) {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    const index = tableData.value.findIndex(item => item.id === row.id)
-    if (index !== -1) {
-      tableData.value.splice(index, 1)
+  }).then(async () => {
+    try {
+      const res = await deleteFacility(row.id)
+      if (res.code === 0 || res.code === 200) {
+        ElMessage.success('删除成功')
+        loadData()
+      } else {
+        ElMessage.error(res.msg || '删除失败')
+      }
+    } catch (e) {
+      ElMessage.error('删除失败')
     }
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).catch(() => {})
 }
 
 function handleBatchDelete() {
@@ -610,104 +599,34 @@ function handleBatchDelete() {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id))
-    selectedIds.value = []
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).then(async () => {
+    try {
+      await Promise.all(selectedIds.value.map(id => deleteFacility(id)))
+      selectedIds.value = []
+      ElMessage.success('删除成功')
+      loadData()
+    } catch (e) {
+      ElMessage.error('删除失败')
+    }
+  }).catch(() => {})
 }
 </script>
 
 <style scoped>
-.app-container {
-  padding: 20px;
-}
-
-.search-form {
-  margin-bottom: 16px;
-}
-
-.toolbar {
-  margin-bottom: 16px;
-}
-
-.detail-info {
-  margin-bottom: 16px;
-}
-
-.info-item {
-  display: flex;
-  align-items: center;
-  margin-bottom: 12px;
-  line-height: 32px;
-}
-
-.info-label {
-  color: #909399;
-  font-size: 14px;
-  white-space: nowrap;
-}
-
-.info-value {
-  color: #303133;
-  font-size: 14px;
-}
-
-.map-section {
-  border: 1px solid #e4e7ed;
-  border-radius: 4px;
-  overflow: hidden;
-}
-
-.map-tabs {
-  display: flex;
-  background: #f5f7fa;
-  border-bottom: 1px solid #e4e7ed;
-}
-
-.map-tab {
-  padding: 8px 24px;
-  font-size: 14px;
-  cursor: pointer;
-  color: #606266;
-  transition: all 0.3s;
-  user-select: none;
-}
-
-.map-tab:hover {
-  color: #409eff;
-}
-
-.map-tab.active {
-  background: #409eff;
-  color: #fff;
-}
-
-.map-tab-action {
-  padding: 8px 24px;
-  font-size: 14px;
-  cursor: pointer;
-  color: #f56c6c;
-  transition: all 0.3s;
-  user-select: none;
-  margin-left: auto;
-}
-
-.map-tab-action:hover {
-  color: #f78989;
-  text-decoration: underline;
-}
-
-.map-container {
-  width: 100%;
-  height: 400px;
-}
-
-.marker-count {
-  padding: 8px 16px;
-  font-size: 13px;
-  color: #909399;
-  background: #f5f7fa;
-  border-top: 1px solid #e4e7ed;
-}
+.app-container { padding: 20px; }
+.search-form { margin-bottom: 16px; }
+.toolbar { margin-bottom: 16px; }
+.detail-info { margin-bottom: 16px; }
+.info-item { display: flex; align-items: center; margin-bottom: 12px; line-height: 32px; }
+.info-label { color: #909399; font-size: 14px; white-space: nowrap; }
+.info-value { color: #303133; font-size: 14px; }
+.map-section { border: 1px solid #e4e7ed; border-radius: 4px; overflow: hidden; }
+.map-tabs { display: flex; background: #f5f7fa; border-bottom: 1px solid #e4e7ed; }
+.map-tab { padding: 8px 24px; font-size: 14px; cursor: pointer; color: #606266; transition: all 0.3s; user-select: none; }
+.map-tab:hover { color: #409eff; }
+.map-tab.active { background: #409eff; color: #fff; }
+.map-tab-action { padding: 8px 24px; font-size: 14px; cursor: pointer; color: #f56c6c; transition: all 0.3s; user-select: none; margin-left: auto; }
+.map-tab-action:hover { color: #f78989; text-decoration: underline; }
+.map-container { width: 100%; height: 400px; }
+.marker-count { padding: 8px 16px; font-size: 13px; color: #909399; background: #f5f7fa; border-top: 1px solid #e4e7ed; }
 </style>

+ 253 - 249
src/views/subSystem/drainage/jcsj/psfqgl.vue

@@ -1,14 +1,27 @@
 <template>
   <div class="app-container">
+    <!-- GIS 地图展示区 -->
+    <div class="map-section" style="margin-bottom: 16px;">
+      <div class="map-tabs">
+        <div class="map-tab" :class="{ active: mapTab === 'all' }" @click="switchMapTab('all')">全部</div>
+        <div class="map-tab" :class="{ active: mapTab === '雨水分区' }" @click="switchMapTab('雨水分区')">雨水分区</div>
+        <div class="map-tab" :class="{ active: mapTab === '污水分区' }" @click="switchMapTab('污水分区')">污水分区</div>
+      </div>
+      <div id="psfqglMainMap" class="map-container" style="height: 350px;"></div>
+    </div>
+
     <!-- 搜索区域 -->
     <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
-      <el-form-item label="区域名称">
+      <el-form-item label="监测点名称">
         <el-input v-model="queryParams.name" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
-      <el-form-item label="类型">
-        <el-select v-model="queryParams.type" placeholder="请输入" clearable style="width: 200px">
-          <el-option label="积水点" value="1" />
-          <el-option label="排水点" value="2" />
+      <el-form-item label="地点">
+        <el-input v-model="queryParams.district" placeholder="请输入" clearable style="width: 200px" />
+      </el-form-item>
+      <el-form-item label="分区类型">
+        <el-select v-model="queryParams.partitionType" placeholder="请选择" clearable style="width: 200px">
+          <el-option label="雨水分区" value="雨水分区" />
+          <el-option label="污水分区" value="污水分区" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -23,18 +36,16 @@
     </div>
 
     <!-- 数据表格 -->
-    <el-table :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="filteredList" border style="width: 100%"
+      @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="监测点名称" prop="name" min-width="160" />
-      <el-table-column label="行政区域" prop="area" min-width="100" />
+      <el-table-column label="地点" prop="district" min-width="100" />
+      <el-table-column label="分区类型" prop="partitionType" min-width="100" />
       <el-table-column label="数据时间" prop="time" min-width="120" />
-      <el-table-column label="排水量" prop="drainage" min-width="80" />
-      <el-table-column label="积水量" prop="waterlogging" min-width="80" />
-      <el-table-column label="积水等级" prop="level" min-width="80">
-        <template #default="{ row }">
-          <span>{{ levelText(row.level) }}</span>
-        </template>
-      </el-table-column>
+      <el-table-column label="排水量" prop="drainage" min-width="90" />
+      <el-table-column label="积水量" prop="waterlogging" min-width="90" />
+      <el-table-column label="积水等级" prop="level" min-width="80" />
       <el-table-column label="操作" width="180" align="center">
         <template #default="{ row }">
           <el-button link type="primary" @click="handleView(row)">查看</el-button>
@@ -44,6 +55,11 @@
       </el-table-column>
     </el-table>
 
+    <!-- 分页 -->
+    <el-pagination v-model:current-page="pageNum" v-model:page-size="pageSize" :total="total"
+      :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper"
+      style="margin-top: 16px; justify-content: flex-end;" @size-change="loadData" @current-change="loadData" />
+
     <!-- 查看详情对话框 -->
     <el-dialog v-model="dialogVisible" title="详情" width="700px" :before-close="handleClose" @opened="onDialogOpened">
       <div class="detail-info">
@@ -57,7 +73,7 @@
           <el-col :span="12">
             <div class="info-item">
               <span class="info-label">行政区域:</span>
-              <span class="info-value">{{ currentRow.area }}</span>
+              <span class="info-value">{{ currentRow.district }}</span>
             </div>
           </el-col>
         </el-row>
@@ -70,22 +86,22 @@
           </el-col>
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">水量:</span>
-              <span class="info-value">{{ currentRow.waterlogging }}</span>
+              <span class="info-label">水量:</span>
+              <span class="info-value">{{ currentRow.drainage }}</span>
             </div>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">积水等级:</span>
-              <span class="info-value">{{ levelText(currentRow.level) }}</span>
+              <span class="info-label">积水:</span>
+              <span class="info-value">{{ currentRow.waterlogging }}</span>
             </div>
           </el-col>
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">排水量:</span>
-              <span class="info-value">{{ currentRow.drainage }}</span>
+              <span class="info-label">积水等级:</span>
+              <span class="info-value">{{ currentRow.level }}</span>
             </div>
           </el-col>
         </el-row>
@@ -94,10 +110,7 @@
       <!-- 地图区域 -->
       <div class="map-section">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: viewMapTab === 'waterlogging' }"
-            @click="switchViewMapTab('waterlogging')">积水点</div>
-          <div class="map-tab" :class="{ active: viewMapTab === 'drainage' }" @click="switchViewMapTab('drainage')">排水点
-          </div>
+          <div class="map-tab active">位置标记</div>
         </div>
         <div id="psfqglViewMap" class="map-container"></div>
       </div>
@@ -114,33 +127,46 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="行政区域" prop="area">
-              <el-input v-model="editForm.area" placeholder="请输入行政区域" />
+            <el-form-item label="地点" prop="district">
+              <el-input v-model="editForm.district" placeholder="请输入地点" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="数据时间" prop="time">
-              <el-date-picker v-model="editForm.time" type="date" placeholder="选择日期" value-format="YYYY-MM-DD"
+              <el-date-picker v-model="editForm.time" type="date" placeholder="选择日期" value-format="YYYY-MM-DD"
                 style="width: 100%" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="排水量" prop="drainage">
-              <el-input v-model="editForm.drainage" placeholder="请输入排水量" />
+            <el-form-item label="分区类型" prop="partitionType">
+              <el-select v-model="editForm.partitionType" placeholder="请选择分区类型" style="width:100%">
+                <el-option label="雨水分区" value="雨水分区" />
+                <el-option label="污水分区" value="污水分区" />
+              </el-select>
             </el-form-item>
           </el-col>
         </el-row>
         <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="排水量" prop="drainage">
+              <el-input-number v-model="editForm.drainage" :precision="2" :min="0" style="width:100%"
+                placeholder="请输入排水量" />
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="积水量" prop="waterlogging">
-              <el-input v-model="editForm.waterlogging" placeholder="请输入积水量" />
+              <el-input-number v-model="editForm.waterlogging" :precision="2" :min="0" style="width:100%"
+                placeholder="请输入积水量" />
             </el-form-item>
           </el-col>
+        </el-row>
+        <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="积水等级" prop="level">
-              <el-input v-model="editForm.level" placeholder="请输入积水等级" />
+              <el-input-number v-model="editForm.level" :min="1" :max="5" :precision="0" style="width:100%"
+                placeholder="请输入积水等级(1-5)" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -149,15 +175,12 @@
       <!-- 地图标点区域 -->
       <div class="map-section" style="margin-top: 16px;">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: editMapTab === 'waterlogging' }"
-            @click="switchEditMapTab('waterlogging')">积水点</div>
-          <div class="map-tab" :class="{ active: editMapTab === 'drainage' }" @click="switchEditMapTab('drainage')">排水点
-          </div>
-          <div class="map-tab-action" @click="clearEditMarkers">清除所有标记</div>
+          <div class="map-tab active">位置标记</div>
+          <div class="map-tab-action" @click="clearEditMarkers">清除标记</div>
         </div>
         <div id="psfqglEditMap" class="map-container" style="height: 350px;"></div>
         <div class="marker-count">
-          已标记 {{ currentEditPoints.length }} 个{{ editMapTab === 'waterlogging' ? '积水点' : '排水点' }}
+          经度:{{ editForm.longitude || '未标记' }},纬度:{{ editForm.latitude || '未标记' }}
         </div>
       </div>
 
@@ -170,14 +193,22 @@
 </template>
 
 <script setup name="Psfqgl">
-import { ref, computed, nextTick } from 'vue'
+import { ref, computed, nextTick, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import locationIcon from '@/assets/images/location.png'
+import {
+  getPartitionPage,
+  addPartition,
+  updatePartition,
+  deletePartition,
+  batchDeletePartition
+} from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
-function createMapMarker(map, bPoint, name) {
+function createMapMarker(map, bPoint, name, bgColor) {
+  const color = bgColor || '#409eff'
   const html = `<div style="text-align:center;cursor:pointer;">
-    <div style="color:#fff;background:#409eff;border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
+    <div style="color:#fff;background:${color};border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
     <div><img src="${locationIcon}" style="width:28px;height:28px;display:block;margin:0 auto;"/></div>
   </div>`
   const label = new BMapGL.Label(html, {
@@ -193,56 +224,86 @@ function createMapMarker(map, bPoint, name) {
   return label
 }
 
+// ==================== 顶部地图 ====================
+let mainMapInstance = null
+const mainMapMarkers = ref([])
+const mapTab = ref('all')
+
+function switchMapTab(tab) {
+  mapTab.value = tab
+  renderMainMapMarkers()
+}
+
+function initMainMap() {
+  const container = document.getElementById('psfqglMainMap')
+  if (!container) return
+  try {
+    mainMapInstance = new BMapGL.Map('psfqglMainMap')
+    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    mainMapInstance.centerAndZoom(centerPoint, 12)
+    mainMapInstance.enableScrollWheelZoom(true)
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('顶部百度地图初始化失败:', e)
+  }
+}
+
+function renderMainMapMarkers() {
+  if (!mainMapInstance) return
+  // 清除旧标记
+  mainMapMarkers.value.forEach(label => {
+    mainMapInstance.removeOverlay(label)
+  })
+  mainMapMarkers.value = []
+
+  const list = tableData.value.filter(item => item.longitude && item.latitude)
+  const filtered = mapTab.value === 'all'
+    ? list
+    : list.filter(item => item.partitionType === mapTab.value)
+
+  filtered.forEach(item => {
+    const bPoint = new BMapGL.Point(item.longitude, item.latitude)
+    const color = item.partitionType === '污水分区' ? '#e6a23c' : '#409eff'
+    const label = createMapMarker(mainMapInstance, bPoint, item.name, color)
+    mainMapMarkers.value.push(label)
+  })
+}
+
 // ==================== 搜索参数 ====================
 const queryParams = ref({
   name: '',
-  type: ''
+  district: '',
+  partitionType: ''
 })
 
 // ==================== 表格数据 ====================
-let nextId = 5
-const tableData = ref([
-  {
-    id: 1, name: 'XX北路1号积水点', area: 'XX区', time: '2025-12-31',
-    drainage: 1, waterlogging: 2, level: 1,
-    waterloggingPoints: [
-      { name: '积水点1', lng: 110.393, lat: 28.452 },
-      { name: '积水点2', lng: 110.400, lat: 28.458 },
-      { name: '积水点3', lng: 110.385, lat: 28.445 }
-    ],
-    drainagePoints: [
-      { name: '排水点1', lng: 110.396, lat: 28.455 },
-      { name: '排水点2', lng: 110.390, lat: 28.448 }
-    ]
-  },
-  {
-    id: 2, name: 'XX北路2号积水点', area: 'XX区', time: '2025-12-31',
-    drainage: 1, waterlogging: 2, level: 1,
-    waterloggingPoints: [
-      { name: '积水点1', lng: 110.404, lat: 28.460 }
-    ],
-    drainagePoints: [
-      { name: '排水点1', lng: 110.398, lat: 28.456 }
-    ]
-  },
-  {
-    id: 3, name: 'XX南路1号积水点', area: 'XX区', time: '2025-12-31',
-    drainage: 2, waterlogging: 2, level: 1,
-    waterloggingPoints: [
-      { name: '积水点1', lng: 110.408, lat: 28.462 },
-      { name: '积水点2', lng: 110.412, lat: 28.448 }
-    ],
-    drainagePoints: [
-      { name: '排水点1', lng: 110.402, lat: 28.450 }
-    ]
-  },
-  {
-    id: 4, name: 'XX南路2号积水点', area: 'XX区', time: '2025-12-31',
-    drainage: 1, waterlogging: 2, level: 1,
-    waterloggingPoints: [],
-    drainagePoints: []
+const tableData = ref([])
+const total = ref(0)
+const pageNum = ref(1)
+const pageSize = ref(10)
+const loading = ref(false)
+
+// 加载分页数据
+async function loadData() {
+  loading.value = true
+  try {
+    const res = await getPartitionPage(pageNum.value, pageSize.value, queryParams.value)
+    // 兼容直接返回Page对象(无code包装)和AjaxResult包装两种格式
+    const pageData = res.code !== undefined ? res.data : res
+    tableData.value = pageData.records || []
+    total.value = pageData.total || 0
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('加载排水分区数据失败', e)
+  } finally {
+    loading.value = false
   }
-])
+}
+
+onMounted(() => {
+  loadData()
+  initMainMap()
+})
 
 // 多选
 const selectedIds = ref([])
@@ -250,35 +311,22 @@ function handleSelectionChange(selection) {
   selectedIds.value = selection.map(item => item.id)
 }
 
-// 过滤后的列表
-const filteredList = computed(() => {
-  return tableData.value.filter(item => {
-    const nameMatch = !queryParams.value.name || item.name.includes(queryParams.value.name)
-    const typeMatch = !queryParams.value.type || String(item.level) === queryParams.value.type
-    return nameMatch && typeMatch
-  })
-})
-
-// 积水等级文本
-function levelText(level) {
-  const map = { 1: 'I级', 2: 'II级', 3: 'III级', 4: 'IV级', 5: 'V级' }
-  return map[level] || '-'
-}
+// 表格数据直接用 tableData(已是分页数据)
+const filteredList = computed(() => tableData.value)
 
 // 搜索
 function handleQuery() {
-  queryParams.value = { ...queryParams.value }
+  pageNum.value = 1
+  loadData()
 }
 
 // ==================== 查看详情对话框 ====================
 const dialogVisible = ref(false)
 const currentRow = ref({})
-const viewMapTab = ref('waterlogging')
 let viewMapInstance = null
 
 function handleView(row) {
   currentRow.value = { ...row }
-  viewMapTab.value = 'waterlogging'
   dialogVisible.value = true
 }
 
@@ -301,40 +349,22 @@ function initViewMap() {
 
   try {
     viewMapInstance = new BMapGL.Map('psfqglViewMap')
-    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    const centerLng = currentRow.value.longitude || 110.393
+    const centerLat = currentRow.value.latitude || 28.452
+    const centerPoint = new BMapGL.Point(centerLng, centerLat)
     viewMapInstance.centerAndZoom(centerPoint, 15)
     viewMapInstance.enableScrollWheelZoom(true)
-    renderViewMarkers()
+
+    // 如果有坐标,显示标记
+    if (currentRow.value.longitude && currentRow.value.latitude) {
+      const bPoint = new BMapGL.Point(currentRow.value.longitude, currentRow.value.latitude)
+      createMapMarker(viewMapInstance, bPoint, currentRow.value.name)
+    }
   } catch (e) {
     console.error('百度地图初始化失败:', e)
   }
 }
 
-function renderViewMarkers() {
-  if (!viewMapInstance) return
-  viewMapInstance.clearOverlays()
-
-  const isWater = viewMapTab.value === 'waterlogging'
-  const points = isWater
-    ? (currentRow.value.waterloggingPoints || [])
-    : (currentRow.value.drainagePoints || [])
-
-  points.forEach(point => {
-    const bPoint = new BMapGL.Point(point.lng, point.lat)
-    createMapMarker(viewMapInstance, bPoint, point.name)
-  })
-
-  if (points.length > 0) {
-    const viewPoints = points.map(p => new BMapGL.Point(p.lng, p.lat))
-    viewMapInstance.setViewport(viewPoints)
-  }
-}
-
-function switchViewMapTab(tab) {
-  viewMapTab.value = tab
-  renderViewMarkers()
-}
-
 // ==================== 新增/修改对话框 ====================
 const editDialogVisible = ref(false)
 const editDialogTitle = ref('新增监测点')
@@ -344,32 +374,24 @@ const editRowId = ref(null)
 
 const editForm = ref({
   name: '',
-  area: '',
+  district: '',
+  partitionType: '',
   time: '',
   drainage: 0,
   waterlogging: 0,
-  level: 1
+  level: 1,
+  longitude: null,
+  latitude: null
 })
 
 const editRules = {
   name: [{ required: true, message: '请输入监测点名称', trigger: 'blur' }],
-  area: [{ required: true, message: '请输入行政区域', trigger: 'blur' }],
-  time: [{ required: true, message: '请选择数据时间', trigger: 'change' }],
-  level: [{ required: true, message: '请选择积水等级', trigger: 'change' }]
+  time: [{ required: true, message: '请选择数据时间', trigger: 'change' }]
 }
 
 // 编辑弹窗地图相关
-const editMapTab = ref('waterlogging')
 let editMapInstance = null
-let editWaterPoints = ref([]) // 积水点临时数据
-let editDrainagePoints = ref([]) // 排水点临时数据
-let editWaterMarkerCount = ref(0)
-let editDrainageMarkerCount = ref(0)
-
-// 当前 tab 对应的点列表
-const currentEditPoints = computed(() => {
-  return editMapTab.value === 'waterlogging' ? editWaterPoints.value : editDrainagePoints.value
-})
+let editMarkerLabel = null
 
 function handleAdd() {
   isEditMode.value = false
@@ -377,17 +399,15 @@ function handleAdd() {
   editRowId.value = null
   editForm.value = {
     name: '',
-    area: '',
+    district: '',
+    partitionType: '',
     time: '',
     drainage: 0,
     waterlogging: 0,
-    level: 1
+    level: 1,
+    longitude: null,
+    latitude: null
   }
-  editMapTab.value = 'waterlogging'
-  editWaterPoints.value = []
-  editDrainagePoints.value = []
-  editWaterMarkerCount.value = 0
-  editDrainageMarkerCount.value = 0
   editDialogVisible.value = true
 }
 
@@ -397,18 +417,15 @@ function handleEdit(row) {
   editRowId.value = row.id
   editForm.value = {
     name: row.name,
-    area: row.area,
+    district: row.district,
+    partitionType: row.partitionType,
     time: row.time,
     drainage: row.drainage,
     waterlogging: row.waterlogging,
-    level: row.level
+    level: row.level,
+    longitude: row.longitude,
+    latitude: row.latitude
   }
-  editMapTab.value = 'waterlogging'
-  // 深拷贝标记点数据
-  editWaterPoints.value = (row.waterloggingPoints || []).map(p => ({ ...p }))
-  editDrainagePoints.value = (row.drainagePoints || []).map(p => ({ ...p }))
-  editWaterMarkerCount.value = editWaterPoints.value.length
-  editDrainageMarkerCount.value = editDrainagePoints.value.length
   editDialogVisible.value = true
 }
 
@@ -417,6 +434,7 @@ function handleEditClose() {
   if (editMapInstance) {
     editMapInstance = null
   }
+  editMarkerLabel = null
 }
 
 function onEditDialogOpened() {
@@ -431,108 +449,79 @@ function initEditMap() {
 
   try {
     editMapInstance = new BMapGL.Map('psfqglEditMap')
-    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    const centerLng = editForm.value.longitude || 110.393
+    const centerLat = editForm.value.latitude || 28.452
+    const centerPoint = new BMapGL.Point(centerLng, centerLat)
     editMapInstance.centerAndZoom(centerPoint, 15)
     editMapInstance.enableScrollWheelZoom(true)
 
-    // 点击地图添加标记
+    // 如果已有坐标,显示标记
+    if (editForm.value.longitude && editForm.value.latitude) {
+      const bPoint = new BMapGL.Point(editForm.value.longitude, editForm.value.latitude)
+      editMarkerLabel = createMapMarker(editMapInstance, bPoint, editForm.value.name)
+    }
+
+    // 点击地图更新标记
     editMapInstance.addEventListener('click', function (e) {
-      addEditMarker(e.latlng)
+      editForm.value.longitude = e.latlng.lng
+      editForm.value.latitude = e.latlng.lat
+      // 清除旧标记,添加新标记
+      if (editMarkerLabel) {
+        editMapInstance.removeOverlay(editMarkerLabel)
+      }
+      const bPoint = new BMapGL.Point(e.latlng.lng, e.latlng.lat)
+      editMarkerLabel = createMapMarker(editMapInstance, bPoint, editForm.value.name)
     })
-
-    // 渲染已有标记
-    renderEditMarkers()
   } catch (e) {
     console.error('百度地图初始化失败:', e)
   }
 }
 
-function addEditMarker(point) {
-  console.log('addEditMarker called:', point.lng, point.lat)
-  const isWater = editMapTab.value === 'waterlogging'
-  const pointList = isWater ? editWaterPoints.value : editDrainagePoints.value
-  const count = isWater ? ++editWaterMarkerCount.value : ++editDrainageMarkerCount.value
-  const labelPrefix = isWater ? '积水点' : '排水点'
-
-  pointList.push({
-    name: `${labelPrefix}${count}`,
-    lng: point.lng,
-    lat: point.lat
-  })
-
-  // 统一重绘,保证地图与数据完全一致
-  renderEditMarkers(false)
-}
-
-function renderEditMarkers(shouldCenter = true) {
-  if (!editMapInstance) return
-  editMapInstance.clearOverlays()
-
-  const isWater = editMapTab.value === 'waterlogging'
-  const points = isWater ? editWaterPoints.value : editDrainagePoints.value
-  if (shouldCenter) {
-    const center = points.length > 0
-      ? new BMapGL.Point(points[0].lng, points[0].lat)
-      : new BMapGL.Point(110.393, 28.452)
-    editMapInstance.centerAndZoom(center, 15)
-  }
-
-  points.forEach((point, index) => {
-    const bPoint = new BMapGL.Point(point.lng, point.lat)
-    const label = createMapMarker(editMapInstance, bPoint, point.name)
-
-    // 右键删除标记
-    label.addEventListener('rightclick', () => {
-      const list = isWater ? editWaterPoints.value : editDrainagePoints.value
-      list.splice(index, 1)
-      renderEditMarkers(false)
-    })
-  })
-}
-
-function switchEditMapTab(tab) {
-  editMapTab.value = tab
-  renderEditMarkers()
-}
-
 function clearEditMarkers() {
-  if (editMapTab.value === 'waterlogging') {
-    editWaterPoints.value = []
-    editWaterMarkerCount.value = 0
-  } else {
-    editDrainagePoints.value = []
-    editDrainageMarkerCount.value = 0
+  if (editMapInstance && editMarkerLabel) {
+    editMapInstance.removeOverlay(editMarkerLabel)
+    editMarkerLabel = null
   }
-  renderEditMarkers()
+  editForm.value.longitude = null
+  editForm.value.latitude = null
 }
 
 function handleEditSubmit() {
-  editFormRef.value.validate(valid => {
+  editFormRef.value.validate(async valid => {
     if (!valid) return
 
     const formData = {
-      ...editForm.value,
-      waterloggingPoints: editWaterPoints.value.map(p => ({ ...p })),
-      drainagePoints: editDrainagePoints.value.map(p => ({ ...p }))
+      ...editForm.value
     }
 
-    if (isEditMode.value) {
-      // 修改
-      const index = tableData.value.findIndex(item => item.id === editRowId.value)
-      if (index !== -1) {
-        tableData.value[index] = { ...tableData.value[index], ...formData }
+    try {
+      if (isEditMode.value) {
+        formData.id = editRowId.value
+        const res = await updatePartition(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('修改成功')
+        } else {
+          ElMessage.error(res.msg || '修改失败')
+          return
+        }
+      } else {
+        const res = await addPartition(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('新增成功')
+        } else {
+          ElMessage.error(res.msg || '新增失败')
+          return
+        }
       }
-      ElMessage.success('修改成功')
-    } else {
-      // 新增
-      formData.id = nextId++
-      tableData.value.push(formData)
-      ElMessage.success('新增成功')
-    }
-
-    editDialogVisible.value = false
-    if (editMapInstance) {
-      editMapInstance = null
+      editDialogVisible.value = false
+      if (editMapInstance) {
+        editMapInstance = null
+      }
+      editMarkerLabel = null
+      loadData()
+    } catch (e) {
+      console.error('提交失败', e)
+      ElMessage.error('操作失败')
     }
   })
 }
@@ -543,12 +532,18 @@ function handleDelete(row) {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    const index = tableData.value.findIndex(item => item.id === row.id)
-    if (index !== -1) {
-      tableData.value.splice(index, 1)
+  }).then(async () => {
+    try {
+      const res = await deletePartition(row.id)
+      if (res.code === 0 || res.code === 200) {
+        ElMessage.success('删除成功')
+        loadData()
+      } else {
+        ElMessage.error(res.msg || '删除失败')
+      }
+    } catch (e) {
+      ElMessage.error('删除失败')
     }
-    ElMessage.success('删除成功')
   }).catch(() => { })
 }
 
@@ -558,10 +553,19 @@ function handleBatchDelete() {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id))
-    selectedIds.value = []
-    ElMessage.success('删除成功')
+  }).then(async () => {
+    try {
+      const res = await batchDeletePartition(selectedIds.value)
+      if (res.code === 0 || res.code === 200) {
+        selectedIds.value = []
+        ElMessage.success('删除成功')
+        loadData()
+      } else {
+        ElMessage.error(res.msg || '删除失败')
+      }
+    } catch (e) {
+      ElMessage.error('删除失败')
+    }
   }).catch(() => { })
 }
 </script>
@@ -658,4 +662,4 @@ function handleBatchDelete() {
   background: #f5f7fa;
   border-top: 1px solid #e4e7ed;
 }
-</style>
+</style>

+ 299 - 245
src/views/subSystem/drainage/jcsj/psgwgl.vue

@@ -1,13 +1,31 @@
 <template>
   <div class="app-container">
+    <!-- GIS 地图展示区 -->
+    <div class="map-section" style="margin-bottom: 16px;">
+      <div class="map-tabs">
+        <div class="map-tab" :class="{ active: mainMapTab === 'all' }" @click="switchMainMapTab('all')">全部</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'pipeline' }" @click="switchMainMapTab('pipeline')">管线</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'pipePoint' }" @click="switchMainMapTab('pipePoint')">管点</div>
+        <div class="map-tab" :class="{ active: mainMapTab === 'outlet' }" @click="switchMainMapTab('outlet')">排口</div>
+      </div>
+      <div id="psgwglMainMap" class="map-container" style="height: 350px;"></div>
+    </div>
+
     <!-- 搜索区域 -->
     <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
-      <el-form-item label="监测点名称">
+      <el-form-item label="管网名称">
         <el-input v-model="queryParams.name" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
       <el-form-item label="行政区域">
         <el-input v-model="queryParams.area" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
+      <el-form-item label="管网类型">
+        <el-select v-model="queryParams.networkType" placeholder="请选择" clearable style="width: 200px">
+          <el-option label="管线" value="管线" />
+          <el-option label="管点" value="管点" />
+          <el-option label="排口" value="排口" />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="handleQuery">搜索</el-button>
       </el-form-item>
@@ -20,13 +38,13 @@
     </div>
 
     <!-- 数据表格 -->
-    <el-table :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="监测点名称" prop="name" min-width="160" />
       <el-table-column label="行政区域" prop="area" min-width="100" />
+      <el-table-column label="管网类型" prop="networkType" min-width="100" />
       <el-table-column label="数据时间" prop="time" min-width="120" />
-      <el-table-column label="管点数量" prop="pipePointCount" min-width="80" />
-      <el-table-column label="排口数量" prop="outletCount" min-width="80" />
+      <el-table-column label="标记数量" prop="pointCount" min-width="80" />
       <el-table-column label="操作" width="180" align="center">
         <template #default="{ row }">
           <el-button link type="primary" @click="handleView(row)">查看</el-button>
@@ -36,6 +54,18 @@
       </el-table-column>
     </el-table>
 
+    <!-- 分页 -->
+    <el-pagination
+      v-model:current-page="pageNum"
+      v-model:page-size="pageSize"
+      :total="total"
+      :page-sizes="[10, 20, 50, 100]"
+      layout="total, sizes, prev, pager, next, jumper"
+      style="margin-top: 16px; justify-content: flex-end;"
+      @size-change="loadData"
+      @current-change="loadData"
+    />
+
     <!-- 查看详情对话框 -->
     <el-dialog v-model="dialogVisible" title="详情" width="700px" :before-close="handleClose" @opened="onDialogOpened">
       <div class="detail-info">
@@ -56,22 +86,22 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">数据时间:</span>
-              <span class="info-value">{{ currentRow.time }}</span>
+              <span class="info-label">管网类型:</span>
+              <span class="info-value">{{ currentRow.networkType }}</span>
             </div>
           </el-col>
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">管点数量:</span>
-              <span class="info-value">{{ (currentRow.pipePoints || []).length }}</span>
+              <span class="info-label">数据时间:</span>
+              <span class="info-value">{{ currentRow.time }}</span>
             </div>
           </el-col>
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
             <div class="info-item">
-              <span class="info-label">排口数量:</span>
-              <span class="info-value">{{ (currentRow.outletPoints || []).length }}</span>
+              <span class="info-label">标记数量:</span>
+              <span class="info-value">{{ currentRowPointCount }}</span>
             </div>
           </el-col>
         </el-row>
@@ -80,12 +110,7 @@
       <!-- 地图区域 -->
       <div class="map-section">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: viewMapTab === 'pipeline' }"
-            @click="switchViewMapTab('pipeline')">管线</div>
-          <div class="map-tab" :class="{ active: viewMapTab === 'pipePoint' }"
-            @click="switchViewMapTab('pipePoint')">管点</div>
-          <div class="map-tab" :class="{ active: viewMapTab === 'outlet' }"
-            @click="switchViewMapTab('outlet')">排口</div>
+          <div class="map-tab active">{{ currentRow.networkType || '位置标记' }}</div>
         </div>
         <div id="psgwglViewMap" class="map-container"></div>
       </div>
@@ -108,6 +133,16 @@
           </el-col>
         </el-row>
         <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="管网类型" prop="networkType">
+              <el-select v-model="editForm.networkType" placeholder="请选择管网类型" style="width:100%"
+                @change="onNetworkTypeChange">
+                <el-option label="管线" value="管线" />
+                <el-option label="管点" value="管点" />
+                <el-option label="排口" value="排口" />
+              </el-select>
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="数据时间" prop="time">
               <el-date-picker v-model="editForm.time" type="date" placeholder="请选择日期" value-format="YYYY-MM-DD"
@@ -117,13 +152,8 @@
         </el-row>
         <el-row :gutter="20">
           <el-col :span="12">
-            <el-form-item label="管点数量">
-              <el-input :model-value="editPipePoints.length" disabled />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="排口数量">
-              <el-input :model-value="editOutletPoints.length" disabled />
+            <el-form-item label="标记数量">
+              <el-input :model-value="editPoints.length" disabled />
             </el-form-item>
           </el-col>
         </el-row>
@@ -132,17 +162,12 @@
       <!-- 地图标点区域 -->
       <div class="map-section" style="margin-top: 16px;">
         <div class="map-tabs">
-          <div class="map-tab" :class="{ active: editMapTab === 'pipeline' }"
-            @click="switchEditMapTab('pipeline')">管线</div>
-          <div class="map-tab" :class="{ active: editMapTab === 'pipePoint' }"
-            @click="switchEditMapTab('pipePoint')">管点</div>
-          <div class="map-tab" :class="{ active: editMapTab === 'outlet' }"
-            @click="switchEditMapTab('outlet')">排口</div>
+          <div class="map-tab active">{{ editForm.networkType || '位置标记' }}</div>
           <div class="map-tab-action" @click="clearEditMarkers">清除所有标记</div>
         </div>
         <div id="psgwglEditMap" class="map-container" style="height: 350px;"></div>
         <div class="marker-count">
-          已标记 {{ currentEditPoints.length }} 个{{ editMapTabLabel }}
+          已标记 {{ editPoints.length }} 个{{ editForm.networkType ? editMarkerLabel : '标记' }}
         </div>
       </div>
 
@@ -155,14 +180,21 @@
 </template>
 
 <script setup name="Psgwgl">
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import locationIcon from '@/assets/images/location.png'
+import {
+  getPipeNetworkPage,
+  addDrainagePipeNetwork,
+  updateDrainagePipeNetwork,
+  deleteDrainagePipeNetwork
+} from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
-function createMapMarker(map, bPoint, name) {
+function createMapMarker(map, bPoint, name, bgColor) {
+  const color = bgColor || '#409eff'
   const html = `<div style="text-align:center;cursor:pointer;">
-    <div style="color:#fff;background:#409eff;border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
+    <div style="color:#fff;background:${color};border-radius:4px;padding:2px 6px;font-size:11px;white-space:nowrap;display:inline-block;margin-bottom:2px;">${name || ''}</div>
     <div><img src="${locationIcon}" style="width:28px;height:28px;display:block;margin:0 auto;"/></div>
   </div>`
   const label = new BMapGL.Label(html, {
@@ -178,83 +210,129 @@ function createMapMarker(map, bPoint, name) {
   return label
 }
 
+// 解析坐标数据(兼容JSON字符串和数组)
+function parsePoints(data) {
+  if (!data) return []
+  if (typeof data === 'string') {
+    try { return JSON.parse(data) } catch (e) { return [] }
+  }
+  return Array.isArray(data) ? data : []
+}
+
+// ==================== 顶部主地图 ====================
+let mainMapInstance = null
+const mainMapTab = ref('all')
+
+function switchMainMapTab(tab) {
+  mainMapTab.value = tab
+  renderMainMapMarkers()
+}
+
+function initMainMap() {
+  const container = document.getElementById('psgwglMainMap')
+  if (!container) return
+  try {
+    mainMapInstance = new BMapGL.Map('psgwglMainMap')
+    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    mainMapInstance.centerAndZoom(centerPoint, 12)
+    mainMapInstance.enableScrollWheelZoom(true)
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('顶部百度地图初始化失败:', e)
+  }
+}
+
+function renderMainMapMarkers() {
+  if (!mainMapInstance) return
+  mainMapInstance.clearOverlays()
+
+  const allPoints = []
+  const tab = mainMapTab.value
+  // 按 networkType 过滤:管线tab显示networkType='管线'的,管点tab显示'管点',排口tab显示'排口',全部显示所有
+  const networkTypeMap = { pipeline: '管线', pipePoint: '管点', outlet: '排口' }
+  const targetNetworkType = tab === 'all' ? null : networkTypeMap[tab]
+
+  tableData.value.forEach(row => {
+    if (targetNetworkType && row.networkType !== targetNetworkType) return
+    const points = parsePoints(row.points)
+    if (points.length === 0) return
+
+    if (row.networkType === '管线') {
+      // 管线模式:绘制折线 + 节点标记
+      if (points.length >= 2) {
+        const polylinePoints = points.map(p => new BMapGL.Point(p.lng, p.lat))
+        const polyline = new BMapGL.Polyline(polylinePoints, {
+          strokeColor: '#409eff',
+          strokeWeight: 4,
+          strokeOpacity: 0.8
+        })
+        mainMapInstance.addOverlay(polyline)
+      }
+      points.forEach(p => {
+        if (p.lng && p.lat) {
+          const bPoint = new BMapGL.Point(p.lng, p.lat)
+          createMapMarker(mainMapInstance, bPoint, p.name || row.name)
+          allPoints.push(bPoint)
+        }
+      })
+    } else {
+      // 管点/排口模式:只显示标记点
+      points.forEach(p => {
+        if (p.lng && p.lat) {
+          const bPoint = new BMapGL.Point(p.lng, p.lat)
+          createMapMarker(mainMapInstance, bPoint, p.name || row.name)
+          allPoints.push(bPoint)
+        }
+      })
+    }
+  })
+
+  if (allPoints.length > 0) {
+    mainMapInstance.setViewport(allPoints)
+  }
+}
+
 // ==================== 搜索参数 ====================
 const queryParams = ref({
   name: '',
-  area: ''
+  area: '',
+  networkType: ''
 })
 
 // ==================== 表格数据 ====================
-let nextId = 5
-const tableData = ref([
-  {
-    id: 1, name: '沅陵北路1号管网', area: '沅陵县', time: '2025-12-31',
-    pipelineLength: '3.2km', pipePointCount: 12, outletCount: 3,
-    pipelinePoints: [
-      { name: '管线节点1', lng: 110.393, lat: 28.452 },
-      { name: '管线节点2', lng: 110.398, lat: 28.455 },
-      { name: '管线节点3', lng: 110.402, lat: 28.450 },
-      { name: '管线节点4', lng: 110.406, lat: 28.453 }
-    ],
-    pipePoints: [
-      { name: '管点1', lng: 110.395, lat: 28.448 },
-      { name: '管点2', lng: 110.400, lat: 28.460 }
-    ],
-    outletPoints: [
-      { name: '排口1', lng: 110.390, lat: 28.445 },
-      { name: '排口2', lng: 110.408, lat: 28.458 }
-    ]
-  },
-  {
-    id: 2, name: '沅陵南路1号管网', area: '沅陵县', time: '2025-12-30',
-    pipelineLength: '2.5km', pipePointCount: 8, outletCount: 2,
-    pipelinePoints: [
-      { name: '管线节点1', lng: 110.385, lat: 28.446 },
-      { name: '管线节点2', lng: 110.390, lat: 28.444 },
-      { name: '管线节点3', lng: 110.395, lat: 28.448 }
-    ],
-    pipePoints: [
-      { name: '管点1', lng: 110.388, lat: 28.450 }
-    ],
-    outletPoints: [
-      { name: '排口1', lng: 110.392, lat: 28.442 }
-    ]
-  },
-  {
-    id: 3, name: '沅陵东路2号管网', area: '沅陵县', time: '2025-12-29',
-    pipelineLength: '4.1km', pipePointCount: 15, outletCount: 5,
-    pipelinePoints: [
-      { name: '管线节点1', lng: 110.400, lat: 28.456 },
-      { name: '管线节点2', lng: 110.405, lat: 28.458 },
-      { name: '管线节点3', lng: 110.410, lat: 28.455 },
-      { name: '管线节点4', lng: 110.412, lat: 28.460 },
-      { name: '管线节点5', lng: 110.408, lat: 28.462 }
-    ],
-    pipePoints: [
-      { name: '管点1', lng: 110.403, lat: 28.454 },
-      { name: '管点2', lng: 110.409, lat: 28.461 },
-      { name: '管点3', lng: 110.398, lat: 28.459 }
-    ],
-    outletPoints: [
-      { name: '排口1', lng: 110.413, lat: 28.461 },
-      { name: '排口2', lng: 110.396, lat: 28.457 }
-    ]
-  },
-  {
-    id: 4, name: '沅陵西路1号管网', area: '沅陵县', time: '2025-12-28',
-    pipelineLength: '1.8km', pipePointCount: 6, outletCount: 1,
-    pipelinePoints: [
-      { name: '管线节点1', lng: 110.380, lat: 28.450 },
-      { name: '管线节点2', lng: 110.385, lat: 28.453 }
-    ],
-    pipePoints: [
-      { name: '管点1', lng: 110.382, lat: 28.448 }
-    ],
-    outletPoints: [
-      { name: '排口1', lng: 110.378, lat: 28.446 }
-    ]
+const tableData = ref([])
+const total = ref(0)
+const pageNum = ref(1)
+const pageSize = ref(10)
+const loading = ref(false)
+
+// 加载分页数据
+async function loadData() {
+  loading.value = true
+  try {
+    const res = await getPipeNetworkPage(pageNum.value, pageSize.value, queryParams.value)
+    // 兼容直接返回Page对象(无code包装)和AjaxResult包装两种格式
+    const pageData = res.code !== undefined ? res.data : res
+    const records = pageData.records || []
+    // 为每条记录计算 pointCount(从 points 字段自动统计)
+    records.forEach(row => {
+      const pts = parsePoints(row.points)
+      row.pointCount = pts.length
+    })
+    tableData.value = records
+    total.value = pageData.total || 0
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('加载排水管网数据失败', e)
+  } finally {
+    loading.value = false
   }
-])
+}
+
+onMounted(() => {
+  loadData()
+  setTimeout(() => { initMainMap() }, 500)
+})
 
 // 多选
 const selectedIds = ref([])
@@ -262,29 +340,26 @@ function handleSelectionChange(selection) {
   selectedIds.value = selection.map(item => item.id)
 }
 
-// 过滤后的列表
-const filteredList = computed(() => {
-  return tableData.value.filter(item => {
-    const nameMatch = !queryParams.value.name || item.name.includes(queryParams.value.name)
-    const areaMatch = !queryParams.value.area || item.area.includes(queryParams.value.area)
-    return nameMatch && areaMatch
-  })
-})
+// 表格数据直接用 tableData(已是分页数据)
+const filteredList = computed(() => tableData.value)
 
 // 搜索
 function handleQuery() {
-  queryParams.value = { ...queryParams.value }
+  pageNum.value = 1
+  loadData()
 }
 
 // ==================== 查看详情对话框 ====================
 const dialogVisible = ref(false)
 const currentRow = ref({})
-const viewMapTab = ref('pipeline')
 let viewMapInstance = null
 
+const currentRowPointCount = computed(() => {
+  return parsePoints(currentRow.value.points).length
+})
+
 function handleView(row) {
   currentRow.value = { ...row }
-  viewMapTab.value = 'pipeline'
   dialogVisible.value = true
 }
 
@@ -316,18 +391,11 @@ function initViewMap() {
   }
 }
 
-function getViewPoints() {
-  const tab = viewMapTab.value
-  if (tab === 'pipeline') return currentRow.value.pipelinePoints || []
-  if (tab === 'pipePoint') return currentRow.value.pipePoints || []
-  return currentRow.value.outletPoints || []
-}
-
 function renderViewMarkers() {
   if (!viewMapInstance) return
   viewMapInstance.clearOverlays()
 
-  const points = getViewPoints()
+  const points = parsePoints(currentRow.value.points)
 
   points.forEach(point => {
     const bPoint = new BMapGL.Point(point.lng, point.lat)
@@ -335,7 +403,7 @@ function renderViewMarkers() {
   })
 
   // 管线模式:绘制折线
-  if (viewMapTab.value === 'pipeline' && points.length >= 2) {
+  if (currentRow.value.networkType === '管线' && points.length >= 2) {
     const polylinePoints = points.map(p => new BMapGL.Point(p.lng, p.lat))
     const polyline = new BMapGL.Polyline(polylinePoints, {
       strokeColor: '#409eff',
@@ -351,11 +419,6 @@ function renderViewMarkers() {
   }
 }
 
-function switchViewMapTab(tab) {
-  viewMapTab.value = tab
-  renderViewMarkers()
-}
-
 // ==================== 新增/修改对话框 ====================
 const editDialogVisible = ref(false)
 const editDialogTitle = ref('新增监测点')
@@ -366,41 +429,37 @@ const editRowId = ref(null)
 const editForm = ref({
   name: '',
   area: '',
+  networkType: '',
   time: '',
-  pipelineLength: '',
-  pipePointCount: '',
-  outletCount: ''
+  pointCount: 0,
+  points: []
 })
 
 const editRules = {
   name: [{ required: true, message: '请输入监测点名称', trigger: 'blur' }],
   area: [{ required: true, message: '请输入行政区域', trigger: 'blur' }],
+  networkType: [{ required: true, message: '请选择管网类型', trigger: 'change' }],
   time: [{ required: true, message: '请选择数据时间', trigger: 'change' }]
 }
 
 // 编辑弹窗地图相关
-const editMapTab = ref('pipeline')
 let editMapInstance = null
-let editPipelinePoints = ref([])
-let editPipePoints = ref([])
-let editOutletPoints = ref([])
-let editPipelineMarkerCount = ref(0)
-let editPipeMarkerCount = ref(0)
-let editOutletMarkerCount = ref(0)
-
-// tab 中文名称
-const editMapTabLabel = computed(() => {
-  const map = { pipeline: '管线节点', pipePoint: '管点', outlet: '排口' }
-  return map[editMapTab.value] || ''
-})
+let editPoints = ref([])
+let editMarkerCount = ref(0)
 
-// 当前 tab 对应的点列表
-const currentEditPoints = computed(() => {
-  if (editMapTab.value === 'pipeline') return editPipelinePoints.value
-  if (editMapTab.value === 'pipePoint') return editPipePoints.value
-  return editOutletPoints.value
+// 标记类型中文名
+const editMarkerLabel = computed(() => {
+  const map = { '管线': '管线节点', '管点': '管点', '排口': '排口' }
+  return map[editForm.value.networkType] || '标记'
 })
 
+// 管网类型变更时,清空已有标记
+function onNetworkTypeChange() {
+  editPoints.value = []
+  editMarkerCount.value = 0
+  renderEditMarkers()
+}
+
 function handleAdd() {
   isEditMode.value = false
   editDialogTitle.value = '新增监测点'
@@ -408,18 +467,13 @@ function handleAdd() {
   editForm.value = {
     name: '',
     area: '',
+    networkType: '',
     time: '',
-    pipelineLength: '',
-    pipePointCount: '',
-    outletCount: ''
+    pointCount: 0,
+    points: []
   }
-  editMapTab.value = 'pipeline'
-  editPipelinePoints.value = []
-  editPipePoints.value = []
-  editOutletPoints.value = []
-  editPipelineMarkerCount.value = 0
-  editPipeMarkerCount.value = 0
-  editOutletMarkerCount.value = 0
+  editPoints.value = []
+  editMarkerCount.value = 0
   editDialogVisible.value = true
 }
 
@@ -430,19 +484,15 @@ function handleEdit(row) {
   editForm.value = {
     name: row.name,
     area: row.area,
+    networkType: row.networkType,
     time: row.time,
-    pipelineLength: row.pipelineLength,
-    pipePointCount: row.pipePointCount,
-    outletCount: row.outletCount
+    pointCount: row.pointCount || 0,
+    points: []
   }
-  editMapTab.value = 'pipeline'
   // 深拷贝标记点数据
-  editPipelinePoints.value = (row.pipelinePoints || []).map(p => ({ ...p }))
-  editPipePoints.value = (row.pipePoints || []).map(p => ({ ...p }))
-  editOutletPoints.value = (row.outletPoints || []).map(p => ({ ...p }))
-  editPipelineMarkerCount.value = editPipelinePoints.value.length
-  editPipeMarkerCount.value = editPipePoints.value.length
-  editOutletMarkerCount.value = editOutletPoints.value.length
+  const pts = parsePoints(row.points)
+  editPoints.value = pts.map(p => ({ ...p }))
+  editMarkerCount.value = editPoints.value.length
   editDialogVisible.value = true
 }
 
@@ -481,31 +531,28 @@ function initEditMap() {
   }
 }
 
-function getCurrentEditPointList() {
-  if (editMapTab.value === 'pipeline') return editPipelinePoints.value
-  if (editMapTab.value === 'pipePoint') return editPipePoints.value
-  return editOutletPoints.value
-}
-
 function addEditMarker(point) {
-  const tab = editMapTab.value
-  let pointList, count, labelPrefix
-
-  if (tab === 'pipeline') {
-    pointList = editPipelinePoints.value
-    count = ++editPipelineMarkerCount.value
-    labelPrefix = '管线节点'
-  } else if (tab === 'pipePoint') {
-    pointList = editPipePoints.value
-    count = ++editPipeMarkerCount.value
-    labelPrefix = '管点'
-  } else {
-    pointList = editOutletPoints.value
-    count = ++editOutletMarkerCount.value
-    labelPrefix = '排口'
+  const networkType = editForm.value.networkType
+  if (!networkType) {
+    ElMessage.warning('请先选择管网类型')
+    return
   }
 
-  pointList.push({
+  // 管点和排口只能标记一个点位,再次点击则替换位置
+  if ((networkType === '管点' || networkType === '排口') && editPoints.value.length >= 1) {
+    editPoints.value[0] = {
+      name: editPoints.value[0].name,
+      lng: point.lng,
+      lat: point.lat
+    }
+    renderEditMarkers(false)
+    return
+  }
+
+  const count = ++editMarkerCount.value
+  const labelPrefix = networkType === '管线' ? '管线节点' : networkType
+
+  editPoints.value.push({
     name: `${labelPrefix}${count}`,
     lng: point.lng,
     lat: point.lat
@@ -519,7 +566,7 @@ function renderEditMarkers(shouldCenter = true) {
   if (!editMapInstance) return
   editMapInstance.clearOverlays()
 
-  const points = getCurrentEditPointList()
+  const points = editPoints.value
   if (shouldCenter) {
     const center = points.length > 0
       ? new BMapGL.Point(points[0].lng, points[0].lat)
@@ -533,14 +580,13 @@ function renderEditMarkers(shouldCenter = true) {
 
     // 右键删除标记
     label.addEventListener('rightclick', () => {
-      const list = getCurrentEditPointList()
-      list.splice(index, 1)
+      editPoints.value.splice(index, 1)
       renderEditMarkers(false)
     })
   })
 
   // 管线模式:绘制折线
-  if (editMapTab.value === 'pipeline' && points.length >= 2) {
+  if (editForm.value.networkType === '管线' && points.length >= 2) {
     const polylinePoints = points.map(p => new BMapGL.Point(p.lng, p.lat))
     const polyline = new BMapGL.Polyline(polylinePoints, {
       strokeColor: '#409eff',
@@ -551,55 +597,51 @@ function renderEditMarkers(shouldCenter = true) {
   }
 }
 
-function switchEditMapTab(tab) {
-  editMapTab.value = tab
-  renderEditMarkers()
-}
-
 function clearEditMarkers() {
-  if (editMapTab.value === 'pipeline') {
-    editPipelinePoints.value = []
-    editPipelineMarkerCount.value = 0
-  } else if (editMapTab.value === 'pipePoint') {
-    editPipePoints.value = []
-    editPipeMarkerCount.value = 0
-  } else {
-    editOutletPoints.value = []
-    editOutletMarkerCount.value = 0
-  }
+  editPoints.value = []
+  editMarkerCount.value = 0
   renderEditMarkers()
 }
 
 function handleEditSubmit() {
-  editFormRef.value.validate(valid => {
+  editFormRef.value.validate(async valid => {
     if (!valid) return
 
     const formData = {
-      ...editForm.value,
-      pipelinePoints: editPipelinePoints.value.map(p => ({ ...p })),
-      pipePoints: editPipePoints.value.map(p => ({ ...p })),
-      outletPoints: editOutletPoints.value.map(p => ({ ...p })),
-      pipePointCount: editPipePoints.value.length,
-      outletCount: editOutletPoints.value.length
+      name: editForm.value.name,
+      area: editForm.value.area,
+      networkType: editForm.value.networkType,
+      time: editForm.value.time,
+      pointCount: editPoints.value.length,
+      points: JSON.stringify(editPoints.value.map(p => ({ name: p.name, lng: p.lng, lat: p.lat })))
     }
-
-    if (isEditMode.value) {
-      // 修改
-      const index = tableData.value.findIndex(item => item.id === editRowId.value)
-      if (index !== -1) {
-        tableData.value[index] = { ...tableData.value[index], ...formData }
+    try {
+      if (isEditMode.value) {
+        formData.id = editRowId.value
+        const res = await updateDrainagePipeNetwork(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('修改成功')
+        } else {
+          ElMessage.error(res.msg || '修改失败')
+          return
+        }
+      } else {
+        const res = await addDrainagePipeNetwork(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('新增成功')
+        } else {
+          ElMessage.error(res.msg || '新增失败')
+          return
+        }
       }
-      ElMessage.success('修改成功')
-    } else {
-      // 新增
-      formData.id = nextId++
-      tableData.value.push(formData)
-      ElMessage.success('新增成功')
-    }
-
-    editDialogVisible.value = false
-    if (editMapInstance) {
-      editMapInstance = null
+      editDialogVisible.value = false
+      if (editMapInstance) {
+        editMapInstance = null
+      }
+      loadData()
+    } catch (e) {
+      console.error('提交失败', e)
+      ElMessage.error('操作失败')
     }
   })
 }
@@ -610,13 +652,19 @@ function handleDelete(row) {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    const index = tableData.value.findIndex(item => item.id === row.id)
-    if (index !== -1) {
-      tableData.value.splice(index, 1)
+  }).then(async () => {
+    try {
+      const res = await deleteDrainagePipeNetwork(row.id)
+      if (res.code === 0 || res.code === 200) {
+        ElMessage.success('删除成功')
+        loadData()
+      } else {
+        ElMessage.error(res.msg || '删除失败')
+      }
+    } catch (e) {
+      ElMessage.error('删除失败')
     }
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).catch(() => {})
 }
 
 function handleBatchDelete() {
@@ -625,11 +673,17 @@ function handleBatchDelete() {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id))
-    selectedIds.value = []
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).then(async () => {
+    // 排水管网暂无批量删除接口,逐条删除
+    try {
+      await Promise.all(selectedIds.value.map(id => deleteDrainagePipeNetwork(id)))
+      selectedIds.value = []
+      ElMessage.success('删除成功')
+      loadData()
+    } catch (e) {
+      ElMessage.error('删除失败')
+    }
+  }).catch(() => {})
 }
 </script>
 

+ 175 - 80
src/views/subSystem/drainage/jcsj/yjsdgl.vue

@@ -1,8 +1,16 @@
 <template>
   <div class="app-container">
+    <!-- GIS 地图展示区 -->
+    <div class="map-section" style="margin-bottom: 16px;">
+      <div class="map-tabs">
+        <div class="map-tab active">易积水点分布</div>
+      </div>
+      <div id="yjsdglMainMap" class="map-container" style="height: 350px;"></div>
+    </div>
+
     <!-- 搜索区域 -->
     <el-form :model="queryParams" ref="queryRef" :inline="true" class="search-form">
-      <el-form-item label="监测点名称">
+      <el-form-item label="点名称">
         <el-input v-model="queryParams.name" placeholder="请输入" clearable style="width: 200px" />
       </el-form-item>
       <el-form-item label="行政区域">
@@ -20,7 +28,7 @@
     </div>
 
     <!-- 数据表格 -->
-    <el-table :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="filteredList" border style="width: 100%" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="监测点名称" prop="name" min-width="160" />
       <el-table-column label="行政区域" prop="area" min-width="100" />
@@ -35,6 +43,18 @@
       </el-table-column>
     </el-table>
 
+    <!-- 分页 -->
+    <el-pagination
+      v-model:current-page="pageNum"
+      v-model:page-size="pageSize"
+      :total="total"
+      :page-sizes="[10, 20, 50, 100]"
+      layout="total, sizes, prev, pager, next, jumper"
+      style="margin-top: 16px; justify-content: flex-end;"
+      @size-change="loadData"
+      @current-change="loadData"
+    />
+
     <!-- 查看详情对话框 -->
     <el-dialog v-model="dialogVisible" title="详情" width="700px" :before-close="handleClose" @opened="onDialogOpened">
       <div class="detail-info">
@@ -126,9 +146,15 @@
 </template>
 
 <script setup name="Yjsdgl">
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import locationIcon from '@/assets/images/location.png'
+import {
+  getWaterloggingPage,
+  addWaterlogging,
+  updateWaterlogging,
+  deleteWaterlogging
+} from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
 function createMapMarker(map, bPoint, name) {
@@ -156,44 +182,84 @@ const queryParams = ref({
 })
 
 // ==================== 表格数据 ====================
-let nextId = 5
-const tableData = ref([
-  {
-    id: 1, name: '沅陵北路1号易积水点', area: '沅陵县', time: '2025-12-31',
-    waterloggingCount: 3,
-    waterloggingPoints: [
-      { name: '易积水点1', lng: 110.393, lat: 28.452 },
-      { name: '易积水点2', lng: 110.398, lat: 28.455 },
-      { name: '易积水点3', lng: 110.402, lat: 28.450 }
-    ]
-  },
-  {
-    id: 2, name: '沅陵南路2号易积水点', area: '沅陵县', time: '2025-12-30',
-    waterloggingCount: 2,
-    waterloggingPoints: [
-      { name: '易积水点1', lng: 110.385, lat: 28.446 },
-      { name: '易积水点2', lng: 110.390, lat: 28.444 }
-    ]
-  },
-  {
-    id: 3, name: '沅陵东路3号易积水点', area: '沅陵县', time: '2025-12-29',
-    waterloggingCount: 4,
-    waterloggingPoints: [
-      { name: '易积水点1', lng: 110.400, lat: 28.456 },
-      { name: '易积水点2', lng: 110.405, lat: 28.458 },
-      { name: '易积水点3', lng: 110.403, lat: 28.454 },
-      { name: '易积水点4', lng: 110.409, lat: 28.461 }
-    ]
-  },
-  {
-    id: 4, name: '沅陵西路4号易积水点', area: '沅陵县', time: '2025-12-28',
-    waterloggingCount: 2,
-    waterloggingPoints: [
-      { name: '易积水点1', lng: 110.380, lat: 28.450 },
-      { name: '易积水点2', lng: 110.382, lat: 28.448 }
-    ]
+const tableData = ref([])
+const total = ref(0)
+const pageNum = ref(1)
+const pageSize = ref(10)
+const loading = ref(false)
+
+// 加载分页数据
+async function loadData() {
+  loading.value = true
+  try {
+    const res = await getWaterloggingPage(pageNum.value, pageSize.value, queryParams.value)
+    // 兼容直接返回Page对象(无code包装)和AjaxResult包装两种格式
+    const pageData = res.code !== undefined ? res.data : res
+    tableData.value = pageData.records || []
+    total.value = pageData.total || 0
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('加载易积水点数据失败', e)
+  } finally {
+    loading.value = false
+  }
+}
+
+onMounted(() => {
+  loadData()
+  setTimeout(() => { initMainMap() }, 500)
+})
+
+// ==================== 顶部主地图 ====================
+let mainMapInstance = null
+
+function initMainMap() {
+  const container = document.getElementById('yjsdglMainMap')
+  if (!container) return
+  try {
+    mainMapInstance = new BMapGL.Map('yjsdglMainMap')
+    const centerPoint = new BMapGL.Point(110.393, 28.452)
+    mainMapInstance.centerAndZoom(centerPoint, 12)
+    mainMapInstance.enableScrollWheelZoom(true)
+    renderMainMapMarkers()
+  } catch (e) {
+    console.error('百度地图初始化失败:', e)
   }
-])
+}
+
+function renderMainMapMarkers() {
+  if (!mainMapInstance) return
+  mainMapInstance.clearOverlays()
+
+  const allPoints = []
+  tableData.value.forEach(row => {
+    const points = row.waterloggingPoints || []
+    if (typeof points === 'string') {
+      try {
+        const parsed = JSON.parse(points)
+        parsed.forEach(p => {
+          if (p.lng && p.lat) {
+            const bPoint = new BMapGL.Point(p.lng, p.lat)
+            createMapMarker(mainMapInstance, bPoint, p.name || row.name)
+            allPoints.push(bPoint)
+          }
+        })
+      } catch (e) {}
+    } else if (Array.isArray(points)) {
+      points.forEach(p => {
+        if (p.lng && p.lat) {
+          const bPoint = new BMapGL.Point(p.lng, p.lat)
+          createMapMarker(mainMapInstance, bPoint, p.name || row.name)
+          allPoints.push(bPoint)
+        }
+      })
+    }
+  })
+
+  if (allPoints.length > 0) {
+    mainMapInstance.setViewport(allPoints)
+  }
+}
 
 // 多选
 const selectedIds = ref([])
@@ -201,18 +267,13 @@ function handleSelectionChange(selection) {
   selectedIds.value = selection.map(item => item.id)
 }
 
-// 过滤后的列表
-const filteredList = computed(() => {
-  return tableData.value.filter(item => {
-    const nameMatch = !queryParams.value.name || item.name.includes(queryParams.value.name)
-    const areaMatch = !queryParams.value.area || item.area.includes(queryParams.value.area)
-    return nameMatch && areaMatch
-  })
-})
+// 表格数据直接用 tableData(已是分页数据)
+const filteredList = computed(() => tableData.value)
 
 // 搜索
 function handleQuery() {
-  queryParams.value = { ...queryParams.value }
+  pageNum.value = 1
+  loadData()
 }
 
 // ==================== 查看详情对话框 ====================
@@ -359,6 +420,17 @@ function initEditMap() {
 }
 
 function addEditMarker(point) {
+  // 只能标记一个点位,再次点击重新定位
+  if (editWaterloggingPoints.value.length >= 1) {
+    editWaterloggingPoints.value[0] = {
+      name: editWaterloggingPoints.value[0].name,
+      lng: point.lng,
+      lat: point.lat
+    }
+    renderEditMarkers(false)
+    return
+  }
+
   const count = ++editWaterloggingMarkerCount.value
   editWaterloggingPoints.value.push({
     name: `易积水点${count}`,
@@ -401,32 +473,44 @@ function clearEditMarkers() {
 }
 
 function handleEditSubmit() {
-  editFormRef.value.validate(valid => {
+  editFormRef.value.validate(async valid => {
     if (!valid) return
 
     const formData = {
-      ...editForm.value,
-      waterloggingPoints: editWaterloggingPoints.value.map(p => ({ ...p })),
-      waterloggingCount: editWaterloggingPoints.value.length
+      name: editForm.value.name,
+      area: editForm.value.area,
+      time: editForm.value.time,
+      waterloggingCount: editWaterloggingPoints.value.length,
+      waterloggingPoints: JSON.stringify(editWaterloggingPoints.value.map(p => ({ name: p.name, lng: p.lng, lat: p.lat })))
     }
 
-    if (isEditMode.value) {
-      // 修改
-      const index = tableData.value.findIndex(item => item.id === editRowId.value)
-      if (index !== -1) {
-        tableData.value[index] = { ...tableData.value[index], ...formData }
+    try {
+      if (isEditMode.value) {
+        formData.id = editRowId.value
+        const res = await updateWaterlogging(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('修改成功')
+        } else {
+          ElMessage.error(res.msg || '修改失败')
+          return
+        }
+      } else {
+        const res = await addWaterlogging(formData)
+        if (res.code === 0 || res.code === 200) {
+          ElMessage.success('新增成功')
+        } else {
+          ElMessage.error(res.msg || '新增失败')
+          return
+        }
       }
-      ElMessage.success('修改成功')
-    } else {
-      // 新增
-      formData.id = nextId++
-      tableData.value.push(formData)
-      ElMessage.success('新增成功')
-    }
-
-    editDialogVisible.value = false
-    if (editMapInstance) {
-      editMapInstance = null
+      editDialogVisible.value = false
+      if (editMapInstance) {
+        editMapInstance = null
+      }
+      loadData()
+    } catch (e) {
+      console.error('提交失败', e)
+      ElMessage.error('操作失败')
     }
   })
 }
@@ -437,13 +521,19 @@ function handleDelete(row) {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    const index = tableData.value.findIndex(item => item.id === row.id)
-    if (index !== -1) {
-      tableData.value.splice(index, 1)
+  }).then(async () => {
+    try {
+      const res = await deleteWaterlogging(row.id)
+      if (res.code === 0 || res.code === 200) {
+        ElMessage.success('删除成功')
+        loadData()
+      } else {
+        ElMessage.error(res.msg || '删除失败')
+      }
+    } catch (e) {
+      ElMessage.error('删除失败')
     }
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).catch(() => {})
 }
 
 function handleBatchDelete() {
@@ -452,11 +542,16 @@ function handleBatchDelete() {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    tableData.value = tableData.value.filter(item => !selectedIds.value.includes(item.id))
-    selectedIds.value = []
-    ElMessage.success('删除成功')
-  }).catch(() => { })
+  }).then(async () => {
+    try {
+      await Promise.all(selectedIds.value.map(id => deleteWaterlogging(id)))
+      selectedIds.value = []
+      ElMessage.success('删除成功')
+      loadData()
+    } catch (e) {
+      ElMessage.error('删除失败')
+    }
+  }).catch(() => {})
 }
 </script>