LAPTOP-JI2IUVG1\26646 hai 1 mes
pai
achega
fc31add029

+ 40 - 2
src/api/drainage.js

@@ -66,8 +66,33 @@ export function deleteWaterlogging(id) {
 }
 
 // ============ 监测设备管理 ============
-export function getEquipmentPage(pageNum, pageSize, params) {
-  return request({ url: '/api/drainage/equipment/base/page', method: 'get', params: { pageNum, pageSize, ...params } })
+let drainageEquipmentTypeIdPromise = null
+
+async function getDrainageEquipmentTypeId() {
+  if (!drainageEquipmentTypeIdPromise) {
+    drainageEquipmentTypeIdPromise = getEquipmentTypeList()
+      .then(res => {
+        const list = (res && res.code !== undefined ? res.data : res) || []
+        const drainageParent = Array.isArray(list)
+          ? list.find(item => item.typeId === 'drainage' && String(item.parentTypeId) === '0')
+          : null
+        return drainageParent && drainageParent.id ? String(drainageParent.id) : 'drainage'
+      })
+      .catch(error => {
+        drainageEquipmentTypeIdPromise = null
+        throw error
+      })
+  }
+  return drainageEquipmentTypeIdPromise
+}
+
+export async function getEquipmentPage(pageNum, pageSize, params = {}) {
+  const requestParams = { ...params }
+  // 后端分页接口按 equipment_type.id 查询,兼容页面使用稳定业务编码 drainage。
+  if (requestParams.equipmentTypeId === 'drainage') {
+    requestParams.equipmentTypeId = await getDrainageEquipmentTypeId()
+  }
+  return request({ url: '/api/drainage/equipment/base/page', method: 'get', params: { pageNum, pageSize, ...requestParams } })
 }
 export function getEquipmentById(id) {
   return request({ url: '/api/drainage/equipment/base/' + id, method: 'get', headers: { 'X-Silent-Error': 'true' } })
@@ -210,6 +235,19 @@ export function getPipeNetworkBoundEquipmentIds(excludeId) {
   return request({ url: '/api/drainage/pipeNetwork/boundEquipmentIds', method: 'get', params, headers: { 'X-Silent-Error': 'true' } })
 }
 
+// 查询排水基础数据中已被占用的设备(跨分区、管网、工程设施、易积水点)
+export function getDrainageBoundEquipmentIds(excludeType, excludeId) {
+  const params = {}
+  if (excludeType) params.excludeType = excludeType
+  if (excludeId) params.excludeId = excludeId
+  return request({
+    url: '/api/drainage/equipment/boundEquipmentIds',
+    method: 'get',
+    params,
+    headers: { 'X-Silent-Error': 'true' }
+  })
+}
+
 // 排水管网关联设备
 export function bindPipeNetworkEquipment(data) {
   return request({ url: '/api/drainage/pipeNetwork/bindEquipment', method: 'post', data })

+ 37 - 2
src/views/subSystem/drainage/jcsj/gcssgl.vue

@@ -202,12 +202,22 @@
       <el-table v-loading="bindLoading" :data="bindTableData" border row-key="equipmentId" ref="bindTableRef">
         <el-table-column label="选择" width="55" align="center">
           <template #default="{ row }">
-            <el-radio v-model="selectedEquipmentId" :label="row.equipmentId">&nbsp;</el-radio>
+            <el-radio v-model="selectedEquipmentId" :label="row.equipmentId"
+              :disabled="isEquipmentBound(row)">&nbsp;</el-radio>
           </template>
         </el-table-column>
         <el-table-column label="设备名称" prop="equipmentName" min-width="120" />
         <el-table-column label="设备编号" prop="equipmentCode" min-width="120" />
         <el-table-column label="设备类型" prop="equipmentTypeName" min-width="100" />
+        <el-table-column label="关联状态" min-width="180">
+          <template #default="{ row }">
+            <span v-if="String(selectedEquipmentId) === String(row.equipmentId)" style="color: #67c23a;">当前选择</span>
+            <span v-else-if="boundEquipmentMap[String(row.equipmentId)]" style="color: #e6a23c;">
+              已关联:{{ boundEquipmentMap[String(row.equipmentId)] }}
+            </span>
+            <span v-else>未关联</span>
+          </template>
+        </el-table-column>
       </el-table>
       <el-pagination v-model:current-page="bindPageNum" v-model:page-size="bindPageSize" :total="bindTotal"
         :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper"
@@ -268,6 +278,7 @@ import {
   getEquipmentPage,
   getEquipmentById,
   bindFacilityEquipment,
+  getDrainageBoundEquipmentIds,
   getPumpStationPage,
   getPumpStationById,
   bindPumpStation
@@ -752,6 +763,7 @@ const bindQueryParams = ref({ equipmentName: '', equipmentTypeId: 'drainage' })
 const selectedEquipmentId = ref('')
 const currentPartitionId = ref('')
 const bindTableRef = ref(null)
+const boundEquipmentMap = ref({})
 
 function handleBind(row) {
   // 泵站类型走泵站弹框
@@ -789,11 +801,28 @@ function handleBindQuery() {
 async function loadBindData() {
   bindLoading.value = true
   try {
-    const res = await getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value)
+    const [equipmentResult, boundResult] = await Promise.allSettled([
+      getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value),
+      getDrainageBoundEquipmentIds('facility', currentPartitionId.value)
+    ])
+    if (equipmentResult.status === 'rejected') {
+      throw equipmentResult.reason
+    }
+    const res = equipmentResult.value
     const pageData = res.code !== undefined ? res.data : res
     bindTableData.value = pageData.records || []
     bindTotal.value = pageData.total || 0
+    if (boundResult.status === 'fulfilled') {
+      const boundRes = boundResult.value
+      const boundData = boundRes.code !== undefined ? boundRes.data : boundRes
+      boundEquipmentMap.value = boundData && typeof boundData === 'object' ? boundData : {}
+    } else {
+      boundEquipmentMap.value = {}
+      console.warn('加载设备关联状态失败,设备列表仍正常显示', boundResult.reason)
+    }
   } catch (e) {
+    bindTableData.value = []
+    bindTotal.value = 0
     console.error('加载设备列表失败', e)
   } finally {
     bindLoading.value = false
@@ -804,6 +833,12 @@ function closeBindDialog() {
   bindDialogVisible.value = false
   bindTableData.value = []
   selectedEquipmentId.value = ''
+  boundEquipmentMap.value = {}
+}
+
+function isEquipmentBound(row) {
+  const id = String(row.equipmentId)
+  return Boolean(boundEquipmentMap.value[id]) && String(selectedEquipmentId.value) !== id
 }
 
 async function submitBind() {

+ 38 - 3
src/views/subSystem/drainage/jcsj/psfqgl.vue

@@ -228,12 +228,21 @@
         <el-table-column label="选择" width="55" align="center">
           <template #default="{ row }">
             <el-checkbox :model-value="selectedEquipmentIds.includes(String(row.equipmentId))"
-              @change="toggleEquipment(row, $event)" />
+              :disabled="isEquipmentBound(row)" @change="toggleEquipment(row, $event)" />
           </template>
         </el-table-column>
         <el-table-column label="设备名称" prop="equipmentName" min-width="160" />
         <el-table-column label="设备编号" prop="equipmentCode" min-width="140" />
         <el-table-column label="设备类型" prop="equipmentTypeName" min-width="120" />
+        <el-table-column label="关联状态" min-width="180">
+          <template #default="{ row }">
+            <span v-if="selectedEquipmentIds.includes(String(row.equipmentId))" style="color: #67c23a;">当前选择</span>
+            <span v-else-if="boundEquipmentMap[String(row.equipmentId)]" style="color: #e6a23c;">
+              已关联:{{ boundEquipmentMap[String(row.equipmentId)] }}
+            </span>
+            <span v-else>未关联</span>
+          </template>
+        </el-table-column>
       </el-table>
 
       <el-pagination v-model:current-page="bindPageNum" v-model:page-size="bindPageSize" :total="bindTotal"
@@ -260,7 +269,8 @@ import {
   batchDeletePartition,
   getEquipmentPage,
   getEquipmentById,
-  bindPartitionEquipment
+  bindPartitionEquipment,
+  getDrainageBoundEquipmentIds
 } from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
@@ -801,6 +811,7 @@ const bindPageNum = ref(1)
 const bindPageSize = ref(10)
 const bindLoading = ref(false)
 const selectedEquipmentIds = ref([])
+const boundEquipmentMap = ref({})
 async function handleBind(row) {
   currentPartitionId.value = row.id
   bindDialogVisible.value = true
@@ -822,11 +833,28 @@ function handleBindQuery() {
 async function loadBindData() {
   bindLoading.value = true
   try {
-    const res = await getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value)
+    const [equipmentResult, boundResult] = await Promise.allSettled([
+      getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value),
+      getDrainageBoundEquipmentIds('partition', currentPartitionId.value)
+    ])
+    if (equipmentResult.status === 'rejected') {
+      throw equipmentResult.reason
+    }
+    const res = equipmentResult.value
     const pageData = res.code !== undefined ? res.data : res
     bindTableData.value = pageData.records || []
     bindTotal.value = pageData.total || 0
+    if (boundResult.status === 'fulfilled') {
+      const boundRes = boundResult.value
+      const boundData = boundRes.code !== undefined ? boundRes.data : boundRes
+      boundEquipmentMap.value = boundData && typeof boundData === 'object' ? boundData : {}
+    } else {
+      boundEquipmentMap.value = {}
+      console.warn('加载设备关联状态失败,设备列表仍正常显示', boundResult.reason)
+    }
   } catch (e) {
+    bindTableData.value = []
+    bindTotal.value = 0
     console.error('加载设备列表失败', e)
   } finally {
     bindLoading.value = false
@@ -837,10 +865,17 @@ function closeBindDialog() {
   bindDialogVisible.value = false
   currentPartitionId.value = null
   selectedEquipmentIds.value = []
+  boundEquipmentMap.value = {}
+}
+
+function isEquipmentBound(row) {
+  const id = String(row.equipmentId)
+  return Boolean(boundEquipmentMap.value[id]) && !selectedEquipmentIds.value.includes(id)
 }
 
 function toggleEquipment(row, checked) {
   const id = String(row.equipmentId)
+  if (isEquipmentBound(row)) return
   const ids = new Set(selectedEquipmentIds.value)
   if (checked) ids.add(id)
   else ids.delete(id)

+ 28 - 5
src/views/subSystem/drainage/jcsj/psgwgl.vue

@@ -211,6 +211,15 @@
         <el-table-column label="设备编号" prop="equipmentCode" min-width="120" />
         <el-table-column label="设备类型" prop="equipmentTypeName" min-width="100" />
         <el-table-column label="安装位置" prop="installLocation" min-width="120" />
+        <el-table-column label="关联状态" min-width="180">
+          <template #default="{ row }">
+            <span v-if="selectedEquipmentIds.includes(String(row.equipmentId))" style="color: #67c23a;">当前选择</span>
+            <span v-else-if="boundEquipmentMap[String(row.equipmentId)]" style="color: #e6a23c;">
+              已关联:{{ boundEquipmentMap[String(row.equipmentId)] }}
+            </span>
+            <span v-else>未关联</span>
+          </template>
+        </el-table-column>
       </el-table>
       <el-pagination v-model:current-page="bindPageNum" v-model:page-size="bindPageSize" :total="bindTotal"
         :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper"
@@ -235,7 +244,7 @@ import {
   getEquipmentPage,
   getEquipmentById,
   bindPipeNetworkEquipment,
-  getPipeNetworkBoundEquipmentIds
+  getDrainageBoundEquipmentIds
 } from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
@@ -808,14 +817,28 @@ function handleBindQuery() {
 async function loadBindData() {
   bindLoading.value = true
   try {
-    const res = await getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value)
+    const [equipmentResult, boundResult] = await Promise.allSettled([
+      getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value),
+      getDrainageBoundEquipmentIds('pipeNetwork', currentPartitionId.value)
+    ])
+    if (equipmentResult.status === 'rejected') {
+      throw equipmentResult.reason
+    }
+    const res = equipmentResult.value
     const pageData = res.code !== undefined ? res.data : res
     bindTableData.value = pageData.records || []
     bindTotal.value = pageData.total || 0
-    const boundRes = await getPipeNetworkBoundEquipmentIds(currentPartitionId.value)
-    const boundData = boundRes.code !== undefined ? boundRes.data : boundRes
-    boundEquipmentMap.value = boundData && typeof boundData === 'object' ? boundData : {}
+    if (boundResult.status === 'fulfilled') {
+      const boundRes = boundResult.value
+      const boundData = boundRes.code !== undefined ? boundRes.data : boundRes
+      boundEquipmentMap.value = boundData && typeof boundData === 'object' ? boundData : {}
+    } else {
+      boundEquipmentMap.value = {}
+      console.warn('加载设备关联状态失败,设备列表仍正常显示', boundResult.reason)
+    }
   } catch (e) {
+    bindTableData.value = []
+    bindTotal.value = 0
     console.error('加载设备列表失败', e)
   } finally {
     bindLoading.value = false

+ 10 - 3
src/views/subSystem/drainage/jcsj/sbjcgl.vue

@@ -356,7 +356,7 @@ function statusTagType(val) {
 // ==================== 搜索参数 ====================
 const queryParams = ref({
   equipmentName: '',
-  equipmentTypeId: 'drainage',
+  equipmentTypeId: '',
   currentStatus: '',
   pageNum: 1,
   pageSize: 10
@@ -400,8 +400,8 @@ function handlePageChange() {
   loadData()
 }
 
-onMounted(() => {
-  loadTypeList()
+onMounted(async () => {
+  await loadTypeList()
   loadData()
 })
 
@@ -409,6 +409,11 @@ async function loadTypeList() {
   try {
     const res = await getEquipmentTypeList()
     typeList.value = (res.code !== undefined ? res.data : res) || []
+    // 分页接口要求传 equipment_type.id,不能传业务编码 drainage。
+    const drainageParent = typeList.value.find(item =>
+      item.typeId === 'drainage' && String(item.parentTypeId) === '0'
+    )
+    queryParams.value.equipmentTypeId = drainageParent ? String(drainageParent.id) : ''
   } catch (error) {
     console.error('加载设备类型失败', error)
     ElMessage.error('加载设备类型失败')
@@ -619,6 +624,8 @@ function handleEditSubmit() {
             }
           }
           ElMessage.success('新增成功')
+          // 新增记录按创建时间倒序显示,回到第一页后才能立即看到。
+          queryParams.value.pageNum = 1
         } else {
           ElMessage.error(res.msg || '新增失败')
           return

+ 40 - 5
src/views/subSystem/drainage/jcsj/yjsdgl.vue

@@ -210,11 +210,21 @@
       </el-form>
       <el-table v-loading="bindLoading" :data="bindTableData" border row-key="equipmentId"
         @selection-change="handleBindSelectionChange" ref="bindTableRef">
-        <el-table-column type="selection" width="55" align="center" :reserve-selection="true" />
+        <el-table-column type="selection" width="55" align="center" :reserve-selection="true"
+          :selectable="isEquipmentSelectable" />
         <el-table-column label="设备名称" prop="equipmentName" min-width="120" />
         <el-table-column label="设备编号" prop="equipmentCode" min-width="120" />
         <el-table-column label="设备类型" prop="equipmentTypeName" min-width="100" />
         <el-table-column label="安装位置" prop="installLocation" min-width="120" />
+        <el-table-column label="关联状态" min-width="180">
+          <template #default="{ row }">
+            <span v-if="selectedEquipmentIds.includes(String(row.equipmentId))" style="color: #67c23a;">当前选择</span>
+            <span v-else-if="boundEquipmentMap[String(row.equipmentId)]" style="color: #e6a23c;">
+              已关联:{{ boundEquipmentMap[String(row.equipmentId)] }}
+            </span>
+            <span v-else>未关联</span>
+          </template>
+        </el-table-column>
       </el-table>
       <el-pagination v-model:current-page="bindPageNum" v-model:page-size="bindPageSize" :total="bindTotal"
         :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper"
@@ -238,7 +248,8 @@ import {
   deleteWaterlogging,
   getEquipmentPage,
   getEquipmentById,
-  bindWaterloggingEquipment
+  bindWaterloggingEquipment,
+  getDrainageBoundEquipmentIds
 } from '@/api/drainage'
 
 // 地图标记创建(用Label+img代替Marker)
@@ -722,6 +733,7 @@ const bindQueryParams = ref({ equipmentName: '', equipmentTypeId: 'drainage' })
 const selectedEquipmentIds = ref([])
 const currentPartitionId = ref('')
 const bindTableRef = ref(null)
+const boundEquipmentMap = ref({})
 
 function handleBind(row) {
   currentPartitionId.value = row.id
@@ -729,7 +741,7 @@ function handleBind(row) {
   bindPageNum.value = 1
   bindQueryParams.value.equipmentName = ''
   if (row.equipmentId) {
-    selectedEquipmentIds.value = row.equipmentId.split(',')
+    selectedEquipmentIds.value = row.equipmentId.split(',').map(id => id.trim()).filter(Boolean)
   } else {
     selectedEquipmentIds.value = []
   }
@@ -746,10 +758,25 @@ function handleBindQuery() {
 async function loadBindData() {
   bindLoading.value = true
   try {
-    const res = await getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value)
+    const [equipmentResult, boundResult] = await Promise.allSettled([
+      getEquipmentPage(bindPageNum.value, bindPageSize.value, bindQueryParams.value),
+      getDrainageBoundEquipmentIds('waterlogging', currentPartitionId.value)
+    ])
+    if (equipmentResult.status === 'rejected') {
+      throw equipmentResult.reason
+    }
+    const res = equipmentResult.value
     const pageData = res.code !== undefined ? res.data : res
     bindTableData.value = pageData.records || []
     bindTotal.value = pageData.total || 0
+    if (boundResult.status === 'fulfilled') {
+      const boundRes = boundResult.value
+      const boundData = boundRes.code !== undefined ? boundRes.data : boundRes
+      boundEquipmentMap.value = boundData && typeof boundData === 'object' ? boundData : {}
+    } else {
+      boundEquipmentMap.value = {}
+      console.warn('加载设备关联状态失败,设备列表仍正常显示', boundResult.reason)
+    }
     await nextTick()
     if (selectedEquipmentIds.value.length > 0 && bindTableRef.value) {
       bindTableData.value.forEach(row => {
@@ -759,6 +786,8 @@ async function loadBindData() {
       })
     }
   } catch (e) {
+    bindTableData.value = []
+    bindTotal.value = 0
     console.error('加载设备列表失败', e)
   } finally {
     bindLoading.value = false
@@ -766,13 +795,19 @@ async function loadBindData() {
 }
 
 function handleBindSelectionChange(selection) {
-  selectedEquipmentIds.value = selection.map(item => item.equipmentId)
+  selectedEquipmentIds.value = selection.map(item => String(item.equipmentId))
+}
+
+function isEquipmentSelectable(row) {
+  const id = String(row.equipmentId)
+  return !boundEquipmentMap.value[id] || selectedEquipmentIds.value.includes(id)
 }
 
 function closeBindDialog() {
   bindDialogVisible.value = false
   bindTableData.value = []
   selectedEquipmentIds.value = []
+  boundEquipmentMap.value = {}
 }
 
 async function submitBind() {