Forráskód Böngészése

fix:燃气管网bug修复

null 2 hete
szülő
commit
0e04a8bc92

+ 6 - 0
src/api/pipeNetwork/basic.js

@@ -105,6 +105,12 @@ export function deleteEquipment(id) {
 export function getEquipmentTypeList() {
   return request({ url: '/EquipmentType/getList', method: 'get' })
 }
+export function getEquipmentByTopLevelType(typeName) {
+  return request({ url: '/EquipmentBase/findByTopLevelType', method: 'get', params: { typeName } })
+}
+export function getGasDashboardSummary() {
+  return request({ url: '/api/gas-dashboard/summary', method: 'get' })
+}
 export function getEquipmentStatus(equipmentId) {
   return request({ url: '/api/equipment/status/' + equipmentId, method: 'get' })
 }

+ 50 - 83
src/views/subSystem/basic/GisDashboard.vue

@@ -147,6 +147,7 @@ import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch }
 import { FullScreen, Location, MapLocation, Minus, Plus, RefreshRight, Search } from '@element-plus/icons-vue'
 import { ElMessage } from 'element-plus'
 import { convertCoord } from '@/utils/coordTransform'
+import { getPipeNetworkOptions, getGasPipePointPage, getManholeList } from '@/api/pipeNetwork/basic'
 
 const centerPoint = { lng: 110.386, lat: 28.445 }
 
@@ -180,87 +181,52 @@ const boundaryPoints = [
 
 const pipelineData = [
   {
-    id: 'pipe-high-01',
-    level: 'high',
-    name: '燃气1',
-    code: 'GX-HP-001',
-    length: 4.1,
-    material: 'L290N 无缝钢管',
-    diameter: 'DN300',
-    pressure: '高压A (4.0MPa)',
-    road: '燃气1主干线',
-    status: '运行正常',
-    layingMethod: '直埋敷设',
-    depth: '1.8m',
-    commissioningDate: '2026-06',
-    points: [
-      { lng: 110.404947, lat: 28.433419 },
-      { lng: 110.404836, lat: 28.433429 },
-      { lng: 110.403275, lat: 28.433571 },
-      { lng: 110.401084, lat: 28.433876 },
-      { lng: 110.399601, lat: 28.433876 },
-      { lng: 110.398112, lat: 28.433979 },
-      { lng: 110.396717, lat: 28.434314 },
-      { lng: 110.394299, lat: 28.434538 },
-      { lng: 110.394352, lat: 28.434887 },
-      { lng: 110.391969, lat: 28.434985 },
-      { lng: 110.384374, lat: 28.435695 },
-      { lng: 110.381418, lat: 28.43559 },
-      { lng: 110.377993, lat: 28.436193 },
-      { lng: 110.376062, lat: 28.436385 },
-      { lng: 110.374231, lat: 28.43655 },
-      { lng: 110.372584, lat: 28.437107 },
-      { lng: 110.371292, lat: 28.4377 },
-      { lng: 110.370581, lat: 28.438198 },
-      { lng: 110.369831, lat: 28.438821 }
-    ]
+    id: 'pipe-high-01', level: 'high', name: '燃气1', code: 'GX-HP-001', length: 4.1,
+    material: 'L290N 无缝钢管', diameter: 'DN300', pressure: '高压A (4.0MPa)', road: '燃气1主干线',
+    status: '运行正常', layingMethod: '直埋敷设', depth: '1.8m', commissioningDate: '2026-06',
+    points: [{lng:110.404947,lat:28.433419},{lng:110.404836,lat:28.433429},{lng:110.403275,lat:28.433571},{lng:110.401084,lat:28.433876},{lng:110.399601,lat:28.433876},{lng:110.398112,lat:28.433979},{lng:110.396717,lat:28.434314},{lng:110.394299,lat:28.434538},{lng:110.394352,lat:28.434887},{lng:110.391969,lat:28.434985},{lng:110.384374,lat:28.435695},{lng:110.381418,lat:28.43559},{lng:110.377993,lat:28.436193},{lng:110.376062,lat:28.436385},{lng:110.374231,lat:28.43655},{lng:110.372584,lat:28.437107},{lng:110.371292,lat:28.4377},{lng:110.370581,lat:28.438198},{lng:110.369831,lat:28.438821}]
   },
   {
-    id: 'pipe-subhigh-01',
-    level: 'subHigh',
-    name: '燃气2',
-    code: 'GX-SHP-002',
-    length: 3.8,
-    material: 'L245N 无缝钢管',
-    diameter: 'DN250',
-    pressure: '次高压A (1.6MPa)',
-    road: '燃气2支线',
-    status: '运行正常',
-    layingMethod: '直埋敷设',
-    depth: '1.6m',
-    commissioningDate: '2026-03',
-    points: [
-      { lng: 110.361433, lat: 28.454979 },
-      { lng: 110.362363, lat: 28.453169 },
-      { lng: 110.362851, lat: 28.452213 },
-      { lng: 110.364377, lat: 28.452443 },
-      { lng: 110.365138, lat: 28.45246 },
-      { lng: 110.366462, lat: 28.452157 },
-      { lng: 110.369549, lat: 28.451441 },
-      { lng: 110.37219, lat: 28.450897 },
-      { lng: 110.372753, lat: 28.450901 },
-      { lng: 110.373875, lat: 28.451194 },
-      { lng: 110.373913, lat: 28.451107 },
-      { lng: 110.374597, lat: 28.451476 }
-    ]
+    id: 'pipe-subhigh-01', level: 'subHigh', name: '燃气2', code: 'GX-SHP-002', length: 3.8,
+    material: 'L245N 无缝钢管', diameter: 'DN250', pressure: '次高压A (1.6MPa)', road: '燃气2支线',
+    status: '运行正常', layingMethod: '直埋敷设', depth: '1.6m', commissioningDate: '2026-03',
+    points: [{lng:110.361433,lat:28.454979},{lng:110.362363,lat:28.453169},{lng:110.362851,lat:28.452213},{lng:110.364377,lat:28.452443},{lng:110.365138,lat:28.45246},{lng:110.366462,lat:28.452157},{lng:110.369549,lat:28.451441},{lng:110.37219,lat:28.450897},{lng:110.372753,lat:28.450901},{lng:110.373875,lat:28.451194},{lng:110.373913,lat:28.451107},{lng:110.374597,lat:28.451476}]
   }
 ]
 
-const pipePointData = [
-  { id: 'point-valve-01', type: 'valve', pipelineId: 'pipe-high-01', name: 'A点', code: 'GD-FM-001', road: '燃气1', status: '在线', deviceModel: 'Z45X-16Q', caliber: 'DN300', lng: 110.362851, lat: 28.452213 },
-  { id: 'point-valve-02', type: 'valve', pipelineId: 'pipe-high-01', name: 'B点', code: 'GD-FM-002', road: '燃气1', status: '在线', deviceModel: 'Z41H-25C', caliber: 'DN300', lng: 110.369549, lat: 28.451441 },
-  { id: 'point-valve-03', type: 'valve', pipelineId: 'pipe-subhigh-01', name: 'C点', code: 'GD-FM-003', road: '燃气2', status: '在线', deviceModel: 'Z45X-16Q', caliber: 'DN250', lng: 110.373913, lat: 28.451107 },
-  { id: 'point-regulator-01', type: 'regulator', pipelineId: 'pipe-high-01', name: 'D点', code: 'GD-TY-001', road: '燃气1', status: '在线', deviceModel: 'RTZ-80/0.4F', caliber: 'DN300', lng: 110.401084, lat: 28.433876 },
-  { id: 'point-regulator-02', type: 'regulator', pipelineId: 'pipe-high-01', name: 'E点', code: 'GD-TY-002', road: '燃气1', status: '在线', deviceModel: 'RTZ-50/0.4F', caliber: 'DN250', lng: 110.391969, lat: 28.434985 },
-  { id: 'point-flowmeter-01', type: 'flowmeter', pipelineId: 'pipe-high-01', name: 'F点', code: 'GD-LL-001', road: '燃气1', status: '在线', deviceModel: 'LWQZ-150', caliber: 'DN300', lng: 110.376062, lat: 28.436385 },
-  { id: 'point-flowmeter-02', type: 'flowmeter', pipelineId: 'pipe-subhigh-01', name: 'G点', code: 'GD-LL-002', road: '燃气2', status: '在线', deviceModel: 'LWQZ-100', caliber: 'DN200', lng: 110.370581, lat: 28.438198 }
-]
+const pipePointData = ref([])
+const manholeData = ref([])
 
-const manholeData = [
-  { id: 'manhole-cover-01', type: 'cover', pipelineId: 'pipe-high-01', name: 'A点窨井盖', code: 'YJ-JG-001', road: '燃气1', status: '完好', material: '球墨铸铁', size: 'Φ700', lng: 110.362851, lat: 28.452213 },
-  { id: 'manhole-cover-02', type: 'cover', pipelineId: 'pipe-high-01', name: 'B点窨井盖', code: 'YJ-JG-002', road: '燃气1', status: '完好', material: '球墨铸铁', size: 'Φ700', lng: 110.369549, lat: 28.451441 },
-  { id: 'manhole-inspection-01', type: 'inspection', pipelineId: 'pipe-subhigh-01', name: 'C点检查井', code: 'YJ-JC-001', road: '燃气2', status: '巡检正常', material: '钢筋混凝土', size: '1000×1000', lng: 110.373913, lat: 28.451107 },
-]
+async function loadGisData() {
+  try {
+    const [pointRes, manholeRes] = await Promise.all([
+      getGasPipePointPage(1, 500, {}),
+      getManholeList()
+    ])
+    const points = (pointRes.data && pointRes.data.records) ? pointRes.data.records : []
+    pipePointData.value = points.filter(p => p.longitude && p.latitude).map(p => ({
+      id: 'point-' + p.pointId, type: mapPointType(p.pointType), pipelineId: p.networkId,
+      name: p.pointName, code: p.pointCode, road: p.networkName || '', status: '在线',
+      deviceModel: p.material || '', caliber: p.diameter ? p.diameter + 'mm' : '',
+      lng: Number(p.longitude), lat: Number(p.latitude)
+    }))
+    const manholes = manholeRes.data || []
+    manholeData.value = manholes.filter(m => m.longitude && m.latitude).map(m => ({
+      id: 'manhole-' + m.manholeId, type: 'cover', pipelineId: m.networkId || '',
+      name: m.manholeName, code: m.manholeCode, road: '', status: m.status === '0' ? '完好' : '异常',
+      material: m.material || '', size: m.manholeShape || '', lng: Number(m.longitude), lat: Number(m.latitude)
+    }))
+    if (mapInstance && typeof BMapGL !== 'undefined') renderMapScene()
+  } catch (e) { console.error(e) }
+}
+
+function mapPointType(type) {
+  if (!type) return 'terminal'
+  if (type.includes('阀门') || type === 'valve') return 'valve'
+  if (type.includes('调压') || type === 'regulator') return 'regulator'
+  if (type.includes('计量') || type.includes('流量') || type === 'flowmeter') return 'flowmeter'
+  return 'terminal'
+}
 
 const colorMap = {
   high: '#e63946',
@@ -302,8 +268,8 @@ let overlayClicked = false
 
 const summaryStats = computed(() => ({
   pipelineLength: pipelineData.reduce((sum, item) => sum + item.length, 0).toFixed(1),
-  pipePointCount: pipePointData.length,
-  manholeCount: manholeData.length,
+  pipePointCount: pipePointData.value.length,
+  manholeCount: manholeData.value.length,
   coverageArea: '18.6'
 }))
 
@@ -323,7 +289,7 @@ const searchableFeatures = computed(() => {
     lat: getMidPoint(item.points).lat,
     raw: item
   }))
-  const pipePoints = pipePointData.map(item => ({
+  const pipePoints = pipePointData.value.map(item => ({
     kind: 'pipePoint',
     type: item.type,
     name: item.name,
@@ -333,7 +299,7 @@ const searchableFeatures = computed(() => {
     lat: item.lat,
     raw: item
   }))
-  const manholes = manholeData.map(item => ({
+  const manholes = manholeData.value.map(item => ({
     kind: 'manhole',
     type: item.type,
     name: item.name,
@@ -352,6 +318,7 @@ watch(layerState, () => {
 
 onMounted(async () => {
   await nextTick()
+  await loadGisData()
   waitForBMapGL()
   document.addEventListener('fullscreenchange', handleFullscreenChange)
 })
@@ -461,7 +428,6 @@ function renderMapScene() {
 
   closeInfoWindow()
   try { mapInstance.clearOverlays() } catch (_) { /* ignore */ }
-  try { drawBoundary() } catch (e) { console.warn('绘制围栏失败:', e) }
   try { drawPipelines() } catch (e) { console.warn('绘制管线失败:', e) }
   try { drawPipePoints() } catch (e) { console.warn('绘制管点失败:', e) }
   try { drawManholes() } catch (e) { console.warn('绘制窨井失败:', e) }
@@ -511,7 +477,7 @@ function drawPipelines() {
 }
 
 function drawPipePoints() {
-  pipePointData.forEach(item => {
+  pipePointData.value.forEach(item => {
     try {
       if (!layerState.pipePoints[item.type]) return
       const [plng, plat] = convertCoord(item.lng, item.lat)
@@ -526,7 +492,7 @@ function drawPipePoints() {
 }
 
 function drawManholes() {
-  manholeData.forEach(item => {
+  manholeData.value.forEach(item => {
     try {
       if (!layerState.manholes[item.type]) return
       const [mlng, mlat] = convertCoord(item.lng, item.lat)
@@ -712,13 +678,14 @@ function handleSearch() {
   ElMessage.success(`已定位到 ${matched.name}`)
 }
 
-function refreshScene() {
+async function refreshScene() {
   layerState.pipelines = { high: true, subHigh: true, medium: true, low: true }
   layerState.pipePoints = { valve: true, regulator: true, flowmeter: true, terminal: true }
   layerState.manholes = { cover: true, inspection: true }
   searchKeyword.value = ''
   selectedFeature.value = null
   closeInfoWindow()
+  await loadGisData()
   locateCenter()
 }
 

+ 2 - 2
src/views/subSystem/basic/Manhole.vue

@@ -164,7 +164,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import {
   getManholePage, addManhole, updateManhole, deleteManhole,
   getManholeDevices, addManholeDeviceRel, deleteManholeDeviceRel,
-  getEquipmentList, getPipeNetworkOptions
+  getEquipmentByTopLevelType, getPipeNetworkOptions
 } from '@/api/pipeNetwork/basic'
 import { getDicts } from '@/api/system/dict/data'
 
@@ -309,7 +309,7 @@ async function loadDeviceList() {
 }
 async function loadEquipmentOptions() {
   try {
-    const res = await getEquipmentList()
+    const res = await getEquipmentByTopLevelType('燃气')
     equipmentOptions.value = res.data || []
   } catch (e) { console.error(e) }
 }

+ 3 - 3
src/views/subSystem/basic/PointManage.vue

@@ -35,7 +35,7 @@
         <el-table-column label="操作" width="200" fixed="right">
           <template #default="{ row }">
             <el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
-<!--            <el-button type="info" size="small" @click="handleRelDevice(row)">关联设备</el-button>-->
+            <el-button type="info" size="small" @click="handleRelDevice(row)">关联设备</el-button>
             <el-button type="danger" size="small" @click="handleDelete(row)">删除</el-button>
           </template>
         </el-table-column>
@@ -130,7 +130,7 @@
 <script setup>
 import { ref, reactive, computed, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
-import { getPointPage, addPoint, updatePoint, deletePoint, getEquipmentByPoint, savePointRel, deletePointRel, getEquipmentList, getPipeNetworkOptions } from '@/api/pipeNetwork/basic'
+import { getPointPage, addPoint, updatePoint, deletePoint, getEquipmentByPoint, savePointRel, deletePointRel, getEquipmentByTopLevelType, getPipeNetworkOptions } from '@/api/pipeNetwork/basic'
 import { getDicts } from '@/api/system/dict/data'
 
 const loading = ref(false)
@@ -238,7 +238,7 @@ async function loadDeviceList() {
 }
 async function loadEquipmentOptions() {
   try {
-    const res = await getEquipmentList()
+    const res = await getEquipmentByTopLevelType('燃气')
     equipmentOptions.value = res.data || []
   } catch (e) { console.error(e) }
 }

+ 50 - 58
src/views/subSystem/basic/RepairRecord.vue

@@ -40,7 +40,7 @@
           <el-form :inline="true" :model="searchForm" class="search-form">
             <el-form-item label="管网ID">
               <el-select v-model="searchForm.networkId" placeholder="请选择" clearable style="width:190px" @change="onFilterChange">
-                <el-option v-for="p in pipelineData" :key="p.id" :label="p.id + ' - ' + p.name" :value="p.id" />
+                <el-option v-for="n in networkOptions" :key="n.networkId" :label="`${n.networkName}(${n.networkCode})`" :value="n.networkId" />
               </el-select>
             </el-form-item>
             <el-form-item label="维修类型">
@@ -59,8 +59,10 @@
         </div>
       </div>
 
-      <el-table :data="paginatedData" border stripe v-loading="loading" max-height="380" size="small">
-        <el-table-column prop="networkId" label="管网ID" width="100" />
+      <el-table :data="tableData" border stripe v-loading="loading" max-height="380" size="small">
+        <el-table-column label="管网" width="130">
+          <template #default="{ row }">{{ getNetworkName(row.networkId) }}</template>
+        </el-table-column>
         <el-table-column prop="repairDate" label="维修日期" width="120" />
         <el-table-column prop="repairType" label="维修类型" width="120">
           <template #default="{ row }">{{ getDictLabel(repairTypeDict, row.repairType) }}</template>
@@ -80,6 +82,7 @@
       <el-pagination
         v-model:current-page="pageNum" v-model:page-size="pageSize" :total="total"
         layout="total, prev, pager, next, sizes" :page-sizes="[10, 20, 50]"
+        @size-change="() => { pageNum = 1; loadData() }" @current-change="() => loadData()"
         style="margin-top:16px;justify-content:flex-end"
       />
     </el-card>
@@ -89,7 +92,7 @@
       <el-form :model="formData" ref="formRef" label-width="100px">
         <el-form-item label="管网ID" prop="networkId">
           <el-select v-model="formData.networkId" style="width:100%">
-            <el-option v-for="p in pipelineData" :key="p.id" :label="p.id + ' - ' + p.name" :value="p.id" />
+            <el-option v-for="n in networkOptions" :key="n.networkId" :label="`${n.networkName}(${n.networkCode})`" :value="n.networkId" />
           </el-select>
         </el-form-item>
         <el-form-item label="维修日期" prop="repairDate">
@@ -119,11 +122,13 @@ import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'v
 import * as echarts from 'echarts'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { convertCoord } from '@/utils/coordTransform'
+import { getPipeNetworkOptions, getRepairRecordPage, addRepairRecord, updateRepairRecord, deleteRepairRecord } from '@/api/pipeNetwork/basic'
 
-// ==================== 静态数据 ====================
+// ==================== 数据 ====================
 const loading = ref(false)
 const pageNum = ref(1)
 const pageSize = ref(10)
+const total = ref(0)
 const searchForm = reactive({ networkId: '', repairType: '' })
 const dialogVisible = ref(false)
 const dialogTitle = ref('新增')
@@ -151,6 +156,7 @@ const MAP_MAX_ZOOM = 19
 const MAP_DEFAULT_ZOOM = 15
 
 const mapError = ref('')
+const networkOptions = ref([])
 let mapInstance = null
 let activeInfoWindow = null
 let overlayClicked = false
@@ -175,42 +181,34 @@ const pipePointData = [
   { name: 'G点', lng: 110.370581, lat: 28.438198, pipelineId: 'net001' },
 ]
 
-// ==================== 维修记录 ====================
-const tableData = ref([
-  { repairId: '1', networkId: 'net001', repairDate: '2026-06-10', repairType: '1', repairContent: '辰州北路高压段焊缝渗漏,管道焊接接头处出现裂纹,停气抢修并更换受损管段1.2m', repairCompany: '沅陵燃气工程有限公司', repairCost: 12500, repairPerson: '张建国', createTime: '2026-06-10 14:30:22', remark: '夜间施工,影响200户居民用气3小时' },
-  { repairId: '2', networkId: 'net005', repairDate: '2026-06-05', repairType: '3', repairContent: '古城中路中压A段防腐层老化脱落,管体局部锈蚀深度1.8mm,防腐层整体修复', repairCompany: '湖南城市燃气技术公司', repairCost: 38600, repairPerson: '李志强', createTime: '2026-06-05 09:15:40', remark: '修复长度约85m' },
-  { repairId: '3', networkId: 'net008', repairDate: '2026-05-28', repairType: '4', repairContent: '迎宾西路中压段三通管件更换,原管件因地基沉降导致应力开裂,更换为加强型管件', repairCompany: '怀化兴燃工程有限公司', repairCost: 8200, repairPerson: '王立新', createTime: '2026-05-28 16:45:10', remark: '' },
-  { repairId: '4', networkId: 'net012', repairDate: '2026-05-20', repairType: '1', repairContent: '建设路中段第三方施工破坏,DN110 PE管被挖掘机铲断,紧急停气抢修', repairCompany: '沅陵燃气工程有限公司', repairCost: 15000, repairPerson: '赵明辉', createTime: '2026-05-20 03:22:55', remark: '第三方施工未报备' },
-  { repairId: '5', networkId: 'net003', repairDate: '2026-05-15', repairType: '2', repairContent: '辰州中路高压B段计划停气检修,更换老化阀门2台,管道内检测并清管', repairCompany: '湖南省特种设备检测院', repairCost: 52000, repairPerson: '刘伟东', createTime: '2026-05-15 08:00:00', remark: '年度计划检修,提前72小时通知用户' },
-  { repairId: '6', networkId: 'net009', repairDate: '2026-05-08', repairType: '5', repairContent: '县政府迎宾路中压段环焊缝异常,超声检测发现焊缝内部缺陷,焊缝重新焊接', repairCompany: '湖南城市燃气技术公司', repairCost: 18600, repairPerson: '李志强', createTime: '2026-05-08 11:20:18', remark: '焊缝缺陷深度2.3mm' },
-  { repairId: '7', networkId: 'net015', repairDate: '2026-04-30', repairType: '6', repairContent: '滨江路东低压段阀门操作卡涩,阀杆填料泄漏,拆解阀门更换填料及O型密封圈', repairCompany: '怀化兴燃工程有限公司', repairCost: 4500, repairPerson: '王立新', createTime: '2026-04-30 14:10:33', remark: '' },
-  { repairId: '8', networkId: 'net011', repairDate: '2026-04-22', repairType: '3', repairContent: '建设西路中压段管道外防腐层破损,杂散电流干扰导致电化学腐蚀,修复防腐层并加装牺牲阳极', repairCompany: '湖南城市燃气技术公司', repairCost: 28500, repairPerson: '李志强', createTime: '2026-04-22 10:05:00', remark: '腐蚀深度1.5mm' },
-  { repairId: '9', networkId: 'net002', repairDate: '2026-04-15', repairType: '1', repairContent: '辰州中路高压A段管道泄漏报警,法兰连接处密封垫老化泄漏,紧急更换金属缠绕垫', repairCompany: '沅陵燃气工程有限公司', repairCost: 6300, repairPerson: '张建国', createTime: '2026-04-15 21:08:42', remark: '泄漏量约0.3m³' },
-  { repairId: '10', networkId: 'net006', repairDate: '2026-04-08', repairType: '2', repairContent: '古城中路中压B段年度维护,全线管道壁厚检测,阴极保护系统检测,更换测试桩3个', repairCompany: '湖南省特种设备检测院', repairCost: 22000, repairPerson: '刘伟东', createTime: '2026-04-08 09:00:00', remark: '壁厚检测结果符合GB50028' },
-  { repairId: '11', networkId: 'net014', repairDate: '2026-03-28', repairType: '4', repairContent: '滨江路西低压段PE管老化更换,原管道使用年限已到设计寿命,整体更换DN160 PE100新管', repairCompany: '沅陵燃气工程有限公司', repairCost: 78500, repairPerson: '赵明辉', createTime: '2026-03-28 07:30:00', remark: '更换长度约210m' },
-  { repairId: '12', networkId: 'net004', repairDate: '2026-03-18', repairType: '6', repairContent: '古城北路中压段阀门井内积水导致阀门锈蚀,清理井室并更换锈蚀螺栓及附件', repairCompany: '怀化兴燃工程有限公司', repairCost: 3500, repairPerson: '王立新', createTime: '2026-03-18 13:25:10', remark: '' },
-  { repairId: '13', networkId: 'net010', repairDate: '2026-03-10', repairType: '5', repairContent: '迎宾东路中压段直缝焊管焊缝补强,焊缝余高不符合规范,打磨处理后进行补焊', repairCompany: '湖南城市燃气技术公司', repairCost: 9800, repairPerson: '李志强', createTime: '2026-03-10 15:40:05', remark: '焊缝长度28mm' },
-  { repairId: '14', networkId: 'net016', repairDate: '2026-02-25', repairType: '3', repairContent: '天宁西路低压段沿河侧管道外防腐保温层修复,河水浸泡导致保温层脱落约40m', repairCompany: '沅陵燃气工程有限公司', repairCost: 33500, repairPerson: '张建国', createTime: '2026-02-25 10:20:30', remark: '枯水期施工' },
-  { repairId: '15', networkId: 'net007', repairDate: '2026-02-18', repairType: '2', repairContent: '古城南路中压段穿越路口管段套管更换,原钢套管腐蚀穿孔,换用加强级3PE防腐套管', repairCompany: '湖南省特种设备检测院', repairCost: 16500, repairPerson: '刘伟东', createTime: '2026-02-18 08:50:15', remark: '' },
-  { repairId: '16', networkId: 'net017', repairDate: '2026-02-08', repairType: '4', repairContent: '天宁东路低压段凝水缸更换,冬季冻裂导致凝水缸壳体破损,更换为抗冻型凝水缸', repairCompany: '怀化兴燃工程有限公司', repairCost: 7200, repairPerson: '王立新', createTime: '2026-02-08 11:15:00', remark: '' },
-  { repairId: '17', networkId: 'net013', repairDate: '2026-01-22', repairType: '1', repairContent: '建设东路中压段地基下沉导致管道变形,开挖后重新敷设管基并加装波纹补偿器', repairCompany: '沅陵燃气工程有限公司', repairCost: 25600, repairPerson: '赵明辉', createTime: '2026-01-22 16:35:48', remark: '沉降量约80mm' },
-  { repairId: '18', networkId: 'net001', repairDate: '2026-01-10', repairType: '2', repairContent: '辰州北路高压段阴极保护系统维护,更换阳极地床,测试保护电位', repairCompany: '湖南省特种设备检测院', repairCost: 11200, repairPerson: '刘伟东', createTime: '2026-01-10 09:30:00', remark: '保护电位-1.15V~-1.22V' },
-])
+// ==================== 维修记录数据 ====================
+const tableData = ref([])
 
 const pressureColors = { high: '#e63946', medium: '#f77f00', low: '#2a9d8f' }
 const repairedNetworkIds = computed(() => { const s = new Set(); tableData.value.forEach(r => s.add(r.networkId)); return s })
 
-function getPipelineName(id) { const p = pipelineData.find(p => p.id === id); return p ? p.name : id }
+async function loadNetworkOptions() {
+  if (networkOptions.value.length > 0) return
+  try { const res = await getPipeNetworkOptions(); networkOptions.value = res.data || [] } catch (e) { console.error(e) }
+}
+function getNetworkName(id) {
+  const found = networkOptions.value.find(n => n.networkId === id)
+  return found ? found.networkName : id
+}
+function getPipelineName(id) {
+  const name = getNetworkName(id)
+  return name !== id ? name : (pipelineData.find(p => p.id === id) || {}).name || id
+}
 
-// ==================== 过滤分页 ====================
-const filteredData = computed(() => {
-  let data = tableData.value
-  if (searchForm.networkId) data = data.filter(r => r.networkId === searchForm.networkId)
-  if (searchForm.repairType) data = data.filter(r => r.repairType === searchForm.repairType)
-  return data.sort((a, b) => b.createTime.localeCompare(a.createTime))
-})
-const paginatedData = computed(() => filteredData.value.slice((pageNum.value - 1) * pageSize.value, pageNum.value * pageSize.value))
-const total = computed(() => filteredData.value.length)
+// ==================== 数据加载 ====================
+async function loadData() {
+  loading.value = true
+  try {
+    const res = await getRepairRecordPage(pageNum.value, pageSize.value, searchForm)
+    tableData.value = (res.data && res.data.records) ? res.data.records : []
+    total.value = (res.data && res.data.total) ? res.data.total : 0
+  } catch (e) { console.error(e) } finally { loading.value = false }
+}
 
 // ==================== 百度地图 ====================
 function waitForBMapGL() {
@@ -288,7 +286,7 @@ function renderMapScene() {
         const mid = { lng: convertCoord(rawMid.lng, rawMid.lat)[0], lat: convertCoord(rawMid.lng, rawMid.lat)[1] }
         const count = tableData.value.filter(r => r.networkId === pipe.id).length
         const repairList = tableData.value.filter(r => r.networkId === pipe.id).slice(0, 3).map(r => `${r.repairDate} ${getDictLabel(repairTypeDict, r.repairType)}`).join('<br>')
-        const html = `<div style="font-size:13px;max-width:300px;"><b>${pipe.id}</b> ${pipe.name}<br>
+        const html = `<div style="font-size:13px;max-width:300px;"><b>${pipe.name}</b>(${getNetworkName(pipe.id)})<br>
           <span style="color:${pressureColors[pipe.pressure]};font-weight:bold;">${pipe.pressure === 'high' ? '高压' : pipe.pressure === 'medium' ? '中压' : '低压'}</span>
           &nbsp;累计维修 <b style="color:#e63946;">${count}</b> 次
           ${count > 0 ? '<br><span style="color:#909399;font-size:11px;">' + repairList + '</span>' : ''}</div>`
@@ -411,36 +409,28 @@ function initCharts() { try { initRiskPie() } catch (e) { console.warn('饼图
 function resizeCharts() { riskPieChart?.resize(); repairTrendChart?.resize() }
 
 // ==================== 操作 ====================
-function onFilterChange() { pageNum.value = 1 }
-function handleSearch() { pageNum.value = 1 }
+function onFilterChange() { pageNum.value = 1; loadData() }
+function handleSearch() { pageNum.value = 1; loadData() }
 function handleReset() {
   searchForm.networkId = ''; searchForm.repairType = ''; pageNum.value = 1
-  nextTick(() => renderMapScene())
+  loadData()
 }
 function handleAdd() {
   dialogTitle.value = '新增'; dialogVisible.value = true
   Object.assign(formData, { repairId: '', networkId: '', repairDate: '', repairType: '', repairContent: '', repairCompany: '', repairCost: null, repairPerson: '', remark: '' })
+  loadNetworkOptions()
 }
-function handleEdit(row) { dialogTitle.value = '编辑'; dialogVisible.value = true; Object.assign(formData, { ...row }) }
-function handleSubmit() {
-  if (formData.repairId) {
-    const idx = tableData.value.findIndex(r => r.repairId === formData.repairId)
-    if (idx >= 0) tableData.value[idx] = { ...formData }
-    ElMessage.success('修改成功')
-  } else {
-    formData.repairId = String(Date.now())
-    formData.createTime = new Date().toLocaleString('zh-CN').replace(/\//g, '-')
-    tableData.value.unshift({ ...formData })
-    ElMessage.success('新增成功')
-  }
-  dialogVisible.value = false
-  nextTick(() => { renderMapScene(); initCharts() })
+function handleEdit(row) { dialogTitle.value = '编辑'; dialogVisible.value = true; Object.assign(formData, { ...row }); loadNetworkOptions() }
+async function handleSubmit() {
+  try {
+    if (formData.repairId) { await updateRepairRecord(formData); ElMessage.success('修改成功') }
+    else { await addRepairRecord(formData); ElMessage.success('新增成功') }
+    dialogVisible.value = false; loadData(); nextTick(() => renderMapScene())
+  } catch (e) { const msg = e?.response?.data?.msg || e?.message || '操作失败'; ElMessage.error(msg) }
 }
 function handleDelete(row) {
-  ElMessageBox.confirm('确认删除该维修记录?', '提示', { type: 'warning' }).then(() => {
-    tableData.value = tableData.value.filter(r => r.repairId !== row.repairId)
-    ElMessage.success('删除成功')
-    nextTick(() => { renderMapScene(); initCharts() })
+  ElMessageBox.confirm('确认删除该维修记录?', '提示', { type: 'warning' }).then(async () => {
+    try { await deleteRepairRecord(row.repairId); ElMessage.success('删除成功'); loadData(); nextTick(() => renderMapScene()) } catch (e) { ElMessage.error('删除失败') }
   }).catch(() => {})
 }
 
@@ -448,6 +438,8 @@ function handleDelete(row) {
 let resizeTimer = null
 onMounted(async () => {
   await nextTick()
+  await loadNetworkOptions()
+  await loadData()
   waitForBMapGL()
   initCharts()
   window.addEventListener('resize', () => {

+ 73 - 60
src/views/subSystem/gas/ghome/gHome.vue

@@ -3,17 +3,25 @@ import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
 import * as echarts from 'echarts'
 import { Odometer, CircleCheckFilled, VideoCameraFilled, WarnTriangleFilled } from '@element-plus/icons-vue'
 import { convertPipeline, convertPoints } from '@/utils/coordTransform'
+import { getGasDashboardSummary } from '@/api/pipeNetwork/basic'
 
 const nowText = ref('2025/12/31 12:59:59')
 const weekText = ref('星期三')
 const mapError = ref('')
-
-const baseCards = computed(() => [
-  { label: '监测点总数', value: 18, unit: '个', icon: Odometer, color: '#60b8ff' },
-  { label: '在线监测点', value: 16, unit: '个', icon: CircleCheckFilled, color: '#52e0a8' },
-  { label: '离线监测点', value: 2, unit: '个', icon: VideoCameraFilled, color: '#ff8e8e' },
-  { label: '当日预警点', value: 3, unit: '个', icon: WarnTriangleFilled, color: '#ffb54d' }
-])
+const loading = ref(false)
+
+// ========== 仪表盘数据 ==========
+const dashboardData = ref({})
+
+const baseCards = computed(() => {
+  const bs = dashboardData.value.baseStats || {}
+  return [
+    { label: '监测点总数', value: bs.totalPoints || 0, unit: '个', icon: Odometer, color: '#60b8ff' },
+    { label: '在线监测点', value: bs.onlinePoints || 0, unit: '个', icon: CircleCheckFilled, color: '#52e0a8' },
+    { label: '离线监测点', value: bs.offlinePoints || 0, unit: '个', icon: VideoCameraFilled, color: '#ff8e8e' },
+    { label: '异常设备', value: bs.alarmCount || 0, unit: '个', icon: WarnTriangleFilled, color: '#ffb54d' }
+  ]
+})
 
 const operationSummary = [
   { label: '管网总长度', value: '128.6km' },
@@ -21,56 +29,49 @@ const operationSummary = [
   { label: '调压站', value: '6座' }
 ]
 
-const repairRecords = [
-  { month: '1月', value: 3 },
-  { month: '2月', value: 5 },
-  { month: '3月', value: 4 },
-  { month: '4月', value: 6 },
-  { month: '5月', value: 4 },
-  { month: '6月', value: 7 }
-]
+const repairRecords = computed(() => {
+  const list = dashboardData.value.repairTrend || []
+  if (list.length > 0) return list
+  return [
+    { month: '1月', value: 0 }, { month: '2月', value: 0 }, { month: '3月', value: 0 },
+    { month: '4月', value: 0 }, { month: '5月', value: 0 }, { month: '6月', value: 0 }
+  ]
+})
 
-const pointRows = [
-  { id: 1, name: '辰州路阀井A-01', time: '12:59', value: '0.22MPa', status: '在线' },
-  { id: 2, name: '古城路调压箱B-02', time: '12:59', value: '0.24MPa', status: '在线' },
-  { id: 3, name: '迎宾路阀室C-03', time: '12:59', value: '0.18MPa', status: '预警' },
-  { id: 4, name: '建设路阀井D-04', time: '12:59', value: '0.21MPa', status: '在线' },
-  { id: 5, name: '滨江路管点E-05', time: '12:59', value: '0.23MPa', status: '在线' },
-  { id: 6, name: '天宁路调压站F-06', time: '12:59', value: '0.19MPa', status: '离线' },
-  { id: 7, name: '鸳鸯路阀井G-07', time: '12:59', value: '0.25MPa', status: '在线' },
-  { id: 8, name: '消防巷支线H-08', time: '12:59', value: '0.20MPa', status: '在线' }
-]
+const pointRows = computed(() => {
+  const list = dashboardData.value.pointRows || []
+  return list.length > 0 ? list : [{ id: 1, name: '暂无数据', time: '--', value: '--', status: '离线' }]
+})
 
-const equipmentRows = [
-  { id: 1, name: '调压柜A', code: 'RQ-001', location: '辰州路', status: '正常' },
-  { id: 2, name: '阀门井B', code: 'RQ-002', location: '古城路', status: '正常' },
-  { id: 3, name: '流量计C', code: 'RQ-003', location: '迎宾路', status: '检修中' },
-  { id: 4, name: '压力表D', code: 'RQ-004', location: '建设路', status: '正常' },
-  { id: 5, name: '调压箱E', code: 'RQ-005', location: '滨江路', status: '正常' }
-]
+const equipmentRows = computed(() => {
+  const list = dashboardData.value.equipmentRows || []
+  return list.length > 0 ? list : [{ id: 1, name: '暂无数据', code: '--', location: '--', status: '--' }]
+})
 
-const warningRows = [
-  { level: '高', title: '压力波动偏高', code: '辰州路阀井A-01', time: '12:59:59', desc: '建议复核上游调压状态', tag: '压力异常' },
-  { level: '中', title: '疑似泄漏趋势', code: '迎宾路阀室C-03', time: '12:58:40', desc: '瞬时流量较近30分钟均值偏高', tag: '流量异常' },
-  { level: '高', title: '通信中断', code: '天宁路调压站F-06', time: '12:57:12', desc: '采集设备离线超过15分钟', tag: '设备离线' },
-  { level: '中', title: '设备开盖异常', code: '古城路调压箱B-02', time: '12:56:22', desc: '巡检确认现场状态', tag: '巡检关注' },
-  { level: '中', title: '阀门状态异常', code: '滨江路管点E-05', time: '12:54:16', desc: '阀门开度反馈与设定值存在偏差', tag: '阀门异常' },
-  { level: '高', title: '瞬时流量突增', code: '鸳鸯路阀井G-07', time: '12:52:48', desc: '短时流量连续3次超出阈值上限', tag: '流量异常' },
-  { level: '中', title: '电池电量偏低', code: '消防巷支线H-08', time: '12:49:05', desc: '建议尽快安排现场更换电池', tag: '设备维护' },
-  { level: '高', title: '站点离线恢复失败', code: '天宁路调压站F-06', time: '12:45:31', desc: '自动重连3次未成功,请人工排查', tag: '设备离线' }
-]
+const warningRows = computed(() => {
+  const list = dashboardData.value.warningRows || []
+  return list.length > 0 ? list : [{ level: '中', title: '暂无告警', code: '--', time: '--:--:--', desc: '当前无告警信息', tag: '正常' }]
+})
 
-const hazardSummary = [
-  { label: '一般隐患', value: 14, color: '#f3e64d' },
-  { label: '较大隐患', value: 5, color: '#ff9f1a' },
-  { label: '重大隐患', value: 2, color: '#ff3030' }
-]
+const hazardSummary = computed(() => {
+  const map = dashboardData.value.hazardStats || {}
+  return [
+    { label: '重大隐患', value: map['重大隐患'] || 0, color: '#ff3030' },
+    { label: '较大隐患', value: map['较大隐患'] || 0, color: '#ff9f1a' },
+    { label: '一般隐患', value: map['一般隐患'] || 0, color: '#f3e64d' }
+  ]
+})
 
-const mapKpis = [
-  { label: '在线率', value: '88.9%' },
-  { label: '压力均值', value: '0.21MPa' },
-  { label: '今日告警', value: '4条' }
-]
+const mapKpis = computed(() => {
+  const bs = dashboardData.value.baseStats || {}
+  const total = bs.totalPoints || 0
+  const online = bs.onlinePoints || 0
+  return [
+    { label: '在线率', value: total > 0 ? (online / total * 100).toFixed(1) + '%' : '--' },
+    { label: '压力均值', value: '0.21MPa' },
+    { label: '今日告警', value: (bs.alarmCount || 0) + '条' }
+  ]
+})
 
 const pipelineLines = [
   {
@@ -156,11 +157,12 @@ function initRepairChart() {
   if (!repairChartRef.value) return
   repairChart?.dispose()
   repairChart = echarts.init(repairChartRef.value)
+  const data = repairRecords.value
   repairChart.setOption({
     grid: { left: 30, right: 12, top: 20, bottom: 24, containLabel: true },
     xAxis: {
       type: 'category',
-      data: repairRecords.map(item => item.month),
+      data: data.map(item => item.month),
       axisLine: { lineStyle: { color: 'rgba(91, 167, 219, 0.8)' } },
       axisLabel: { color: '#d2efff' }
     },
@@ -174,7 +176,7 @@ function initRepairChart() {
     series: [{
       type: 'bar',
       barWidth: 24,
-      data: repairRecords.map(item => item.value),
+      data: data.map(item => item.value),
       itemStyle: {
         borderRadius: [6, 6, 0, 0],
         color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
@@ -190,6 +192,7 @@ function initHazardChart() {
   if (!hazardChartRef.value) return
   hazardChart?.dispose()
   hazardChart = echarts.init(hazardChartRef.value)
+  const data = hazardSummary.value
   hazardChart.setOption({
     grid: { left: 18, right: 18, top: 10, bottom: 10, containLabel: true },
     xAxis: {
@@ -201,7 +204,7 @@ function initHazardChart() {
     },
     yAxis: {
       type: 'category',
-      data: hazardSummary.map(item => item.label),
+      data: data.map(item => item.label),
       axisLine: { show: false },
       axisTick: { show: false },
       axisLabel: { color: '#d2efff', fontSize: 13 }
@@ -209,7 +212,7 @@ function initHazardChart() {
     tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
     series: [{
       type: 'bar',
-      data: hazardSummary.map(item => ({ value: item.value, itemStyle: { color: item.color, borderRadius: 10 } })),
+      data: data.map(item => ({ value: item.value, itemStyle: { color: item.color, borderRadius: 10 } })),
       barWidth: 14,
       label: { show: true, position: 'right', color: '#fff', fontWeight: 'bold' },
       showBackground: true,
@@ -243,13 +246,14 @@ function waitForBMapGL() {
 function createFlowLabel(BMapGL, text) {
   const label = new BMapGL.Label(text, { offset: new BMapGL.Size(-46, -18) })
   label.setStyle({
-    color: '#fff36a',
-    background: 'rgba(255, 230, 0, 0.22)',
-    border: '1px solid rgba(255, 230, 0, 0.55)',
+    color: '#00ff88',
+    background: 'rgba(0, 40, 30, 0.85)',
+    border: '1px solid rgba(0, 255, 136, 0.7)',
     borderRadius: '8px',
     padding: '5px 8px',
     fontSize: '12px',
-    boxShadow: '0 0 12px rgba(255, 230, 0, 0.22)'
+    fontWeight: 'bold',
+    boxShadow: '0 0 14px rgba(0, 255, 136, 0.35)'
   })
   return label
 }
@@ -323,9 +327,18 @@ function handleResize() {
   hazardChart?.resize()
 }
 
+async function loadDashboardData() {
+  loading.value = true
+  try {
+    const res = await getGasDashboardSummary()
+    dashboardData.value = res.data || {}
+  } catch (e) { console.error(e) } finally { loading.value = false }
+}
+
 onMounted(async () => {
   updateClock()
   clockTimer = window.setInterval(updateClock, 1000)
+  await loadDashboardData()
   await nextTick()
   initRepairChart()
   initHazardChart()

+ 61 - 7
src/views/subSystem/hidden/HazardList.vue

@@ -23,6 +23,16 @@
             <el-option label="已报送" :value="1" />
           </el-select>
         </el-form-item>
+        <el-form-item label="关联管网">
+          <el-select v-model="searchForm.networkId" placeholder="请选择" clearable style="width:160px">
+            <el-option v-for="n in networkOptions" :key="n.networkId" :label="n.networkName" :value="n.networkId" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="关联设备">
+          <el-select v-model="searchForm.equipmentId" placeholder="请选择" clearable style="width:160px">
+            <el-option v-for="e in equipmentOptions" :key="e.equipmentId" :label="e.equipmentName" :value="e.equipmentId" />
+          </el-select>
+        </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleSearch">查询</el-button>
           <el-button @click="handleReset">重置</el-button>
@@ -51,6 +61,12 @@
             <el-tag :type="statusTag(row.hazardStatus)">{{ getDictLabel(hazardStatusDict, row.hazardStatus) }}</el-tag>
           </template>
         </el-table-column>
+        <el-table-column label="关联管网" width="140">
+          <template #default="{ row }">{{ getNetworkName(row.networkId) }}</template>
+        </el-table-column>
+        <el-table-column label="关联设备" width="140">
+          <template #default="{ row }">{{ getEquipmentName(row.equipmentId) }}</template>
+        </el-table-column>
         <el-table-column prop="reportUnit" label="上报单位" width="120" />
         <el-table-column prop="reportTime" label="上报时间" width="160" />
         <el-table-column label="操作" width="260" fixed="right">
@@ -99,6 +115,20 @@
               </el-select>
             </el-form-item>
           </el-col>
+          <el-col :span="12">
+            <el-form-item label="关联管网">
+              <el-select v-model="formData.networkId" placeholder="请选择" clearable style="width: 100%">
+                <el-option v-for="n in networkOptions" :key="n.networkId" :label="n.networkName" :value="n.networkId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="关联设备">
+              <el-select v-model="formData.equipmentId" placeholder="请选择" clearable style="width: 100%">
+                <el-option v-for="e in equipmentOptions" :key="e.equipmentId" :label="e.equipmentName" :value="e.equipmentId" />
+              </el-select>
+            </el-form-item>
+          </el-col>
           <el-col :span="12">
             <el-form-item label="上报单位">
               <el-input v-model="formData.reportUnit" />
@@ -154,26 +184,30 @@ import { ref, reactive, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { getHazardPage, addHazard, updateHazard, deleteHazard, submitHazard } from '@/api/pipeNetwork/hazard'
 import { getDicts } from '@/api/system/dict/data'
+import { getPipeNetworkOptions, getEquipmentByTopLevelType } from '@/api/pipeNetwork/basic'
 
 const loading = ref(false)
 const tableData = ref([])
 const pageNum = ref(1)
 const pageSize = ref(10)
 const total = ref(0)
-const searchForm = reactive({ hazardType: '', hazardLevel: '', hazardStatus: '', isSubmitted: null })
+const searchForm = reactive({ hazardType: '', hazardLevel: '', hazardStatus: '', isSubmitted: null, networkId: '', equipmentId: '' })
 const dialogVisible = ref(false)
 const dialogTitle = ref('新增')
 const formRef = ref(null)
 const formData = reactive({
   hazardId: '', hazardNo: '', hazardType: '', hazardLevel: '', hazardDesc: '',
   hazardSource: '', hazardStatus: '2', reportUnit: '', reportTime: '',
-  rectifyPlan: '', rectifyDeadline: '', rectifyPerson: '', longitude: null, latitude: null
+  rectifyPlan: '', rectifyDeadline: '', rectifyPerson: '',
+  networkId: '', equipmentId: '', longitude: null, latitude: null
 })
 
 const hazardTypeDict = ref([])
 const hazardLevelDict = ref([])
 const hazardStatusDict = ref([])
 const hazardSourceDict = ref([])
+const networkOptions = ref([])
+const equipmentOptions = ref([])
 
 function getDictLabel(dict, value) {
   const item = dict.find(d => d.dictValue === value)
@@ -212,21 +246,41 @@ async function loadData() {
 }
 function handleSearch() { pageNum.value = 1; loadData() }
 function handleReset() {
-  Object.assign(searchForm, { hazardType: '', hazardLevel: '', hazardStatus: '', isSubmitted: null })
+  Object.assign(searchForm, { hazardType: '', hazardLevel: '', hazardStatus: '', isSubmitted: null, networkId: '', equipmentId: '' })
   handleSearch()
 }
+async function loadNetworkOptions() {
+  if (networkOptions.value.length > 0) return
+  try { const res = await getPipeNetworkOptions(); networkOptions.value = res.data || [] } catch (e) { console.error(e) }
+}
+async function loadEquipmentOptions() {
+  if (equipmentOptions.value.length > 0) return
+  try { const res = await getEquipmentByTopLevelType('燃气'); equipmentOptions.value = res.data || [] } catch (e) { console.error(e) }
+}
+function getNetworkName(id) {
+  const found = networkOptions.value.find(n => n.networkId === id)
+  return found ? found.networkName : id || '-'
+}
+function getEquipmentName(id) {
+  const found = equipmentOptions.value.find(e => e.equipmentId === id)
+  return found ? found.equipmentName : id || '-'
+}
 function handleAdd() {
   dialogTitle.value = '新增'
-  Object.assign(formData, { hazardId: '', hazardNo: '', hazardType: '', hazardLevel: '', hazardDesc: '', hazardSource: '', hazardStatus: '2', reportUnit: '', reportTime: '', rectifyPlan: '', rectifyDeadline: '', rectifyPerson: '', longitude: null, latitude: null })
+  Object.assign(formData, { hazardId: '', hazardNo: '', hazardType: '', hazardLevel: '', hazardDesc: '', hazardSource: '', hazardStatus: '2', reportUnit: '', reportTime: '', rectifyPlan: '', rectifyDeadline: '', rectifyPerson: '', networkId: '', equipmentId: '', longitude: null, latitude: null })
   dialogVisible.value = true
+  loadNetworkOptions(); loadEquipmentOptions()
 }
-function handleEdit(row) { dialogTitle.value = '编辑'; Object.assign(formData, row); dialogVisible.value = true }
+function handleEdit(row) { dialogTitle.value = '编辑'; Object.assign(formData, row); dialogVisible.value = true; loadNetworkOptions(); loadEquipmentOptions() }
 async function handleSave() {
   try {
     if (formData.hazardId) { await updateHazard(formData); ElMessage.success('修改成功') }
     else { await addHazard(formData); ElMessage.success('新增成功') }
     dialogVisible.value = false; loadData()
-  } catch (e) { console.error(e) }
+  } catch (e) {
+    const msg = e?.response?.data?.msg || e?.message || '操作失败'
+    ElMessage.error(msg)
+  }
 }
 function handleDelete(row) {
   ElMessageBox.confirm('确认删除该隐患记录?', '提示', { type: 'warning' }).then(async () => {
@@ -239,7 +293,7 @@ async function handleSubmitHazard(row) {
   }).catch(() => {})
 }
 
-onMounted(async () => { await loadDicts(); loadData() })
+onMounted(async () => { await loadDicts(); loadData(); loadNetworkOptions(); loadEquipmentOptions() })
 </script>
 
 <style scoped>