فهرست منبع

feat(pipeNetwork): 管网子系统首页及设备信息页面调整

- 更新管网子系统的侧边栏与首页 (pHome)
- 重构管网设备信息相关页面: Pbasicinfo、PequipmentLed、PkeyPoints
- 新增管网设备信息 API 模块 (src/api/pipeNetwork/pdeviceInform.js)
- 调整 vite 配置
nahida 1 ماه پیش
والد
کامیت
36037447ec

+ 214 - 0
src/api/pipeNetwork/pdeviceInform.js

@@ -0,0 +1,214 @@
+import request from "@/utils/request";
+
+// 管网基础信息
+export function listPipeNetwork(query) {
+  return request({
+    url: "/PipeNetworkBase/findByPage",
+    method: "get",
+    params: query
+  });
+}
+
+export function getPipeNetwork(id) {
+  return request({
+    url: `/PipeNetworkBase/getById/${id}`,
+    method: "get"
+  });
+}
+
+export function listPipeNetworkAll() {
+  return request({
+    url: "/PipeNetworkBase/getList",
+    method: "get"
+  });
+}
+
+export function addPipeNetwork(data) {
+  return request({
+    url: "/PipeNetworkBase/save",
+    method: "post",
+    data
+  });
+}
+
+export function updatePipeNetwork(data) {
+  return request({
+    url: "/PipeNetworkBase/updateById",
+    method: "put",
+    data
+  });
+}
+
+export function delPipeNetwork(id) {
+  return request({
+    url: "/PipeNetworkBase/deleteById",
+    method: "delete",
+    params: { id }
+  });
+}
+
+// 关键监测点
+export function listMonitorPoint(query) {
+  return request({
+    url: "/MonitorPoint/findByPage",
+    method: "get",
+    params: query
+  });
+}
+
+export function getMonitorPoint(id) {
+  return request({
+    url: `/MonitorPoint/getById/${id}`,
+    method: "get"
+  });
+}
+
+export function addMonitorPoint(data) {
+  return request({
+    url: "/MonitorPoint/save",
+    method: "post",
+    data
+  });
+}
+
+export function updateMonitorPoint(data) {
+  return request({
+    url: "/MonitorPoint/updateById",
+    method: "put",
+    data
+  });
+}
+
+export function delMonitorPoint(id) {
+  return request({
+    url: "/MonitorPoint/deleteById",
+    method: "delete",
+    params: { id }
+  });
+}
+
+export function getMonitorPointDetail(pointId) {
+  return request({
+    url: `/MonitorPoint/pointDetail/${pointId}`,
+    method: "get"
+  });
+}
+
+export function listPointsByNetwork(networkId) {
+  return request({
+    url: `/MonitorPoint/byNetwork/${networkId}`,
+    method: "get"
+  });
+}
+
+export function bindPointEquipment(pointId, equipmentIds) {
+  return request({
+    url: "/MonitorPoint/bindEquipment",
+    method: "post",
+    params: {
+      pointId,
+      equipmentIds: Array.isArray(equipmentIds) ? equipmentIds.join(",") : equipmentIds
+    }
+  });
+}
+
+export function unbindPointEquipment(pointId, equipmentIds) {
+  return request({
+    url: "/MonitorPoint/unbindEquipment",
+    method: "post",
+    params: {
+      pointId,
+      equipmentIds: Array.isArray(equipmentIds) ? equipmentIds.join(",") : equipmentIds
+    }
+  });
+}
+
+// 物联感知设备
+export function listEquipment(query) {
+  return request({
+    url: "/EquipmentBase/findByPage",
+    method: "get",
+    params: query
+  });
+}
+
+export function getEquipment(id) {
+  return request({
+    url: `/EquipmentBase/getById/${id}`,
+    method: "get"
+  });
+}
+
+export function addEquipment(data) {
+  return request({
+    url: "/EquipmentBase/save",
+    method: "post",
+    data
+  });
+}
+
+export function updateEquipment(data) {
+  return request({
+    url: "/EquipmentBase/updateById",
+    method: "put",
+    data
+  });
+}
+
+export function delEquipment(id) {
+  return request({
+    url: "/EquipmentBase/deleteById",
+    method: "delete",
+    params: { id }
+  });
+}
+
+export function getEquipmentDetail(equipmentId) {
+  return request({
+    url: `/EquipmentBase/detail/${equipmentId}`,
+    method: "get"
+  });
+}
+
+export function listEquipmentByPoint(pointId) {
+  return request({
+    url: `/EquipmentBase/byPoint/${pointId}`,
+    method: "get"
+  });
+}
+
+export function updateEquipmentStatus(equipmentId, currentStatus) {
+  return request({
+    url: "/EquipmentBase/updateStatus",
+    method: "put",
+    params: { equipmentId, currentStatus }
+  });
+}
+
+export function testEquipment(equipmentId, payload = {}) {
+  return request({
+    url: "/EquipmentBase/test",
+    method: "post",
+    params: {
+      equipmentId,
+      testType: payload.testType,
+      testDetail: payload.testDetail,
+      testUser: payload.testUser
+    }
+  });
+}
+
+// 基础辅助数据
+export function listEquipmentTypeAll() {
+  return request({
+    url: "/EquipmentType/getList",
+    method: "get"
+  });
+}
+
+export function listEquipmentStatusAll() {
+  return request({
+    url: "/EquipmentStatus/getList",
+    method: "get"
+  });
+}

+ 25 - 24
src/layout/components/Sidebar/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <!-- 左边菜单栏-->
+  <!-- 左侧菜单栏 -->
   <div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
     <logo v-if="showLogo" :collapse="isCollapse" />
     <el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
@@ -52,43 +52,44 @@ const activeMenu = computed(() => {
   return path
 })
 
-// ===================== 【核心:彻底隔离总后台/子系统,并过滤 PipeNetwork】 =====================
+const legacySubSystemPrefixes = ['/pipeNetwork']
+
+function isSubSystemPath(path) {
+  return path.startsWith('/subSystem/') || legacySubSystemPrefixes.some(prefix => path === prefix || path.startsWith(`${prefix}/`))
+}
+
+function getCurrentSystemPrefix(path) {
+  if (path.startsWith('/subSystem/')) {
+    return path.split('/').slice(0, 3).join('/')
+  }
+  return legacySubSystemPrefixes.find(prefix => path === prefix || path.startsWith(`${prefix}/`)) || ''
+}
+
 const showRoutes = computed(() => {
   const currentPath = route.path
   const allRoutes = permissionStore.sidebarRouters
-  // 1. 门户 → 无菜单
+
   if (currentPath.startsWith('/portal')) {
     return []
   }
 
-  // 2. 总后台场景:
-  // 包含:/index、/system、/log 等总后台公共路径
   const isAdminPage =
-      currentPath.startsWith('/index') ||
-      currentPath.startsWith('/system') ||
-      currentPath.startsWith('/log') ||
-      currentPath.startsWith('/monitor') ||
-      !currentPath.startsWith('/subSystem/') // 兜底:所有非子系统路径都视为总后台
+    currentPath.startsWith('/index') ||
+    currentPath.startsWith('/system') ||
+    currentPath.startsWith('/log') ||
+    currentPath.startsWith('/monitor') ||
+    !isSubSystemPath(currentPath)
 
   if (isAdminPage) {
-    // 只显示总后台菜单,隐藏所有子系统,同时过滤掉 name 为 PipeNetwork 的路由
-    return allRoutes.filter(item => {
-      return !item.path.startsWith('/subSystem/') && item.name !== 'PipeNetwork'
-    })
+    return allRoutes.filter(item => !isSubSystemPath(item.path))
   }
 
-  // 3. 子系统 /subSystem/xxx 开头 → 只显示当前子系统菜单
-  if (currentPath.startsWith('/subSystem/')) {
-    // 截取当前子系统前缀:/subSystem/xxx
-    const currentSystemPrefix = currentPath.split('/').slice(0, 3).join('/')
-    // 同时过滤掉 name 为 PipeNetwork 的路由
-    return allRoutes.filter(item => {
-      return item.path.startsWith(currentSystemPrefix) && item.name !== 'PipeNetwork'
-    })
+  if (isSubSystemPath(currentPath)) {
+    const currentSystemPrefix = getCurrentSystemPrefix(currentPath)
+    return allRoutes.filter(item => currentSystemPrefix && item.path.startsWith(currentSystemPrefix))
   }
 
-  // 兜底:不显示任何菜单
   return []
 })
 
-</script>
+</script>

+ 389 - 697
src/views/subSystem/pipeNetwork/pdeviceInform/Pbasicinfo.vue

@@ -1,717 +1,409 @@
-<!--管网基础信息管理-->
+<!-- 管网基础信息管理 -->
 <template>
-  <div class="prototype-container">
-
-    <div class="main-layout">
-      <!-- 左侧查询面板 -->
-      <div class="left-panel">
-        <div class="card">
-          <div class="card-header">🔍 设备查询</div>
-          <div class="card-body">
-            <div class="form-group">
-              <label class="form-label">设备名称 / ID</label>
-              <input
-                  type="text"
-                  v-model="searchParams.keyword"
-                  class="form-input"
-                  placeholder="模糊匹配设备名称或ID"
-                  @keyup.enter="handleSearch"
+  <div class="app-container">
+    <el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch">
+      <el-form-item label="设施编码" prop="networkCode">
+        <el-input
+          v-model="queryParams.networkCode"
+          placeholder="请输入设施编码"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="设施名称" prop="networkName">
+        <el-input
+          v-model="queryParams.networkName"
+          placeholder="请输入设施名称"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="设施类型" prop="networkType">
+        <el-select
+          v-model="queryParams.networkType"
+          placeholder="请选择设施类型"
+          clearable
+          filterable
+          allow-create
+          default-first-option
+          style="width: 220px"
+        >
+          <el-option
+            v-for="item in networkTypeOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+          filterable
+          allow-create
+          default-first-option
+          style="width: 180px"
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
+          修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
+          删除
+        </el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="networkList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="设施编码" align="center" prop="networkCode" min-width="130" />
+      <el-table-column label="设施名称" align="center" prop="networkName" min-width="160" show-overflow-tooltip />
+      <el-table-column label="设施类型" align="center" prop="networkType" min-width="120" />
+      <el-table-column label="等级" align="center" prop="networkLevel" width="90" />
+      <el-table-column label="管养单位" align="center" prop="managementUnit" min-width="150" show-overflow-tooltip />
+      <el-table-column label="位置描述" align="center" prop="location" min-width="180" show-overflow-tooltip />
+      <el-table-column label="状态" align="center" prop="status" width="100" />
+      <el-table-column label="建设日期" align="center" prop="buildDate" width="120" />
+      <el-table-column label="操作" align="center" width="220" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
+          <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog :title="title" v-model="open" width="760px" append-to-body>
+      <el-form ref="networkRef" :model="form" :rules="rules" label-width="110px">
+        <el-row :gutter="16">
+          <el-col :span="12">
+            <el-form-item label="设施编码" prop="networkCode">
+              <el-input v-model="form.networkCode" placeholder="请输入设施编码" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设施名称" prop="networkName">
+              <el-input v-model="form.networkName" placeholder="请输入设施名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设施类型" prop="networkType">
+              <el-select
+                v-model="form.networkType"
+                placeholder="请选择或输入设施类型"
+                filterable
+                allow-create
+                default-first-option
+                style="width: 100%"
               >
-            </div>
-            <div class="form-group">
-              <label class="form-label">设备状态</label>
-              <select v-model="searchParams.status" class="form-select">
-                <option value="">全部</option>
-                <option value="active">启用</option>
-                <option value="inactive">停用</option>
-                <option value="maintenance">维护中</option>
-              </select>
-            </div>
-            <div class="form-group">
-              <label class="form-label">设备类型</label>
-              <select v-model="searchParams.type" class="form-select">
-                <option value="">全部</option>
-                <option value="压力传感器">压力传感器</option>
-                <option value="流量传感器">流量传感器</option>
-                <option value="温度传感器">温度传感器</option>
-                <option value="泄漏检测仪">泄漏检测仪</option>
-              </select>
-            </div>
-            <div class="search-group">
-              <button @click="handleSearch" class="btn-primary">🔍 查询</button>
-              <button @click="handleReset" class="btn-outline">重置</button>
-            </div>
-          </div>
-        </div>
-
-        <div class="card">
-          <div class="card-header">📊 快捷操作</div>
-          <div class="card-body">
-            <button @click="openAddModal" class="btn-primary" style="width:100%; margin-bottom:8px;">+ 新增设备</button>
-            <button @click="batchTest" class="btn-outline" style="width:100%;">⚡ 批量测试验证</button>
-          </div>
-        </div>
-      </div>
-
-      <!-- 右侧设备列表 -->
-      <div class="right-panel">
-        <div class="card">
-          <div class="card-header">
-            📋 设备列表
-            <span style="font-size:0.7rem; font-weight:normal;">共 {{ filteredDevices.length }} 条记录</span>
-          </div>
-          <div class="card-body">
-            <div class="table-wrapper">
-              <table class="data-table">
-                <thead>
-                <tr><th>设备名称</th><th>设备ID</th><th>位置</th><th>类型</th><th>状态</th><th>维护人员</th><th>操作</th></tr>
-                </thead>
-                <tbody>
-                <tr v-if="paginatedDevices.length === 0">
-                  <td colspan="7" style="text-align:center;">暂无设备数据</td>
-                </tr>
-                <tr v-for="device in paginatedDevices" :key="device.id">
-                  <td>{{ device.name }}</td>
-                  <td>{{ device.deviceId }}</td>
-                  <td>{{ device.location }}</td>
-                  <td>{{ device.type }}</td>
-                  <td>
-                      <span class="status-badge" :class="getStatusClass(device.status)">
-                        {{ getStatusText(device.status) }}
-                      </span>
-                  </td>
-                  <td>{{ device.maintainer || '-' }}</td>
-                  <td class="action-icons">
-                    <button class="icon-btn" @click="showDetail(device)" title="查看详情">👁️</button>
-                    <button class="icon-btn" @click="openEditModal(device)" title="编辑">✏️</button>
-                    <button class="icon-btn" @click="testDevice(device)" title="测试验证">🧪</button>
-                    <button class="icon-btn" @click="toggleDeviceStatus(device)" title="启用/停用">🔘</button>
-                    <button class="icon-btn" @click="deleteDevice(device)" title="删除">🗑️</button>
-                  </td>
-                </tr>
-                </tbody>
-              </table>
-            </div>
-            <div class="pagination" v-if="totalPages > 1">
-              <button
-                  v-for="page in totalPages"
-                  :key="page"
-                  class="page-btn"
-                  :class="{ active: currentPage === page }"
-                  @click="currentPage = page"
+                <el-option
+                  v-for="item in networkTypeOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设施等级" prop="networkLevel">
+              <el-input v-model="form.networkLevel" placeholder="请输入设施等级" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="管养单位" prop="managementUnit">
+              <el-input v-model="form.managementUnit" placeholder="请输入管养单位" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-select
+                v-model="form.status"
+                placeholder="请选择或输入状态"
+                filterable
+                allow-create
+                default-first-option
+                style="width: 100%"
               >
-                {{ page }}
-              </button>
-            </div>
-          </div>
+                <el-option
+                  v-for="item in statusOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="位置描述" prop="location">
+              <el-input v-model="form.location" placeholder="请输入位置描述" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="经度" prop="longitude">
+              <el-input-number v-model="form.longitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="纬度" prop="latitude">
+              <el-input-number v-model="form.latitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="长度(米)" prop="length">
+              <el-input-number v-model="form.length" :precision="2" :step="1" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="管径(mm)" prop="diameter">
+              <el-input-number v-model="form.diameter" :precision="2" :step="1" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="材质" prop="material">
+              <el-input v-model="form.material" placeholder="请输入材质" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="建设日期" prop="buildDate">
+              <el-date-picker
+                v-model="form.buildDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择建设日期"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
         </div>
-      </div>
-    </div>
-
-    <!-- 设备详情模态框 -->
-    <div v-if="detailModalVisible" class="modal-overlay" @click.self="closeDetailModal">
-      <div class="modal-content">
-        <h3 style="margin-bottom:16px;">📟 设备详细信息</h3>
-        <div class="detail-row"><span class="detail-label">设备名称:</span>{{ currentDevice?.name }}</div>
-        <div class="detail-row"><span class="detail-label">设备ID:</span>{{ currentDevice?.deviceId }}</div>
-        <div class="detail-row"><span class="detail-label">设备位置:</span>{{ currentDevice?.location }}</div>
-        <div class="detail-row"><span class="detail-label">设备类型:</span>{{ currentDevice?.type }}</div>
-        <div class="detail-row"><span class="detail-label">设备厂家:</span>{{ currentDevice?.manufacturer || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">安装时间:</span>{{ currentDevice?.installDate || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">维护人员:</span>{{ currentDevice?.maintainer || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">联系方式:</span>{{ currentDevice?.contact || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">维修记录:</span>{{ currentDevice?.maintainRecord || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">关联监测点:</span>{{ currentDevice?.monitorPoint || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">设备状态:</span>
-          <span class="status-badge" :class="getStatusClass(currentDevice?.status)">
-            {{ getStatusText(currentDevice?.status) }}
-          </span>
-        </div>
-        <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-          <button @click="closeDetailModal" class="btn-outline">关闭</button>
-          <button @click="openEditFromDetail" class="btn-primary">编辑设备</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 编辑/新增设备模态框 -->
-    <div v-if="editModalVisible" class="modal-overlay" @click.self="closeEditModal">
-      <div class="modal-content" style="width:560px;">
-        <h3 style="margin-bottom:16px;">{{ isEdit ? '编辑设备信息' : '新增设备' }}</h3>
-        <form @submit.prevent="saveDevice">
-          <div class="form-group">
-            <label class="form-label">设备名称 *</label>
-            <input v-model="formData.name" class="form-input" required>
-          </div>
-          <div class="form-group">
-            <label class="form-label">设备ID *</label>
-            <input v-model="formData.deviceId" class="form-input" required>
-          </div>
-          <div class="form-group">
-            <label class="form-label">设备位置</label>
-            <input v-model="formData.location" class="form-input">
-          </div>
-          <div class="form-group">
-            <label class="form-label">设备类型</label>
-            <select v-model="formData.type" class="form-select">
-              <option>压力传感器</option>
-              <option>流量传感器</option>
-              <option>温度传感器</option>
-              <option>泄漏检测仪</option>
-            </select>
-          </div>
-          <div class="form-group">
-            <label class="form-label">设备厂家</label>
-            <input v-model="formData.manufacturer" class="form-input">
-          </div>
-          <div class="form-group">
-            <label class="form-label">安装时间</label>
-            <input v-model="formData.installDate" type="date" class="form-input">
-          </div>
-          <div class="form-group">
-            <label class="form-label">维护人员</label>
-            <input v-model="formData.maintainer" class="form-input">
-          </div>
-          <div class="form-group">
-            <label class="form-label">联系方式</label>
-            <input v-model="formData.contact" class="form-input">
-          </div>
-          <div class="form-group">
-            <label class="form-label">维修记录</label>
-            <textarea v-model="formData.maintainRecord" rows="2" class="form-textarea"></textarea>
-          </div>
-          <div class="form-group">
-            <label class="form-label">关联监测点</label>
-            <input v-model="formData.monitorPoint" class="form-input" placeholder="例如: 化工园区A点">
-          </div>
-          <div class="form-group">
-            <label class="form-label">设备状态</label>
-            <select v-model="formData.status" class="form-select">
-              <option value="active">启用</option>
-              <option value="inactive">停用</option>
-              <option value="maintenance">维护中</option>
-            </select>
-          </div>
-          <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-            <button type="button" @click="closeEditModal" class="btn-outline">取消</button>
-            <button type="submit" class="btn-primary">保存</button>
-          </div>
-        </form>
-      </div>
-    </div>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="设施详情" v-model="detailOpen" width="760px" append-to-body>
+      <el-descriptions :column="2" border v-if="detailForm.networkId">
+        <el-descriptions-item label="设施编码">{{ detailForm.networkCode || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设施名称">{{ detailForm.networkName || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设施类型">{{ detailForm.networkType || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设施等级">{{ detailForm.networkLevel || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="管养单位">{{ detailForm.managementUnit || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="状态">{{ detailForm.status || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="经度">{{ detailForm.longitude ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="纬度">{{ detailForm.latitude ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="长度(米)">{{ detailForm.length ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="管径(mm)">{{ detailForm.diameter ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="材质">{{ detailForm.material || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="建设日期">{{ detailForm.buildDate || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="位置描述" :span="2">{{ detailForm.location || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ detailForm.remark || "-" }}</el-descriptions-item>
+      </el-descriptions>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
-
-// 设备数据
-const devices = ref([
-  {
-    id: 1, name: "压力传感器A01", deviceId: "PS-001", location: "化工园区东门",
-    type: "压力传感器", manufacturer: "华仪科技", installDate: "2024-03-15",
-    maintainer: "张工", contact: "13800001111", maintainRecord: "2025-01-10 校准",
-    monitorPoint: "化工园区A点", status: "active"
-  },
-  {
-    id: 2, name: "流量监测仪B02", deviceId: "FL-002", location: "城南泵站",
-    type: "流量传感器", manufacturer: "水测智能", installDate: "2024-06-20",
-    maintainer: "李工", contact: "13800002222", maintainRecord: "正常",
-    monitorPoint: "城南枢纽", status: "active"
-  },
-  {
-    id: 3, name: "温度传感器C03", deviceId: "TP-003", location: "城西换热站",
-    type: "温度传感器", manufacturer: "北方仪表", installDate: "2023-11-10",
-    maintainer: "王工", contact: "13800003333", maintainRecord: "2025-02-01 更换探头",
-    monitorPoint: "城西热力点", status: "maintenance"
-  },
-  {
-    id: 4, name: "泄漏检测仪D04", deviceId: "LD-004", location: "华东管廊K2+300",
-    type: "泄漏检测仪", manufacturer: "安防科技", installDate: "2025-01-05",
-    maintainer: "赵工", contact: "13800004444", maintainRecord: "运行正常",
-    monitorPoint: "管廊重点段", status: "inactive"
+import { getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
+import {
+  addPipeNetwork,
+  delPipeNetwork,
+  getPipeNetwork,
+  listPipeNetwork,
+  updatePipeNetwork
+} from "@/api/pipeNetwork/pdeviceInform";
+
+const { proxy } = getCurrentInstance();
+
+const networkList = ref([]);
+const loading = ref(false);
+const open = ref(false);
+const detailOpen = ref(false);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+const networkTypeOptions = ["管网路线", "燃气设施", "排水设施", "供水设施", "桥梁"];
+const statusOptions = ["正常", "启用", "停用", "维修中", "预警"];
+
+const data = reactive({
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    networkCode: undefined,
+    networkName: undefined,
+    networkType: undefined,
+    status: undefined
   },
-  {
-    id: 5, name: "压力传感器E05", deviceId: "PS-005", location: "北环加压站",
-    type: "压力传感器", manufacturer: "华仪科技", installDate: "2024-09-12",
-    maintainer: "孙工", contact: "13800005555", maintainRecord: "无",
-    monitorPoint: "北环节点", status: "active"
-  }
-])
-
-// 搜索参数
-const searchParams = ref({
-  keyword: '',
-  status: '',
-  type: ''
-})
-
-// 分页
-const currentPage = ref(1)
-const pageSize = 5
-
-// 模态框状态
-const detailModalVisible = ref(false)
-const editModalVisible = ref(false)
-const currentDevice = ref(null)
-const isEdit = ref(false)
-const formData = ref({
-  name: '', deviceId: '', location: '', type: '压力传感器',
-  manufacturer: '', installDate: '', maintainer: '', contact: '',
-  maintainRecord: '', monitorPoint: '', status: 'active'
-})
-
-// 过滤后的设备列表
-const filteredDevices = computed(() => {
-  let result = [...devices.value]
-  const { keyword, status, type } = searchParams.value
-
-  if (keyword) {
-    const kw = keyword.toLowerCase()
-    result = result.filter(d =>
-        d.name.toLowerCase().includes(kw) ||
-        d.deviceId.toLowerCase().includes(kw)
-    )
-  }
-  if (status) {
-    result = result.filter(d => d.status === status)
+  form: {},
+  detailForm: {},
+  rules: {
+    networkCode: [{ required: true, message: "设施编码不能为空", trigger: "blur" }],
+    networkName: [{ required: true, message: "设施名称不能为空", trigger: "blur" }],
+    networkType: [{ required: true, message: "设施类型不能为空", trigger: "change" }]
   }
-  if (type) {
-    result = result.filter(d => d.type === type)
+});
+
+const { queryParams, form, detailForm, rules } = toRefs(data);
+
+function createEmptyForm() {
+  return {
+    networkId: undefined,
+    networkCode: undefined,
+    networkName: undefined,
+    networkType: undefined,
+    networkLevel: undefined,
+    managementUnit: undefined,
+    location: undefined,
+    longitude: undefined,
+    latitude: undefined,
+    length: undefined,
+    diameter: undefined,
+    material: undefined,
+    buildDate: undefined,
+    status: "正常",
+    remark: undefined
+  };
+}
+
+function getList() {
+  loading.value = true;
+  listPipeNetwork(queryParams.value)
+    .then((response) => {
+      networkList.value = response.records || [];
+      total.value = response.total || 0;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+function reset() {
+  form.value = createEmptyForm();
+  proxy.resetForm("networkRef");
+}
+
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+function resetQuery() {
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+function handleSelectionChange(selection) {
+  ids.value = selection.map((item) => item.networkId);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+}
+
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "新增管网基础信息";
+}
+
+function handleUpdate(row) {
+  reset();
+  const networkId = row?.networkId || ids.value[0];
+  if (!networkId) {
+    return;
   }
-  return result
-})
-
-// 分页后的设备列表
-const paginatedDevices = computed(() => {
-  const start = (currentPage.value - 1) * pageSize
-  return filteredDevices.value.slice(start, start + pageSize)
-})
-
-// 总页数
-const totalPages = computed(() => {
-  return Math.ceil(filteredDevices.value.length / pageSize)
-})
-
-// 状态辅助函数
-const getStatusClass = (status) => {
-  const map = {
-    active: 'status-active',
-    inactive: 'status-inactive',
-    maintenance: 'status-maintenance'
-  }
-  return map[status] || ''
+  getPipeNetwork(networkId).then((response) => {
+    form.value = { ...createEmptyForm(), ...(response.data || {}) };
+    open.value = true;
+    title.value = "修改管网基础信息";
+  });
 }
 
-const getStatusText = (status) => {
-  const map = {
-    active: '● 启用',
-    inactive: '● 停用',
-    maintenance: '● 维护中'
-  }
-  return map[status] || status
+function handleView(row) {
+  getPipeNetwork(row.networkId).then((response) => {
+    detailForm.value = { ...createEmptyForm(), ...(response.data || {}) };
+    detailOpen.value = true;
+  });
 }
 
-// 搜索操作
-const handleSearch = () => {
-  currentPage.value = 1
+function cancel() {
+  open.value = false;
+  reset();
 }
 
-const handleReset = () => {
-  searchParams.value = { keyword: '', status: '', type: '' }
-  currentPage.value = 1
-}
-
-// 设备详情
-const showDetail = (device) => {
-  currentDevice.value = device
-  detailModalVisible.value = true
-}
-
-const closeDetailModal = () => {
-  detailModalVisible.value = false
-  currentDevice.value = null
-}
-
-const openEditFromDetail = () => {
-  closeDetailModal()
-  openEditModal(currentDevice.value)
-}
-
-// 新增/编辑设备
-const openAddModal = () => {
-  isEdit.value = false
-  formData.value = {
-    name: '', deviceId: '', location: '', type: '压力传感器',
-    manufacturer: '', installDate: '', maintainer: '', contact: '',
-    maintainRecord: '', monitorPoint: '', status: 'active'
-  }
-  editModalVisible.value = true
-}
-
-const openEditModal = (device) => {
-  isEdit.value = true
-  formData.value = { ...device }
-  editModalVisible.value = true
-}
-
-const closeEditModal = () => {
-  editModalVisible.value = false
-}
-
-const saveDevice = () => {
-  if (!formData.value.name || !formData.value.deviceId) {
-    alert("设备名称和设备ID不能为空")
-    return
-  }
-
-  if (isEdit.value) {
-    const index = devices.value.findIndex(d => d.id === formData.value.id)
-    if (index !== -1) {
-      devices.value[index] = { ...formData.value }
+function submitForm() {
+  proxy.$refs.networkRef.validate((valid) => {
+    if (!valid) {
+      return;
     }
-    alert("设备信息已更新")
-  } else {
-    const newId = Math.max(...devices.value.map(d => d.id), 0) + 1
-    devices.value.push({ ...formData.value, id: newId })
-    alert("设备已添加")
+    const request = form.value.networkId ? updatePipeNetwork(form.value) : addPipeNetwork(form.value);
+    request.then(() => {
+      proxy.$modal.msgSuccess(form.value.networkId ? "修改成功" : "新增成功");
+      open.value = false;
+      getList();
+    });
+  });
+}
+
+function handleDelete(row) {
+  const deleteIds = row?.networkId ? [row.networkId] : ids.value;
+  if (!deleteIds.length) {
+    return;
   }
-  closeEditModal()
-  handleReset()
-}
-
-// 删除设备
-const deleteDevice = (device) => {
-  if (confirm(`确定删除设备 "${device.name}" 吗?`)) {
-    const index = devices.value.findIndex(d => d.id === device.id)
-    if (index !== -1) {
-      devices.value.splice(index, 1)
-    }
-    handleReset()
-    alert("设备已删除")
-  }
-}
-
-// 切换设备状态
-const toggleDeviceStatus = (device) => {
-  const newStatus = device.status === 'active' ? 'inactive' : 'active'
-  device.status = newStatus
-  alert(`设备状态已切换为${newStatus === 'active' ? '启用' : '停用'}`)
-}
-
-// 测试验证设备
-const testDevice = (device) => {
-  // 模拟测试通信
-  setTimeout(() => {
-    const success = Math.random() > 0.2
-    if (success) {
-      alert(`✅ 设备测试成功\n设备名称: ${device.name}\n设备ID: ${device.deviceId}\n通信正常,数据采集正常。`)
-    } else {
-      alert(`⚠️ 设备测试失败\n设备名称: ${device.name}\n请检查设备连接或联系维护人员。`)
-    }
-  }, 300)
-}
-
-// 批量测试验证
-const batchTest = () => {
-  const activeDevices = devices.value.filter(d => d.status === 'active')
-  if (activeDevices.length === 0) {
-    alert("没有启用的设备可测试")
-    return
-  }
-
-  let successCount = 0
-  let failCount = 0
-
-  activeDevices.forEach(device => {
-    const success = Math.random() > 0.2
-    if (success) successCount++
-    else failCount++
-  })
-
-  alert(`批量测试完成\n共测试 ${activeDevices.length} 台设备,成功 ${successCount} 台,失败 ${failCount} 台。`)
-}
+  proxy.$modal
+    .confirm(`是否确认删除选中的 ${deleteIds.length} 条管网设施数据?`)
+    .then(() => Promise.all(deleteIds.map((id) => delPipeNetwork(id))))
+    .then(() => {
+      proxy.$modal.msgSuccess("删除成功");
+      getList();
+    });
+}
+
+onMounted(() => {
+  reset();
+  detailForm.value = createEmptyForm();
+  getList();
+});
 </script>
-
-<style scoped>
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-}
-
-.prototype-container {
-  max-width: 1600px;
-  margin: 0 auto;
-  background: #ffffff;
-  border-radius: 28px;
-  box-shadow: 0 20px 35px -12px rgba(0, 0, 0, 0.15);
-  overflow: hidden;
-  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
-}
-
-/* 头部 */
-.header {
-  background: #0a2b3c;
-  padding: 18px 28px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 12px;
-  border-bottom: 3px solid #3498db;
-}
-
-.logo h2 {
-  color: white;
-  font-weight: 600;
-  font-size: 1.4rem;
-}
-
-.logo p {
-  color: #bdd8e8;
-  font-size: 0.7rem;
-}
-
-.badge-device {
-  background: #3498db;
-  padding: 6px 18px;
-  border-radius: 30px;
-  color: white;
-  font-weight: 500;
-  font-size: 0.8rem;
-}
-
-/* 主体布局 */
-.main-layout {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.left-panel {
-  width: 320px;
-  background: #f9fbfd;
-  border-right: 1px solid #e2edf2;
-  padding: 20px 18px;
-  display: flex;
-  flex-direction: column;
-  gap: 20px;
-}
-
-.right-panel {
-  flex: 1;
-  background: #ffffff;
-  padding: 20px 24px;
-  min-width: 600px;
-}
-
-/* 卡片样式 */
-.card {
-  background: white;
-  border-radius: 20px;
-  border: 1px solid #e6edf3;
-  overflow: hidden;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
-}
-
-.card-header {
-  background: #f9fafc;
-  padding: 14px 18px;
-  border-bottom: 1px solid #eef2f6;
-  font-weight: 700;
-  font-size: 0.9rem;
-  color: #1d5a78;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.card-body {
-  padding: 16px;
-}
-
-/* 表单 */
-.form-group {
-  margin-bottom: 16px;
-}
-
-.form-label {
-  font-size: 0.7rem;
-  font-weight: 600;
-  margin-bottom: 6px;
-  display: block;
-  color: #2c5a72;
-}
-
-.form-input, .form-select, .form-textarea {
-  width: 100%;
-  padding: 8px 12px;
-  border-radius: 12px;
-  border: 1px solid #cbdde6;
-  font-size: 0.75rem;
-  background: white;
-}
-
-.search-group {
-  display: flex;
-  gap: 8px;
-}
-
-.btn-primary {
-  background: #3498db;
-  border: none;
-  color: white;
-  padding: 8px 16px;
-  border-radius: 30px;
-  font-weight: 600;
-  font-size: 0.75rem;
-  cursor: pointer;
-  transition: 0.2s;
-}
-
-.btn-primary:hover {
-  background: #2980b9;
-}
-
-.btn-outline {
-  background: white;
-  border: 1px solid #3498db;
-  color: #3498db;
-  padding: 6px 12px;
-  border-radius: 30px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-/* 表格 */
-.table-wrapper {
-  overflow-x: auto;
-  border-radius: 16px;
-  border: 1px solid #eef2f6;
-  margin-bottom: 20px;
-}
-
-.data-table {
-  width: 100%;
-  border-collapse: collapse;
-  font-size: 0.7rem;
-}
-
-.data-table th {
-  background: #f8fafc;
-  padding: 10px 8px;
-  text-align: left;
-  font-weight: 600;
-  color: #2c5a72;
-  border-bottom: 1px solid #e2edf2;
-}
-
-.data-table td {
-  padding: 8px;
-  border-bottom: 1px solid #f0f4f7;
-}
-
-.data-table tr:hover {
-  background: #fafeff;
-}
-
-.status-badge {
-  display: inline-block;
-  padding: 2px 8px;
-  border-radius: 20px;
-  font-size: 0.65rem;
-}
-
-.status-active {
-  background: #d5f5e3;
-  color: #27ae60;
-}
-
-.status-inactive {
-  background: #fadbd8;
-  color: #e74c3c;
-}
-
-.status-maintenance {
-  background: #fdebd0;
-  color: #e67e22;
-}
-
-.action-icons {
-  display: flex;
-  gap: 8px;
-}
-
-.icon-btn {
-  background: none;
-  border: none;
-  cursor: pointer;
-  font-size: 1rem;
-  padding: 4px;
-  border-radius: 6px;
-  transition: 0.1s;
-}
-
-.icon-btn:hover {
-  background: #eef2f5;
-}
-
-/* 分页 */
-.pagination {
-  display: flex;
-  justify-content: flex-end;
-  gap: 8px;
-  margin-top: 12px;
-}
-
-.page-btn {
-  background: white;
-  border: 1px solid #cbdde6;
-  padding: 4px 10px;
-  border-radius: 20px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-.page-btn.active {
-  background: #3498db;
-  color: white;
-  border-color: #3498db;
-}
-
-/* 模态框 */
-.modal-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.5);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.modal-content {
-  background: white;
-  border-radius: 24px;
-  width: 500px;
-  max-width: 90%;
-  padding: 24px;
-  max-height: 85vh;
-  overflow-y: auto;
-}
-
-.detail-row {
-  margin-bottom: 12px;
-  font-size: 0.75rem;
-}
-
-.detail-label {
-  font-weight: 600;
-  width: 110px;
-  display: inline-block;
-  color: #2c5a72;
-}
-</style>

+ 517 - 813
src/views/subSystem/pipeNetwork/pdeviceInform/PequipmentLed.vue

@@ -1,855 +1,559 @@
-<!--物联感知设备管理-->
+<!-- 物联感知设备管理 -->
 <template>
-  <div class="prototype-container">
-
-    <div class="main-layout">
-      <!-- 左侧:查询与统计面板 -->
-      <div class="left-panel">
-        <div class="card">
-          <div class="card-header">🔍 设施查询</div>
-          <div class="card-body">
-            <div class="form-group">
-              <label class="form-label">设施名称</label>
-              <input
-                  type="text"
-                  v-model="searchParams.name"
-                  class="form-input"
-                  placeholder="模糊匹配"
-                  @keyup.enter="handleSearch"
-              >
-            </div>
-            <div class="form-group">
-              <label class="form-label">设施类型</label>
-              <select v-model="searchParams.type" class="form-select">
-                <option value="">全部</option>
-                <option value="管网路线">管网路线</option>
-                <option value="燃气设施">燃气设施</option>
-                <option value="排水设施">排水设施</option>
-                <option value="供水设施">供水设施</option>
-                <option value="桥梁">桥梁</option>
-              </select>
-            </div>
-            <div class="form-group">
-              <label class="form-label">设施等级</label>
-              <select v-model="searchParams.level" class="form-select">
-                <option value="">全部</option>
-                <option value="一级">一级</option>
-                <option value="二级">二级</option>
-                <option value="三级">三级</option>
-              </select>
-            </div>
-            <div class="form-group">
-              <label class="form-label">管养单位</label>
-              <input
-                  type="text"
-                  v-model="searchParams.unit"
-                  class="form-input"
-                  placeholder="管养单位"
-              >
-            </div>
-            <div class="search-group">
-              <button @click="handleSearch" class="btn-primary">🔍 查询</button>
-              <button @click="handleReset" class="btn-outline">重置</button>
-            </div>
-          </div>
+  <div class="app-container">
+    <el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch">
+      <el-form-item label="设备编码" prop="equipmentCode">
+        <el-input
+          v-model="queryParams.equipmentCode"
+          placeholder="请输入设备编码"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="设备名称" prop="equipmentName">
+        <el-input
+          v-model="queryParams.equipmentName"
+          placeholder="请输入设备名称"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="设备型号" prop="equipmentModel">
+        <el-input
+          v-model="queryParams.equipmentModel"
+          placeholder="请输入设备型号"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="制造商" prop="manufacturer">
+        <el-input
+          v-model="queryParams.manufacturer"
+          placeholder="请输入制造商"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
+          修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
+          删除
+        </el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="equipmentList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="设备编码" align="center" prop="equipmentCode" min-width="140" />
+      <el-table-column label="设备名称" align="center" prop="equipmentName" min-width="160" show-overflow-tooltip />
+      <el-table-column label="设备型号" align="center" prop="equipmentModel" min-width="120" />
+      <el-table-column label="设备类型" align="center" min-width="140">
+        <template #default="scope">
+          {{ typeNameMap[scope.row.equipmentTypeId] || scope.row.equipmentTypeId || "-" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="当前状态" align="center" width="110">
+        <template #default="scope">
+          <el-tag :type="getStatusTagType(getRowStatus(scope.row.equipmentId))">
+            {{ getStatusText(getRowStatus(scope.row.equipmentId)) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="制造商" align="center" prop="manufacturer" min-width="140" show-overflow-tooltip />
+      <el-table-column label="设备位置" align="center" prop="equipmentLocation" min-width="180" show-overflow-tooltip />
+      <el-table-column label="维护人员" align="center" prop="maintainer" min-width="100" />
+      <el-table-column label="操作" align="center" width="300" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
+          <el-button link type="warning" icon="Tools" @click="openStatusDialog(scope.row)">状态维护</el-button>
+          <el-button link type="success" icon="Aim" @click="openTestDialog(scope.row)">测试验证</el-button>
+          <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog :title="title" v-model="open" width="860px" append-to-body>
+      <el-form ref="equipmentRef" :model="form" :rules="rules" label-width="110px">
+        <el-row :gutter="16">
+          <el-col :span="12">
+            <el-form-item label="设备编码" prop="equipmentCode">
+              <el-input v-model="form.equipmentCode" placeholder="请输入设备编码" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设备名称" prop="equipmentName">
+              <el-input v-model="form.equipmentName" placeholder="请输入设备名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设备型号" prop="equipmentModel">
+              <el-input v-model="form.equipmentModel" placeholder="请输入设备型号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="设备类型" prop="equipmentTypeId">
+              <el-select v-model="form.equipmentTypeId" placeholder="请选择设备类型" style="width: 100%">
+                <el-option
+                  v-for="item in equipmentTypeOptions"
+                  :key="item.typeId"
+                  :label="item.typeName"
+                  :value="item.typeId"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="制造商" prop="manufacturer">
+              <el-input v-model="form.manufacturer" placeholder="请输入制造商" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="生产日期" prop="productionDate">
+              <el-date-picker
+                v-model="form.productionDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择生产日期"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="规格参数" prop="equipmentSpec">
+              <el-input v-model="form.equipmentSpec" placeholder="请输入设备规格参数" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="资产价值(元)" prop="assetValue">
+              <el-input-number v-model="form.assetValue" :precision="2" :step="100" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="使用年限(年)" prop="useLife">
+              <el-input-number v-model="form.useLife" :precision="0" :step="1" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="设备位置" prop="equipmentLocation">
+              <el-input v-model="form.equipmentLocation" placeholder="请输入设备位置" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="经度" prop="longitude">
+              <el-input-number v-model="form.longitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="纬度" prop="latitude">
+              <el-input-number v-model="form.latitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="安装时间" prop="installTime">
+              <el-date-picker
+                v-model="form.installTime"
+                type="datetime"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                placeholder="请选择安装时间"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="维护人员" prop="maintainer">
+              <el-input v-model="form.maintainer" placeholder="请输入维护人员" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="联系电话" prop="maintainerPhone">
+              <el-input v-model="form.maintainerPhone" placeholder="请输入联系电话" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
         </div>
-
-        <div class="card">
-          <div class="card-header">📊 分类统计</div>
-          <div class="card-body">
-            <div v-for="item in typeStats" :key="item.type" class="stat-item">
-              <span class="stat-label">{{ item.type }}</span>
-              <span class="stat-value">{{ item.count }}</span>
-              <div class="stat-bar">
-                <div class="stat-fill" :style="{ width: getStatPercent(item.count) + '%' }"></div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-
-      <!-- 右侧:设施列表 -->
-      <div class="right-panel">
-        <div class="card">
-          <div class="card-header">
-            📋 基础设施列表
-            <div class="header-actions">
-              <button @click="openAddModal" class="btn-primary btn-sm">+ 新增设施</button>
-              <button @click="handleImport" class="btn-outline btn-sm">📂 导入</button>
-              <button @click="handleExport" class="btn-outline btn-sm">📎 导出</button>
-            </div>
-          </div>
-          <div class="card-body">
-            <div class="table-wrapper">
-              <table class="data-table">
-                <thead>
-                <tr>
-                  <th>设施名称</th>
-                  <th>设施类型</th>
-                  <th>设施等级</th>
-                  <th>设施编码</th>
-                  <th>管养单位</th>
-                  <th>位置</th>
-                  <th>状态</th>
-                  <th>操作</th>
-                </tr>
-                </thead>
-                <tbody>
-                <tr v-if="paginatedList.length === 0">
-                  <td colspan="8" style="text-align:center;">暂无数据</td>
-                </tr>
-                <tr v-for="item in paginatedList" :key="item.id">
-                  <td><strong>{{ item.name }}</strong></td>
-                  <td><span class="type-badge" :class="getTypeClass(item.type)">{{ item.type }}</span></td>
-                  <td>{{ item.level || '-' }}</td>
-                  <td><code>{{ item.code }}</code></td>
-                  <td>{{ item.maintenanceUnit || '-' }}</td>
-                  <td>{{ item.location || '-' }}</td>
-                  <td>
-                      <span class="status-badge" :class="getStatusClass(item.status)">
-                        {{ getStatusText(item.status) }}
-                      </span>
-                  </td>
-                  <td class="action-icons">
-                    <button class="icon-btn" @click="viewDetail(item)" title="查看">👁️</button>
-                    <button class="icon-btn" @click="openEditModal(item)" title="编辑">✏️</button>
-                    <button class="icon-btn" @click="deleteItem(item)" title="删除">🗑️</button>
-                  </td>
-                </tr>
-                </tbody>
-              </table>
-            </div>
-            <div class="pagination" v-if="totalPages > 1">
-              <button
-                  v-for="page in totalPages"
-                  :key="page"
-                  class="page-btn"
-                  :class="{ active: currentPage === page }"
-                  @click="currentPage = page"
-              >
-                {{ page }}
-              </button>
-            </div>
-          </div>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="设备详情" v-model="detailOpen" width="980px" append-to-body>
+      <el-descriptions :column="2" border v-if="detailForm.equipmentInfo">
+        <el-descriptions-item label="设备编码">{{ detailForm.equipmentInfo.equipmentCode || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设备名称">{{ detailForm.equipmentInfo.equipmentName || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设备型号">{{ detailForm.equipmentInfo.equipmentModel || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="设备类型">{{ detailForm.typeInfo?.typeName || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="制造商">{{ detailForm.equipmentInfo.manufacturer || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="当前状态">{{ getStatusText(detailForm.statusInfo?.currentStatus) }}</el-descriptions-item>
+        <el-descriptions-item label="设备位置" :span="2">{{ detailForm.equipmentInfo.equipmentLocation || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="规格参数" :span="2">{{ detailForm.equipmentInfo.equipmentSpec || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="维护人员">{{ detailForm.equipmentInfo.maintainer || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="联系电话">{{ detailForm.equipmentInfo.maintainerPhone || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="安装时间">{{ detailForm.equipmentInfo.installTime || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="生产日期">{{ detailForm.equipmentInfo.productionDate || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ detailForm.equipmentInfo.remark || "-" }}</el-descriptions-item>
+      </el-descriptions>
+
+      <el-divider content-position="left">关联监测点</el-divider>
+      <el-table :data="detailForm.pointRelList || []" border>
+        <el-table-column label="监测点ID" prop="pointId" min-width="200" show-overflow-tooltip />
+        <el-table-column label="设备ID" prop="equipmentId" min-width="200" show-overflow-tooltip />
+      </el-table>
+
+      <el-divider content-position="left">测试记录</el-divider>
+      <el-table :data="detailForm.testList || []" border>
+        <el-table-column label="测试时间" prop="testTime" min-width="170" />
+        <el-table-column label="测试类型" prop="testType" min-width="120" />
+        <el-table-column label="测试结果" prop="testResult" width="100" />
+        <el-table-column label="测试人员" prop="testUser" width="120" />
+        <el-table-column label="测试详情" prop="testDetail" min-width="220" show-overflow-tooltip />
+      </el-table>
+    </el-dialog>
+
+    <el-dialog title="设备状态维护" v-model="statusOpen" width="420px" append-to-body>
+      <el-form label-width="90px">
+        <el-form-item label="设备名称">
+          <span>{{ currentRow.equipmentName || "-" }}</span>
+        </el-form-item>
+        <el-form-item label="当前状态">
+          <el-select v-model="statusForm.currentStatus" style="width: 100%">
+            <el-option
+              v-for="item in equipmentStatusOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitStatus">确 定</el-button>
+          <el-button @click="statusOpen = false">取 消</el-button>
         </div>
-      </div>
-    </div>
-
-    <!-- 详情查看模态框 -->
-    <div v-if="detailModalVisible" class="modal-overlay" @click.self="closeDetailModal">
-      <div class="modal-content">
-        <h3 style="margin-bottom:16px;">📋 设施详细信息</h3>
-        <div class="detail-row"><span class="detail-label">设施名称:</span>{{ currentItem?.name }}</div>
-        <div class="detail-row"><span class="detail-label">设施类型:</span>{{ currentItem?.type }}</div>
-        <div class="detail-row"><span class="detail-label">设施等级:</span>{{ currentItem?.level || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">设施编码:</span>{{ currentItem?.code }}</div>
-        <div class="detail-row"><span class="detail-label">管养单位:</span>{{ currentItem?.maintenanceUnit || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">具体位置:</span>{{ currentItem?.location || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">建设年份:</span>{{ currentItem?.buildYear || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">设计年限:</span>{{ currentItem?.designLife || '-' }} 年</div>
-        <div class="detail-row"><span class="detail-label">上次巡检:</span>{{ currentItem?.lastInspection || '-' }}</div>
-        <div class="detail-row"><span class="detail-label">设施状态:</span>
-          <span class="status-badge" :class="getStatusClass(currentItem?.status)">
-            {{ getStatusText(currentItem?.status) }}
-          </span>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="设备测试验证" v-model="testOpen" width="520px" append-to-body>
+      <el-form ref="testRef" :model="testForm" label-width="90px">
+        <el-form-item label="设备名称">
+          <span>{{ currentRow.equipmentName || "-" }}</span>
+        </el-form-item>
+        <el-form-item label="测试类型">
+          <el-input v-model="testForm.testType" placeholder="例如:通信测试" />
+        </el-form-item>
+        <el-form-item label="测试人员">
+          <el-input v-model="testForm.testUser" placeholder="请输入测试人员" />
+        </el-form-item>
+        <el-form-item label="测试详情">
+          <el-input v-model="testForm.testDetail" type="textarea" :rows="4" placeholder="请输入测试详情" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitTest">确 定</el-button>
+          <el-button @click="testOpen = false">取 消</el-button>
         </div>
-        <div class="detail-row"><span class="detail-label">备注:</span>{{ currentItem?.remark || '-' }}</div>
-        <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-          <button @click="closeDetailModal" class="btn-outline">关闭</button>
-          <button @click="openEditFromDetail" class="btn-primary">编辑设施</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 新增/编辑模态框 -->
-    <div v-if="editModalVisible" class="modal-overlay" @click.self="closeEditModal">
-      <div class="modal-content" style="width:560px;">
-        <h3 style="margin-bottom:16px;">{{ isEdit ? '编辑设施信息' : '新增设施' }}</h3>
-        <form @submit.prevent="saveItem">
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">设施名称 *</label>
-              <input v-model="formData.name" class="form-input" required>
-            </div>
-            <div class="form-group half">
-              <label class="form-label">设施类型 *</label>
-              <select v-model="formData.type" class="form-select" required>
-                <option value="管网路线">管网路线</option>
-                <option value="燃气设施">燃气设施</option>
-                <option value="排水设施">排水设施</option>
-                <option value="供水设施">供水设施</option>
-                <option value="桥梁">桥梁</option>
-              </select>
-            </div>
-          </div>
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">设施等级</label>
-              <select v-model="formData.level" class="form-select">
-                <option value="">无</option>
-                <option value="一级">一级</option>
-                <option value="二级">二级</option>
-                <option value="三级">三级</option>
-              </select>
-            </div>
-            <div class="form-group half">
-              <label class="form-label">设施编码 *</label>
-              <input v-model="formData.code" class="form-input" required placeholder="唯一编码">
-            </div>
-          </div>
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">管养单位</label>
-              <input v-model="formData.maintenanceUnit" class="form-input" placeholder="管养单位">
-            </div>
-            <div class="form-group half">
-              <label class="form-label">具体位置</label>
-              <input v-model="formData.location" class="form-input" placeholder="经纬度或地址">
-            </div>
-          </div>
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">建设年份</label>
-              <input v-model="formData.buildYear" type="number" class="form-input" placeholder="YYYY">
-            </div>
-            <div class="form-group half">
-              <label class="form-label">设计年限(年)</label>
-              <input v-model="formData.designLife" type="number" class="form-input" placeholder="设计使用年限">
-            </div>
-          </div>
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">上次巡检</label>
-              <input v-model="formData.lastInspection" type="date" class="form-input">
-            </div>
-            <div class="form-group half">
-              <label class="form-label">设施状态</label>
-              <select v-model="formData.status" class="form-select">
-                <option value="normal">正常</option>
-                <option value="warning">需关注</option>
-                <option value="danger">存在风险</option>
-                <option value="maintenance">维修中</option>
-              </select>
-            </div>
-          </div>
-          <div class="form-group">
-            <label class="form-label">备注</label>
-            <textarea v-model="formData.remark" rows="2" class="form-textarea" placeholder="其他说明"></textarea>
-          </div>
-          <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-            <button type="button" @click="closeEditModal" class="btn-outline">取消</button>
-            <button type="submit" class="btn-primary">保存</button>
-          </div>
-        </form>
-      </div>
-    </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
-
-// 设施数据类型定义
-const facilities = ref([
-  {
-    id: 1, name: "城东燃气管网", type: "燃气设施", level: "一级", code: "GAS-001",
-    maintenanceUnit: "市燃气集团", location: "城东区龙蟠路", buildYear: "2018",
-    designLife: "30", lastInspection: "2025-03-15", status: "normal", remark: "主要供气干线"
-  },
-  {
-    id: 2, name: "城南雨水管网", type: "排水设施", level: "二级", code: "DRN-002",
-    maintenanceUnit: "市政排水公司", location: "城南新区", buildYear: "2020",
-    designLife: "25", lastInspection: "2025-02-10", status: "normal", remark: ""
+import { computed, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
+import {
+  addEquipment,
+  delEquipment,
+  getEquipment,
+  getEquipmentDetail,
+  listEquipment,
+  listEquipmentStatusAll,
+  listEquipmentTypeAll,
+  testEquipment,
+  updateEquipment,
+  updateEquipmentStatus
+} from "@/api/pipeNetwork/pdeviceInform";
+
+const { proxy } = getCurrentInstance();
+
+const equipmentList = ref([]);
+const equipmentTypeOptions = ref([]);
+const equipmentStatusList = ref([]);
+const loading = ref(false);
+const open = ref(false);
+const detailOpen = ref(false);
+const statusOpen = ref(false);
+const testOpen = ref(false);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+const currentRow = ref({});
+
+const equipmentStatusOptions = [
+  { label: "在用", value: 1 },
+  { label: "闲置", value: 2 },
+  { label: "维修", value: 3 },
+  { label: "报废", value: 4 },
+  { label: "待入库", value: 5 }
+];
+
+const typeNameMap = computed(() => {
+  return equipmentTypeOptions.value.reduce((acc, item) => {
+    acc[item.typeId] = item.typeName;
+    return acc;
+  }, {});
+});
+
+const statusMap = computed(() => {
+  return equipmentStatusList.value.reduce((acc, item) => {
+    acc[item.equipmentId] = item;
+    return acc;
+  }, {});
+});
+
+const data = reactive({
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    equipmentCode: undefined,
+    equipmentName: undefined,
+    equipmentModel: undefined,
+    manufacturer: undefined
   },
-  {
-    id: 3, name: "城北供水主管", type: "供水设施", level: "一级", code: "WTR-003",
-    maintenanceUnit: "水务集团", location: "城北大道", buildYear: "2015",
-    designLife: "30", lastInspection: "2025-01-20", status: "warning", remark: "部分管段老化"
+  form: {},
+  detailForm: {},
+  statusForm: {
+    currentStatus: 1
   },
-  {
-    id: 4, name: "江汉大桥", type: "桥梁", level: "一级", code: "BRG-004",
-    maintenanceUnit: "市桥梁管理处", location: "江汉路与长江大道交叉口", buildYear: "2010",
-    designLife: "50", lastInspection: "2024-12-05", status: "normal", remark: "定期维护中"
+  testForm: {
+    testType: undefined,
+    testDetail: undefined,
+    testUser: undefined
   },
-  {
-    id: 5, name: "城西天然气管线", type: "燃气设施", level: "二级", code: "GAS-005",
-    maintenanceUnit: "市燃气集团", location: "城西工业区", buildYear: "2019",
-    designLife: "30", lastInspection: "2025-02-28", status: "normal", remark: ""
-  },
-  {
-    id: 6, name: "城北排水管网", type: "排水设施", level: "三级", code: "DRN-006",
-    maintenanceUnit: "市政排水公司", location: "北环路", buildYear: "2021",
-    designLife: "25", lastInspection: "2025-03-01", status: "normal", remark: ""
-  },
-  {
-    id: 7, name: "东区供水管网", type: "供水设施", level: "二级", code: "WTR-007",
-    maintenanceUnit: "水务集团", location: "东开发区", buildYear: "2017",
-    designLife: "30", lastInspection: "2024-11-15", status: "maintenance", remark: "管道维修中"
-  },
-  {
-    id: 8, name: "南湖大桥", type: "桥梁", level: "二级", code: "BRG-008",
-    maintenanceUnit: "市桥梁管理处", location: "南湖路", buildYear: "2012",
-    designLife: "50", lastInspection: "2024-10-20", status: "warning", remark: "桥面需修复"
+  rules: {
+    equipmentCode: [{ required: true, message: "设备编码不能为空", trigger: "blur" }],
+    equipmentName: [{ required: true, message: "设备名称不能为空", trigger: "blur" }],
+    equipmentTypeId: [{ required: true, message: "设备类型不能为空", trigger: "change" }]
   }
-])
-
-// 搜索参数
-const searchParams = ref({
-  name: '',
-  type: '',
-  level: '',
-  unit: ''
-})
-
-// 分页
-const currentPage = ref(1)
-const pageSize = 8
-
-// 模态框状态
-const detailModalVisible = ref(false)
-const editModalVisible = ref(false)
-const currentItem = ref(null)
-const isEdit = ref(false)
-const formData = ref({
-  name: '', type: '管网路线', level: '', code: '',
-  maintenanceUnit: '', location: '', buildYear: '', designLife: '',
-  lastInspection: '', status: 'normal', remark: ''
-})
-
-// 计算总数
-const totalCount = computed(() => facilities.value.length)
-
-// 分类统计
-const typeStats = computed(() => {
-  const types = ['管网路线', '燃气设施', '排水设施', '供水设施', '桥梁']
-  return types.map(type => ({
-    type,
-    count: facilities.value.filter(f => f.type === type).length
-  }))
-})
-
-// 获取统计百分比
-const getStatPercent = (count) => {
-  if (totalCount.value === 0) return 0
-  return (count / totalCount.value) * 100
-}
-
-// 过滤后的列表
-const filteredList = computed(() => {
-  let result = [...facilities.value]
-  const { name, type, level, unit } = searchParams.value
-
-  if (name) {
-    const kw = name.toLowerCase()
-    result = result.filter(f => f.name.toLowerCase().includes(kw))
-  }
-  if (type) {
-    result = result.filter(f => f.type === type)
-  }
-  if (level) {
-    result = result.filter(f => f.level === level)
-  }
-  if (unit) {
-    const kw = unit.toLowerCase()
-    result = result.filter(f => f.maintenanceUnit?.toLowerCase().includes(kw))
-  }
-  return result
-})
-
-// 分页后的列表
-const paginatedList = computed(() => {
-  const start = (currentPage.value - 1) * pageSize
-  return filteredList.value.slice(start, start + pageSize)
-})
-
-// 总页数
-const totalPages = computed(() => {
-  return Math.ceil(filteredList.value.length / pageSize)
-})
-
-// 获取类型样式
-const getTypeClass = (type) => {
+});
+
+const { queryParams, form, detailForm, statusForm, testForm, rules } = toRefs(data);
+
+function createEmptyForm() {
+  return {
+    equipmentId: undefined,
+    equipmentCode: undefined,
+    equipmentName: undefined,
+    equipmentModel: undefined,
+    equipmentSpec: undefined,
+    manufacturer: undefined,
+    productionDate: undefined,
+    equipmentTypeId: undefined,
+    assetValue: undefined,
+    useLife: undefined,
+    longitude: undefined,
+    latitude: undefined,
+    equipmentLocation: undefined,
+    installTime: undefined,
+    maintainer: undefined,
+    maintainerPhone: undefined,
+    remark: undefined
+  };
+}
+
+function getRowStatus(equipmentId) {
+  return statusMap.value[equipmentId]?.currentStatus;
+}
+
+function getStatusText(status) {
+  const found = equipmentStatusOptions.find((item) => item.value === status);
+  return found?.label || "未维护";
+}
+
+function getStatusTagType(status) {
   const map = {
-    '管网路线': 'type-pipeline',
-    '燃气设施': 'type-gas',
-    '排水设施': 'type-drain',
-    '供水设施': 'type-water',
-    '桥梁': 'type-bridge'
-  }
-  return map[type] || ''
+    1: "success",
+    2: "info",
+    3: "warning",
+    4: "danger",
+    5: ""
+  };
+  return map[status] || "";
 }
 
-// 状态相关
-const getStatusClass = (status) => {
-  const map = {
-    normal: 'status-normal',
-    warning: 'status-warning',
-    danger: 'status-danger',
-    maintenance: 'status-maintenance'
-  }
-  return map[status] || ''
+function getList() {
+  loading.value = true;
+  listEquipment(queryParams.value)
+    .then((response) => {
+      equipmentList.value = response.records || [];
+      total.value = response.total || 0;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
 }
 
-const getStatusText = (status) => {
-  const map = {
-    normal: '● 正常',
-    warning: '● 需关注',
-    danger: '● 存在风险',
-    maintenance: '● 维修中'
-  }
-  return map[status] || status
+function loadAssistData() {
+  return Promise.all([listEquipmentTypeAll(), listEquipmentStatusAll()]).then(([typeRes, statusRes]) => {
+    equipmentTypeOptions.value = typeRes.data || [];
+    equipmentStatusList.value = statusRes.data || [];
+  });
 }
 
-// 搜索操作
-const handleSearch = () => {
-  currentPage.value = 1
+function reset() {
+  form.value = createEmptyForm();
+  proxy.resetForm("equipmentRef");
 }
 
-const handleReset = () => {
-  searchParams.value = { name: '', type: '', level: '', unit: '' }
-  currentPage.value = 1
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
 }
 
-// 查看详情
-const viewDetail = (item) => {
-  currentItem.value = item
-  detailModalVisible.value = true
+function resetQuery() {
+  proxy.resetForm("queryRef");
+  handleQuery();
 }
 
-const closeDetailModal = () => {
-  detailModalVisible.value = false
-  currentItem.value = null
+function handleSelectionChange(selection) {
+  ids.value = selection.map((item) => item.equipmentId);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
 }
 
-const openEditFromDetail = () => {
-  closeDetailModal()
-  openEditModal(currentItem.value)
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "新增物联感知设备";
 }
 
-// 新增/编辑
-const openAddModal = () => {
-  isEdit.value = false
-  formData.value = {
-    name: '', type: '管网路线', level: '', code: '',
-    maintenanceUnit: '', location: '', buildYear: '', designLife: '',
-    lastInspection: '', status: 'normal', remark: ''
+function handleUpdate(row) {
+  reset();
+  const equipmentId = row?.equipmentId || ids.value[0];
+  if (!equipmentId) {
+    return;
   }
-  editModalVisible.value = true
+  getEquipment(equipmentId).then((response) => {
+    form.value = { ...createEmptyForm(), ...(response.data || {}) };
+    open.value = true;
+    title.value = "修改物联感知设备";
+  });
 }
 
-const openEditModal = (item) => {
-  isEdit.value = true
-  formData.value = { ...item }
-  editModalVisible.value = true
+function handleView(row) {
+  getEquipmentDetail(row.equipmentId).then((response) => {
+    detailForm.value = response.data || {};
+    detailOpen.value = true;
+  });
 }
 
-const closeEditModal = () => {
-  editModalVisible.value = false
+function cancel() {
+  open.value = false;
+  reset();
 }
 
-const saveItem = () => {
-  if (!formData.value.name || !formData.value.type || !formData.value.code) {
-    alert("请填写设施名称、类型和编码")
-    return
-  }
-
-  // 检查编码唯一性(编辑时排除自身)
-  const exists = facilities.value.some(f =>
-      f.code === formData.value.code && f.id !== formData.value.id
-  )
-  if (exists) {
-    alert("设施编码已存在,请使用唯一编码")
-    return
-  }
-
-  if (isEdit.value) {
-    const index = facilities.value.findIndex(f => f.id === formData.value.id)
-    if (index !== -1) {
-      facilities.value[index] = { ...formData.value }
+function submitForm() {
+  proxy.$refs.equipmentRef.validate((valid) => {
+    if (!valid) {
+      return;
     }
-    alert("设施信息已更新")
-  } else {
-    const newId = Math.max(...facilities.value.map(f => f.id), 0) + 1
-    facilities.value.push({ ...formData.value, id: newId })
-    alert("设施已添加")
+    const request = form.value.equipmentId ? updateEquipment(form.value) : addEquipment(form.value);
+    request.then(() => {
+      proxy.$modal.msgSuccess(form.value.equipmentId ? "修改成功" : "新增成功");
+      open.value = false;
+      Promise.all([getList(), loadAssistData()]);
+    });
+  });
+}
+
+function handleDelete(row) {
+  const deleteIds = row?.equipmentId ? [row.equipmentId] : ids.value;
+  if (!deleteIds.length) {
+    return;
   }
-  closeEditModal()
-  handleReset()
-}
-
-// 删除
-const deleteItem = (item) => {
-  if (confirm(`确定删除设施 "${item.name}" 吗?`)) {
-    const index = facilities.value.findIndex(f => f.id === item.id)
-    if (index !== -1) {
-      facilities.value.splice(index, 1)
+  proxy.$modal
+    .confirm(`是否确认删除选中的 ${deleteIds.length} 台设备?`)
+    .then(() => Promise.all(deleteIds.map((id) => delEquipment(id))))
+    .then(() => {
+      proxy.$modal.msgSuccess("删除成功");
+      Promise.all([getList(), loadAssistData()]);
+    });
+}
+
+function openStatusDialog(row) {
+  currentRow.value = row;
+  statusForm.value.currentStatus = getRowStatus(row.equipmentId) || 1;
+  statusOpen.value = true;
+}
+
+function submitStatus() {
+  updateEquipmentStatus(currentRow.value.equipmentId, statusForm.value.currentStatus).then(() => {
+    proxy.$modal.msgSuccess("状态维护成功");
+    statusOpen.value = false;
+    loadAssistData();
+  });
+}
+
+function openTestDialog(row) {
+  currentRow.value = row;
+  testForm.value = {
+    testType: "通信测试",
+    testDetail: undefined,
+    testUser: undefined
+  };
+  testOpen.value = true;
+}
+
+function submitTest() {
+  testEquipment(currentRow.value.equipmentId, testForm.value).then(() => {
+    proxy.$modal.msgSuccess("测试记录已提交");
+    testOpen.value = false;
+    if (detailOpen.value && detailForm.value?.equipmentInfo?.equipmentId === currentRow.value.equipmentId) {
+      handleView(currentRow.value);
     }
-    handleReset()
-    alert("设施已删除")
-  }
+  });
 }
 
-// 导入导出
-const handleImport = () => {
-  alert("📂 导入功能\n支持 Excel/CSV 格式导入管网基础设施数据。\n请准备包含:名称、类型、等级、编码、管养单位等列的文件。")
-}
-
-const handleExport = () => {
-  const headers = ['设施名称', '设施类型', '设施等级', '设施编码', '管养单位', '具体位置', '建设年份', '设计年限', '上次巡检', '设施状态', '备注']
-  const rows = filteredList.value.map(f => [
-    f.name, f.type, f.level || '', f.code, f.maintenanceUnit || '', f.location || '',
-    f.buildYear || '', f.designLife || '', f.lastInspection || '', f.status, f.remark || ''
-  ])
-
-  const csvContent = [headers, ...rows].map(row => row.join(',')).join('\n')
-  const blob = new Blob(["\uFEFF" + csvContent], { type: 'text/csv;charset=utf-8;' })
-  const link = document.createElement('a')
-  link.href = URL.createObjectURL(blob)
-  link.download = `管网基础设施_${new Date().toISOString().slice(0,10)}.csv`
-  link.click()
-  URL.revokeObjectURL(link.href)
-  alert("导出成功!")
-}
+onMounted(() => {
+  reset();
+  Promise.all([getList(), loadAssistData()]);
+});
 </script>
-
-<style scoped>
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-}
-
-.prototype-container {
-  max-width: 1600px;
-  margin: 0 auto;
-  background: #ffffff;
-  border-radius: 28px;
-  box-shadow: 0 20px 35px -12px rgba(0, 0, 0, 0.15);
-  overflow: hidden;
-  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
-}
-
-/* 头部 */
-.header {
-  background: #0a2b3c;
-  padding: 18px 28px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 12px;
-  border-bottom: 3px solid #2ecc71;
-}
-
-.logo h2 {
-  color: white;
-  font-weight: 600;
-  font-size: 1.4rem;
-}
-
-.logo p {
-  color: #bdd8e8;
-  font-size: 0.7rem;
-}
-
-.badge-stats {
-  background: #2ecc71;
-  padding: 6px 18px;
-  border-radius: 30px;
-  color: white;
-  font-weight: 500;
-  font-size: 0.8rem;
-}
-
-/* 主体布局 */
-.main-layout {
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.left-panel {
-  width: 320px;
-  background: #f9fbfd;
-  border-right: 1px solid #e2edf2;
-  padding: 20px 18px;
-  display: flex;
-  flex-direction: column;
-  gap: 20px;
-}
-
-.right-panel {
-  flex: 1;
-  background: #ffffff;
-  padding: 20px 24px;
-  min-width: 600px;
-}
-
-/* 卡片 */
-.card {
-  background: white;
-  border-radius: 20px;
-  border: 1px solid #e6edf3;
-  overflow: hidden;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
-}
-
-.card-header {
-  background: #f9fafc;
-  padding: 14px 18px;
-  border-bottom: 1px solid #eef2f6;
-  font-weight: 700;
-  font-size: 0.9rem;
-  color: #1d5a78;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.card-body {
-  padding: 16px;
-}
-
-/* 表单 */
-.form-group {
-  margin-bottom: 16px;
-}
-
-.form-label {
-  font-size: 0.7rem;
-  font-weight: 600;
-  margin-bottom: 6px;
-  display: block;
-  color: #2c5a72;
-}
-
-.form-input, .form-select, .form-textarea {
-  width: 100%;
-  padding: 8px 12px;
-  border-radius: 12px;
-  border: 1px solid #cbdde6;
-  font-size: 0.75rem;
-  background: white;
-}
-
-.form-row {
-  display: flex;
-  gap: 12px;
-}
-
-.form-row .form-group {
-  flex: 1;
-}
-
-.search-group {
-  display: flex;
-  gap: 8px;
-  margin-top: 8px;
-}
-
-/* 按钮 */
-.btn-primary {
-  background: #2ecc71;
-  border: none;
-  color: white;
-  padding: 8px 16px;
-  border-radius: 30px;
-  font-weight: 600;
-  font-size: 0.75rem;
-  cursor: pointer;
-  transition: 0.2s;
-}
-
-.btn-primary:hover {
-  background: #27ae60;
-}
-
-.btn-outline {
-  background: white;
-  border: 1px solid #2ecc71;
-  color: #2ecc71;
-  padding: 6px 12px;
-  border-radius: 30px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-.btn-sm {
-  padding: 6px 12px;
-  font-size: 0.7rem;
-}
-
-.header-actions {
-  display: flex;
-  gap: 8px;
-}
-
-/* 统计 */
-.stat-item {
-  margin-bottom: 12px;
-}
-
-.stat-label {
-  font-size: 0.7rem;
-  color: #2c5a72;
-  display: inline-block;
-  width: 70px;
-}
-
-.stat-value {
-  font-size: 0.75rem;
-  font-weight: 600;
-  color: #2ecc71;
-  margin-left: 8px;
-}
-
-.stat-bar {
-  margin-top: 4px;
-  background: #e2e9ef;
-  border-radius: 10px;
-  height: 6px;
-  overflow: hidden;
-}
-
-.stat-fill {
-  background: #2ecc71;
-  height: 100%;
-  border-radius: 10px;
-  width: 0%;
-}
-
-/* 表格 */
-.table-wrapper {
-  overflow-x: auto;
-  border-radius: 16px;
-  border: 1px solid #eef2f6;
-  margin-bottom: 20px;
-}
-
-.data-table {
-  width: 100%;
-  border-collapse: collapse;
-  font-size: 0.7rem;
-}
-
-.data-table th {
-  background: #f8fafc;
-  padding: 10px 8px;
-  text-align: left;
-  font-weight: 600;
-  color: #2c5a72;
-  border-bottom: 1px solid #e2edf2;
-}
-
-.data-table td {
-  padding: 8px;
-  border-bottom: 1px solid #f0f4f7;
-}
-
-.data-table tr:hover {
-  background: #fafeff;
-}
-
-/* 类型标签 */
-.type-badge {
-  display: inline-block;
-  padding: 2px 8px;
-  border-radius: 20px;
-  font-size: 0.65rem;
-}
-
-.type-pipeline { background: #e8f4fd; color: #2980b9; }
-.type-gas { background: #fef3e2; color: #e67e22; }
-.type-drain { background: #e0f2f1; color: #16a085; }
-.type-water { background: #e3f2fd; color: #2196f3; }
-.type-bridge { background: #f3e5f5; color: #9b59b6; }
-
-/* 状态标签 */
-.status-badge {
-  display: inline-block;
-  padding: 2px 8px;
-  border-radius: 20px;
-  font-size: 0.65rem;
-}
-
-.status-normal { background: #d5f5e3; color: #27ae60; }
-.status-warning { background: #fdebd0; color: #e67e22; }
-.status-danger { background: #fadbd8; color: #e74c3c; }
-.status-maintenance { background: #e8daef; color: #8e44ad; }
-
-/* 分页 */
-.pagination {
-  display: flex;
-  justify-content: flex-end;
-  gap: 8px;
-  margin-top: 12px;
-}
-
-.page-btn {
-  background: white;
-  border: 1px solid #cbdde6;
-  padding: 4px 10px;
-  border-radius: 20px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-.page-btn.active {
-  background: #2ecc71;
-  color: white;
-  border-color: #2ecc71;
-}
-
-/* 模态框 */
-.modal-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.5);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.modal-content {
-  background: white;
-  border-radius: 24px;
-  width: 500px;
-  max-width: 90%;
-  padding: 24px;
-  max-height: 85vh;
-  overflow-y: auto;
-}
-
-.detail-row {
-  margin-bottom: 12px;
-  font-size: 0.75rem;
-}
-
-.detail-label {
-  font-weight: 600;
-  width: 100px;
-  display: inline-block;
-  color: #2c5a72;
-}
-
-.action-icons {
-  display: flex;
-  gap: 8px;
-}
-
-.icon-btn {
-  background: none;
-  border: none;
-  cursor: pointer;
-  font-size: 1rem;
-  padding: 4px;
-  border-radius: 6px;
-}
-
-.icon-btn:hover {
-  background: #eef2f5;
-}
-</style>

+ 496 - 952
src/views/subSystem/pipeNetwork/pdeviceInform/PkeyPoints.vue

@@ -1,979 +1,523 @@
-<!--关键监控点位管理-->
+<!-- 关键监控点位管理 -->
 <template>
-  <div class="prototype-container">
-    <div class="main-layout">
-      <!-- 左侧:监测点列表 -->
-      <div class="left-panel">
-        <div class="card">
-          <div class="card-header">
-            📍 监测点列表
-            <button @click="openAddPointModal" class="btn-primary btn-sm">+ 新增监测点</button>
-          </div>
-          <div class="card-body">
-            <div class="search-group">
-              <input
-                  type="text"
-                  v-model="pointSearchKeyword"
-                  class="search-input"
-                  placeholder="搜索监测点名称/编码..."
-                  @keyup.enter="handlePointSearch"
+  <div class="app-container">
+    <el-form ref="queryRef" :model="queryParams" :inline="true" v-show="showSearch">
+      <el-form-item label="监测点编码" prop="pointCode">
+        <el-input
+          v-model="queryParams.pointCode"
+          placeholder="请输入监测点编码"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="监测点名称" prop="pointName">
+        <el-input
+          v-model="queryParams.pointName"
+          placeholder="请输入监测点名称"
+          clearable
+          style="width: 220px"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="监测类型" prop="pointType">
+        <el-select
+          v-model="queryParams.pointType"
+          placeholder="请选择监测类型"
+          clearable
+          filterable
+          allow-create
+          default-first-option
+          style="width: 220px"
+        >
+          <el-option
+            v-for="item in pointTypeOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+          filterable
+          allow-create
+          default-first-option
+          style="width: 180px"
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item"
+            :label="item"
+            :value="item"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
+          修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
+          删除
+        </el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="pointList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="监测点编码" align="center" prop="pointCode" min-width="140" />
+      <el-table-column label="监测点名称" align="center" prop="pointName" min-width="180" show-overflow-tooltip />
+      <el-table-column label="关联设施" align="center" min-width="160" show-overflow-tooltip>
+        <template #default="scope">
+          {{ networkNameMap[scope.row.networkId] || scope.row.networkId || "-" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="监测类型" align="center" prop="pointType" min-width="120" />
+      <el-table-column label="位置描述" align="center" prop="location" min-width="180" show-overflow-tooltip />
+      <el-table-column label="状态" align="center" prop="status" width="100" />
+      <el-table-column label="安装日期" align="center" prop="installationDate" width="120" />
+      <el-table-column label="操作" align="center" width="280" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="View" @click="handleView(scope.row)">详情</el-button>
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
+          <el-button link type="warning" icon="Connection" @click="openBindDialog(scope.row)">关联设备</el-button>
+          <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog :title="title" v-model="open" width="780px" append-to-body>
+      <el-form ref="pointRef" :model="form" :rules="rules" label-width="110px">
+        <el-row :gutter="16">
+          <el-col :span="12">
+            <el-form-item label="监测点编码" prop="pointCode">
+              <el-input v-model="form.pointCode" placeholder="请输入监测点编码" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="监测点名称" prop="pointName">
+              <el-input v-model="form.pointName" placeholder="请输入监测点名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="关联设施" prop="networkId">
+              <el-select v-model="form.networkId" clearable placeholder="请选择管网设施" style="width: 100%">
+                <el-option
+                  v-for="item in networkOptions"
+                  :key="item.networkId"
+                  :label="`${item.networkName}(${item.networkCode})`"
+                  :value="item.networkId"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="监测类型" prop="pointType">
+              <el-select
+                v-model="form.pointType"
+                placeholder="请选择或输入监测类型"
+                filterable
+                allow-create
+                default-first-option
+                style="width: 100%"
               >
-              <button @click="handlePointSearch" class="btn-outline btn-sm">搜索</button>
-              <button @click="resetPointSearch" class="btn-outline btn-sm">重置</button>
-            </div>
-            <div class="point-list">
-              <div
-                  v-for="point in filteredPoints"
-                  :key="point.id"
-                  class="point-item"
-                  :class="{ active: selectedPointId === point.id }"
-                  @click="selectPoint(point)"
+                <el-option
+                  v-for="item in pointTypeOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-select
+                v-model="form.status"
+                placeholder="请选择或输入状态"
+                filterable
+                allow-create
+                default-first-option
+                style="width: 100%"
               >
-                <div class="point-name">{{ point.name }}</div>
-                <div class="point-info">
-                  <span class="point-code">{{ point.code }}</span>
-                  <span class="point-type">{{ point.type }}</span>
-                </div>
-                <div class="point-location">{{ point.location }}</div>
-              </div>
-              <div v-if="filteredPoints.length === 0" class="empty-state">
-                暂无监测点数据
-              </div>
-            </div>
-          </div>
+                <el-option
+                  v-for="item in statusOptions"
+                  :key="item"
+                  :label="item"
+                  :value="item"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="安装日期" prop="installationDate">
+              <el-date-picker
+                v-model="form.installationDate"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择安装日期"
+                style="width: 100%"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="位置描述" prop="location">
+              <el-input v-model="form.location" placeholder="请输入位置描述" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="经度" prop="longitude">
+              <el-input-number v-model="form.longitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="纬度" prop="latitude">
+              <el-input-number v-model="form.latitude" :precision="6" :step="0.000001" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
         </div>
+      </template>
+    </el-dialog>
+
+    <el-dialog title="监测点详情" v-model="detailOpen" width="920px" append-to-body>
+      <el-descriptions :column="2" border v-if="detailForm.pointInfo">
+        <el-descriptions-item label="监测点编码">{{ detailForm.pointInfo.pointCode || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="监测点名称">{{ detailForm.pointInfo.pointName || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="监测类型">{{ detailForm.pointInfo.pointType || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="状态">{{ detailForm.pointInfo.status || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="安装日期">{{ detailForm.pointInfo.installationDate || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="关联设施">
+          {{ detailForm.networkInfo?.networkName || detailForm.pointInfo.networkId || "-" }}
+        </el-descriptions-item>
+        <el-descriptions-item label="经度">{{ detailForm.pointInfo.longitude ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="纬度">{{ detailForm.pointInfo.latitude ?? "-" }}</el-descriptions-item>
+        <el-descriptions-item label="位置描述" :span="2">{{ detailForm.pointInfo.location || "-" }}</el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ detailForm.pointInfo.remark || "-" }}</el-descriptions-item>
+      </el-descriptions>
+
+      <el-divider content-position="left">关联设备</el-divider>
+      <el-table :data="detailForm.equipmentList || []" border>
+        <el-table-column label="设备编码" prop="equipmentCode" min-width="140" />
+        <el-table-column label="设备名称" prop="equipmentName" min-width="180" show-overflow-tooltip />
+        <el-table-column label="设备型号" prop="equipmentModel" min-width="120" />
+        <el-table-column label="制造商" prop="manufacturer" min-width="140" show-overflow-tooltip />
+        <el-table-column label="设备位置" prop="equipmentLocation" min-width="180" show-overflow-tooltip />
+      </el-table>
+    </el-dialog>
+
+    <el-dialog title="关联监测设备" v-model="bindOpen" width="860px" append-to-body>
+      <el-form label-width="90px">
+        <el-form-item label="当前点位">
+          <span>{{ currentRow.pointName || "-" }}</span>
+        </el-form-item>
+        <el-form-item label="选择设备">
+          <el-select
+            v-model="bindForm.equipmentId"
+            filterable
+            clearable
+            placeholder="请选择设备"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in unboundEquipmentOptions"
+              :key="item.equipmentId"
+              :label="`${item.equipmentName}(${item.equipmentCode})`"
+              :value="item.equipmentId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+
+      <div class="mb12">
+        <el-button type="primary" @click="submitBind">添加关联</el-button>
       </div>
 
-      <!-- 右侧:监测点详情与设备关联 -->
-      <div class="right-panel">
-        <div v-if="selectedPoint" class="point-detail">
-          <!-- 监测点基本信息 -->
-          <div class="card">
-            <div class="card-header">
-              📋 监测点基本信息
-              <div class="header-actions">
-                <button @click="openEditPointModal" class="btn-outline btn-sm">✏️ 编辑</button>
-                <button @click="deletePoint" class="btn-danger btn-sm">🗑️ 删除</button>
-              </div>
-            </div>
-            <div class="card-body">
-              <div class="info-grid">
-                <div class="info-item"><span class="info-label">监测点名称:</span>{{ selectedPoint.name }}</div>
-                <div class="info-item"><span class="info-label">监测点编码:</span>{{ selectedPoint.code }}</div>
-                <div class="info-item"><span class="info-label">监测类型:</span>{{ selectedPoint.type }}</div>
-                <div class="info-item"><span class="info-label">所在位置:</span>{{ selectedPoint.location }}</div>
-                <div class="info-item"><span class="info-label">责任单位:</span>{{ selectedPoint.responsibleUnit || '-' }}</div>
-                <div class="info-item"><span class="info-label">联系人:</span>{{ selectedPoint.contactPerson || '-' }} / {{ selectedPoint.contactPhone || '-' }}</div>
-                <div class="info-item full-width"><span class="info-label">描述:</span>{{ selectedPoint.description || '-' }}</div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 关联设备列表 -->
-          <div class="card">
-            <div class="card-header">
-              🔌 关联监测设备
-              <button @click="openAddDeviceModal" class="btn-primary btn-sm">+ 添加设备</button>
-            </div>
-            <div class="card-body">
-              <div v-if="selectedPoint.devices && selectedPoint.devices.length > 0" class="device-list">
-                <div v-for="device in selectedPoint.devices" :key="device.id" class="device-item">
-                  <div class="device-info">
-                    <div class="device-name">{{ device.name }}</div>
-                    <div class="device-meta">
-                      <span>ID: {{ device.deviceId }}</span>
-                      <span>类型: {{ device.type }}</span>
-                      <span>厂家: {{ device.manufacturer || '-' }}</span>
-                    </div>
-                  </div>
-                  <div class="device-actions">
-                    <button @click="openRuleModal(device)" class="btn-outline btn-sm">⚙️ 预警规则</button>
-                    <button @click="removeDevice(device)" class="btn-danger-outline btn-sm">解绑</button>
-                  </div>
-                </div>
-              </div>
-              <div v-else class="empty-device">
-                暂无关联设备,点击「添加设备」进行关联
-              </div>
-            </div>
-          </div>
-
-          <!-- 预警规则展示 -->
-          <div class="card" v-if="selectedDeviceForRule">
-            <div class="card-header">
-              ⚠️ 设备预警规则配置
-              <span class="device-name-tag">{{ selectedDeviceForRule.name }}</span>
-            </div>
-            <div class="card-body">
-              <div class="rule-form">
-                <div class="form-group">
-                  <label class="form-label">预警阈值范围</label>
-                  <div class="threshold-group">
-                    <input
-                        type="number"
-                        v-model="currentRule.minThreshold"
-                        class="threshold-input"
-                        placeholder="下限值"
-                    >
-                    <span>~</span>
-                    <input
-                        type="number"
-                        v-model="currentRule.maxThreshold"
-                        class="threshold-input"
-                        placeholder="上限值"
-                    >
-                    <span class="unit">{{ selectedDeviceForRule?.unit || '' }}</span>
-                  </div>
-                </div>
-                <div class="form-group">
-                  <label class="form-label">预警等级</label>
-                  <select v-model="currentRule.alertLevel" class="form-select">
-                    <option value="info">提示</option>
-                    <option value="warning">预警</option>
-                    <option value="critical">严重告警</option>
-                  </select>
-                </div>
-                <div class="form-group">
-                  <label class="form-label">联动抓拍</label>
-                  <label class="switch-label">
-                    <input type="checkbox" v-model="currentRule.enableCapture">
-                    <span>超过阈值时自动抓拍现场画面</span>
-                  </label>
-                </div>
-                <div class="form-group">
-                  <label class="form-label">联动录像</label>
-                  <label class="switch-label">
-                    <input type="checkbox" v-model="currentRule.enableRecord">
-                    <span>超过阈值时自动开始录像(时长:</span>
-                    <input
-                        v-if="currentRule.enableRecord"
-                        type="number"
-                        v-model="currentRule.recordDuration"
-                        class="duration-input"
-                        placeholder="秒"
-                    >
-                    <span v-if="currentRule.enableRecord">秒)</span>
-                  </label>
-                </div>
-                <div class="form-group">
-                  <label class="form-label">联动通知</label>
-                  <label class="switch-label">
-                    <input type="checkbox" v-model="currentRule.enableNotify">
-                    <span>发送告警通知给责任人</span>
-                  </label>
-                </div>
-                <div class="form-actions">
-                  <button @click="saveRule" class="btn-primary">保存预警规则</button>
-                  <button @click="clearRuleSelection" class="btn-outline">取消</button>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-
-        <!-- 未选择监测点时显示 -->
-        <div v-else class="empty-selection">
-          <div class="empty-icon">📍</div>
-          <div>请从左侧选择监测点</div>
-        </div>
-      </div>
-    </div>
-
-    <!-- 新增/编辑监测点模态框 -->
-    <div v-if="pointModalVisible" class="modal-overlay" @click.self="closePointModal">
-      <div class="modal-content" style="width:500px;">
-        <h3 style="margin-bottom:16px;">{{ isEditPoint ? '编辑监测点' : '新增监测点' }}</h3>
-        <form @submit.prevent="savePoint">
-          <div class="form-group">
-            <label class="form-label">监测点名称 *</label>
-            <input v-model="pointForm.name" class="form-input" required>
-          </div>
-          <div class="form-group">
-            <label class="form-label">监测点编码 *</label>
-            <input v-model="pointForm.code" class="form-input" required>
-          </div>
-          <div class="form-group">
-            <label class="form-label">监测类型</label>
-            <select v-model="pointForm.type" class="form-select">
-              <option value="水质监测">水质监测</option>
-              <option value="空气质量">空气质量</option>
-              <option value="压力监测">压力监测</option>
-              <option value="流量监测">流量监测</option>
-              <option value="温度监测">温度监测</option>
-              <option value="泄漏检测">泄漏检测</option>
-            </select>
-          </div>
-          <div class="form-group">
-            <label class="form-label">所在位置</label>
-            <input v-model="pointForm.location" class="form-input" placeholder="地址或经纬度">
-          </div>
-          <div class="form-group">
-            <label class="form-label">责任单位</label>
-            <input v-model="pointForm.responsibleUnit" class="form-input">
-          </div>
-          <div class="form-row">
-            <div class="form-group half">
-              <label class="form-label">联系人</label>
-              <input v-model="pointForm.contactPerson" class="form-input">
-            </div>
-            <div class="form-group half">
-              <label class="form-label">联系电话</label>
-              <input v-model="pointForm.contactPhone" class="form-input">
-            </div>
-          </div>
-          <div class="form-group">
-            <label class="form-label">描述</label>
-            <textarea v-model="pointForm.description" rows="2" class="form-textarea"></textarea>
-          </div>
-          <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-            <button type="button" @click="closePointModal" class="btn-outline">取消</button>
-            <button type="submit" class="btn-primary">保存</button>
-          </div>
-        </form>
-      </div>
-    </div>
-
-    <!-- 添加设备模态框 -->
-    <div v-if="deviceModalVisible" class="modal-overlay" @click.self="closeDeviceModal">
-      <div class="modal-content" style="width:550px;">
-        <h3 style="margin-bottom:16px;">🔌 添加监测设备</h3>
-        <p style="font-size:0.75rem; color:#6f8ea8; margin-bottom:16px;">当前监测点:<strong>{{ selectedPoint?.name }}</strong></p>
-        <form @submit.prevent="addDeviceToPoint">
-          <div class="form-group">
-            <label class="form-label">选择设备</label>
-            <select v-model="selectedDeviceId" class="form-select" required>
-              <option value="">-- 请选择设备 --</option>
-              <option v-for="device in availableDevices" :key="device.id" :value="device.id">
-                {{ device.name }} ({{ device.deviceId }}) - {{ device.type }}
-              </option>
-            </select>
-          </div>
-          <div v-if="selectedDevice" class="device-preview">
-            <div class="preview-title">设备信息</div>
-            <div class="preview-row">设备ID: {{ selectedDevice.deviceId }}</div>
-            <div class="preview-row">类型: {{ selectedDevice.type }}</div>
-            <div class="preview-row">厂家: {{ selectedDevice.manufacturer || '-' }}</div>
-            <div class="preview-row">量程/单位: {{ selectedDevice.range || '-' }} / {{ selectedDevice.unit || '-' }}</div>
-          </div>
-          <div style="margin-top:20px; display:flex; gap:10px; justify-content:flex-end;">
-            <button type="button" @click="closeDeviceModal" class="btn-outline">取消</button>
-            <button type="submit" class="btn-primary">确认关联</button>
-          </div>
-        </form>
-      </div>
-    </div>
+      <el-table :data="bindDetail.equipmentList || []" border>
+        <el-table-column label="设备编码" prop="equipmentCode" min-width="140" />
+        <el-table-column label="设备名称" prop="equipmentName" min-width="180" show-overflow-tooltip />
+        <el-table-column label="设备型号" prop="equipmentModel" min-width="120" />
+        <el-table-column label="制造商" prop="manufacturer" min-width="140" show-overflow-tooltip />
+        <el-table-column label="设备位置" prop="equipmentLocation" min-width="180" show-overflow-tooltip />
+        <el-table-column label="操作" align="center" width="100">
+          <template #default="scope">
+            <el-button link type="danger" icon="Close" @click="handleUnbind(scope.row)">解绑</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
-
-// 监测点数据
-const monitoringPoints = ref([
-  {
-    id: 1,
-    name: "化工园区水质监测点",
-    code: "WQ-001",
-    type: "水质监测",
-    location: "化工园区东侧排水口",
-    responsibleUnit: "环保监测中心",
-    contactPerson: "张明",
-    contactPhone: "13800001111",
-    description: "监测化工园区排水口水质参数",
-    devices: [
-      {
-        id: 101,
-        name: "水质在线分析仪",
-        deviceId: "WQA-001",
-        type: "水质传感器",
-        manufacturer: "华测仪器",
-        range: "0-100mg/L",
-        unit: "mg/L",
-        rule: { minThreshold: 0, maxThreshold: 50, alertLevel: "warning", enableCapture: true, enableRecord: false, enableNotify: true, recordDuration: 30 }
-      }
-    ]
+import { computed, getCurrentInstance, onMounted, reactive, ref, toRefs } from "vue";
+import {
+  addMonitorPoint,
+  bindPointEquipment,
+  delMonitorPoint,
+  getMonitorPoint,
+  getMonitorPointDetail,
+  listEquipment,
+  listMonitorPoint,
+  listPipeNetworkAll,
+  unbindPointEquipment,
+  updateMonitorPoint
+} from "@/api/pipeNetwork/pdeviceInform";
+
+const { proxy } = getCurrentInstance();
+
+const pointList = ref([]);
+const networkOptions = ref([]);
+const equipmentOptions = ref([]);
+const loading = ref(false);
+const open = ref(false);
+const detailOpen = ref(false);
+const bindOpen = ref(false);
+const showSearch = ref(true);
+const ids = ref([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+const currentRow = ref({});
+
+const pointTypeOptions = ["水质监测", "空气质量", "压力监测", "流量监测", "温度监测", "泄漏检测"];
+const statusOptions = ["正常", "启用", "停用", "维修中", "预警"];
+
+const networkNameMap = computed(() => {
+  return networkOptions.value.reduce((acc, item) => {
+    acc[item.networkId] = item.networkName;
+    return acc;
+  }, {});
+});
+
+const data = reactive({
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    pointCode: undefined,
+    pointName: undefined,
+    pointType: undefined,
+    status: undefined
   },
-  {
-    id: 2,
-    name: "城南泵站压力监测点",
-    code: "PR-002",
-    type: "压力监测",
-    location: "城南污水处理厂泵房",
-    responsibleUnit: "水务集团",
-    contactPerson: "李华",
-    contactPhone: "13800002222",
-    description: "监测泵站出水压力",
-    devices: [
-      {
-        id: 102,
-        name: "压力变送器",
-        deviceId: "PT-002",
-        type: "压力传感器",
-        manufacturer: "西门子",
-        range: "0-1.6MPa",
-        unit: "MPa",
-        rule: { minThreshold: 0.2, maxThreshold: 1.2, alertLevel: "critical", enableCapture: true, enableRecord: true, enableNotify: true, recordDuration: 60 }
-      }
-    ]
+  form: {},
+  detailForm: {},
+  bindDetail: {},
+  bindForm: {
+    equipmentId: undefined
   },
-  {
-    id: 3,
-    name: "城北燃气管网监测点",
-    code: "GAS-003",
-    type: "泄漏检测",
-    location: "城北燃气管网阀门井",
-    responsibleUnit: "燃气集团",
-    contactPerson: "王强",
-    contactPhone: "13800003333",
-    description: "可燃气体浓度监测",
-    devices: []
+  rules: {
+    pointCode: [{ required: true, message: "监测点编码不能为空", trigger: "blur" }],
+    pointName: [{ required: true, message: "监测点名称不能为空", trigger: "blur" }],
+    pointType: [{ required: true, message: "监测类型不能为空", trigger: "change" }]
   }
-])
-
-// 可用设备库(用于关联)
-const availableDevices = ref([
-  { id: 201, name: "多参数水质分析仪", deviceId: "WQA-101", type: "水质传感器", manufacturer: "哈希", range: "0-200mg/L", unit: "mg/L" },
-  { id: 202, name: "压力传感器", deviceId: "PT-103", type: "压力传感器", manufacturer: "罗斯蒙特", range: "0-2.5MPa", unit: "MPa" },
-  { id: 203, name: "可燃气体探测器", deviceId: "GD-205", type: "气体传感器", manufacturer: "霍尼韦尔", range: "0-100%LEL", unit: "%LEL" },
-  { id: 204, name: "超声波流量计", deviceId: "UF-308", type: "流量传感器", manufacturer: "艾默生", range: "0-500m³/h", unit: "m³/h" },
-  { id: 205, name: "红外热成像仪", deviceId: "TI-410", type: "温度传感器", manufacturer: "海康威视", range: "-20~500℃", unit: "℃" }
-])
-
-// 当前选中的监测点
-const selectedPointId = ref(1)
-const selectedPoint = computed(() => monitoringPoints.value.find(p => p.id === selectedPointId.value))
-
-// 设备预警规则相关
-const selectedDeviceForRule = ref(null)
-const currentRule = ref({
-  minThreshold: 0,
-  maxThreshold: 100,
-  alertLevel: "warning",
-  enableCapture: false,
-  enableRecord: false,
-  enableNotify: true,
-  recordDuration: 30
-})
-
-// 模态框状态
-const pointModalVisible = ref(false)
-const deviceModalVisible = ref(false)
-const isEditPoint = ref(false)
-const pointForm = ref({
-  name: '', code: '', type: '水质监测', location: '', responsibleUnit: '',
-  contactPerson: '', contactPhone: '', description: ''
-})
-
-// 设备关联表单
-const selectedDeviceId = ref('')
-const selectedDevice = computed(() => availableDevices.value.find(d => d.id === selectedDeviceId.value))
-
-// 搜索
-const pointSearchKeyword = ref('')
-const filteredPoints = computed(() => {
-  if (!pointSearchKeyword.value) return monitoringPoints.value
-  const kw = pointSearchKeyword.value.toLowerCase()
-  return monitoringPoints.value.filter(p =>
-      p.name.toLowerCase().includes(kw) ||
-      p.code.toLowerCase().includes(kw) ||
-      p.location.toLowerCase().includes(kw)
-  )
-})
-
-// 选择监测点
-const selectPoint = (point) => {
-  selectedPointId.value = point.id
-  selectedDeviceForRule.value = null
-  currentRule.value = { minThreshold: 0, maxThreshold: 100, alertLevel: "warning", enableCapture: false, enableRecord: false, enableNotify: true, recordDuration: 30 }
-}
-
-// 监测点搜索
-const handlePointSearch = () => {
-  // 已通过computed自动过滤
-}
-const resetPointSearch = () => {
-  pointSearchKeyword.value = ''
-}
-
-// 新增/编辑监测点
-const openAddPointModal = () => {
-  isEditPoint.value = false
-  pointForm.value = {
-    name: '', code: '', type: '水质监测', location: '', responsibleUnit: '',
-    contactPerson: '', contactPhone: '', description: ''
+});
+
+const { queryParams, form, detailForm, bindDetail, bindForm, rules } = toRefs(data);
+
+const unboundEquipmentOptions = computed(() => {
+  const boundIds = new Set((bindDetail.value.equipmentList || []).map((item) => item.equipmentId));
+  return equipmentOptions.value.filter((item) => !boundIds.has(item.equipmentId));
+});
+
+function createEmptyForm() {
+  return {
+    pointId: undefined,
+    pointCode: undefined,
+    pointName: undefined,
+    networkId: undefined,
+    pointType: undefined,
+    location: undefined,
+    longitude: undefined,
+    latitude: undefined,
+    installationDate: undefined,
+    status: "正常",
+    remark: undefined
+  };
+}
+
+function getList() {
+  loading.value = true;
+  listMonitorPoint(queryParams.value)
+    .then((response) => {
+      pointList.value = response.records || [];
+      total.value = response.total || 0;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+function loadAssistData() {
+  return Promise.all([
+    listPipeNetworkAll(),
+    listEquipment({
+      pageNum: 1,
+      pageSize: 1000
+    })
+  ]).then(([networkRes, equipmentRes]) => {
+    networkOptions.value = networkRes.data || [];
+    equipmentOptions.value = equipmentRes.records || [];
+  });
+}
+
+function loadPointDetail(pointId, targetRef) {
+  return getMonitorPointDetail(pointId).then((response) => {
+    targetRef.value = response.data || {};
+  });
+}
+
+function reset() {
+  form.value = createEmptyForm();
+  proxy.resetForm("pointRef");
+}
+
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+function resetQuery() {
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+function handleSelectionChange(selection) {
+  ids.value = selection.map((item) => item.pointId);
+  single.value = selection.length !== 1;
+  multiple.value = !selection.length;
+}
+
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "新增关键监控点位";
+}
+
+function handleUpdate(row) {
+  reset();
+  const pointId = row?.pointId || ids.value[0];
+  if (!pointId) {
+    return;
   }
-  pointModalVisible.value = true
+  getMonitorPoint(pointId).then((response) => {
+    form.value = { ...createEmptyForm(), ...(response.data || {}) };
+    open.value = true;
+    title.value = "修改关键监控点位";
+  });
 }
 
-const openEditPointModal = () => {
-  if (!selectedPoint.value) return
-  isEditPoint.value = true
-  pointForm.value = { ...selectedPoint.value }
-  pointModalVisible.value = true
+function handleView(row) {
+  loadPointDetail(row.pointId, detailForm).then(() => {
+    detailOpen.value = true;
+  });
 }
 
-const closePointModal = () => {
-  pointModalVisible.value = false
-}
-
-const savePoint = () => {
-  if (!pointForm.value.name || !pointForm.value.code) {
-    alert("请填写监测点名称和编码")
-    return
-  }
-
-  if (isEditPoint.value && selectedPoint.value) {
-    const index = monitoringPoints.value.findIndex(p => p.id === selectedPoint.value.id)
-    if (index !== -1) {
-      monitoringPoints.value[index] = { ...pointForm.value, id: selectedPoint.value.id, devices: selectedPoint.value.devices || [] }
-    }
-    alert("监测点信息已更新")
-  } else {
-    const newId = Math.max(...monitoringPoints.value.map(p => p.id), 0) + 1
-    monitoringPoints.value.push({ ...pointForm.value, id: newId, devices: [] })
-    selectedPointId.value = newId
-    alert("监测点已添加")
-  }
-  closePointModal()
+function cancel() {
+  open.value = false;
+  reset();
 }
 
-// 删除监测点
-const deletePoint = () => {
-  if (!selectedPoint.value) return
-  if (confirm(`确定删除监测点 "${selectedPoint.value.name}" 吗?`)) {
-    const index = monitoringPoints.value.findIndex(p => p.id === selectedPoint.value.id)
-    if (index !== -1) {
-      monitoringPoints.value.splice(index, 1)
+function submitForm() {
+  proxy.$refs.pointRef.validate((valid) => {
+    if (!valid) {
+      return;
     }
-    if (monitoringPoints.value.length > 0) {
-      selectedPointId.value = monitoringPoints.value[0].id
-    } else {
-      selectedPointId.value = null
-    }
-    alert("监测点已删除")
-  }
-}
-
-// 设备关联
-const openAddDeviceModal = () => {
-  if (!selectedPoint.value) return
-  selectedDeviceId.value = ''
-  deviceModalVisible.value = true
-}
-
-const closeDeviceModal = () => {
-  deviceModalVisible.value = false
-}
-
-const addDeviceToPoint = () => {
-  if (!selectedDevice.value) {
-    alert("请选择设备")
-    return
+    const request = form.value.pointId ? updateMonitorPoint(form.value) : addMonitorPoint(form.value);
+    request.then(() => {
+      proxy.$modal.msgSuccess(form.value.pointId ? "修改成功" : "新增成功");
+      open.value = false;
+      getList();
+    });
+  });
+}
+
+function handleDelete(row) {
+  const deleteIds = row?.pointId ? [row.pointId] : ids.value;
+  if (!deleteIds.length) {
+    return;
   }
-  if (!selectedPoint.value) return
-
-  // 检查是否已关联
-  const alreadyExists = selectedPoint.value.devices?.some(d => d.id === selectedDevice.value.id)
-  if (alreadyExists) {
-    alert("该设备已是当前监测点的关联设备")
-    return
-  }
-
-  const newDevice = {
-    ...selectedDevice.value,
-    rule: { minThreshold: 0, maxThreshold: 100, alertLevel: "warning", enableCapture: false, enableRecord: false, enableNotify: true, recordDuration: 30 }
-  }
-
-  if (!selectedPoint.value.devices) {
-    selectedPoint.value.devices = []
+  proxy.$modal
+    .confirm(`是否确认删除选中的 ${deleteIds.length} 个监测点?`)
+    .then(() => Promise.all(deleteIds.map((id) => delMonitorPoint(id))))
+    .then(() => {
+      proxy.$modal.msgSuccess("删除成功");
+      getList();
+    });
+}
+
+function openBindDialog(row) {
+  currentRow.value = row;
+  bindForm.value.equipmentId = undefined;
+  loadPointDetail(row.pointId, bindDetail).then(() => {
+    bindOpen.value = true;
+  });
+}
+
+function submitBind() {
+  if (!bindForm.value.equipmentId) {
+    proxy.$modal.msgError("请选择要关联的设备");
+    return;
   }
-  selectedPoint.value.devices.push(newDevice)
-  closeDeviceModal()
-  alert(`设备 "${selectedDevice.value.name}" 已关联到监测点`)
-}
-
-// 解绑设备
-const removeDevice = (device) => {
-  if (!selectedPoint.value) return
-  if (confirm(`确定解绑设备 "${device.name}" 吗?`)) {
-    selectedPoint.value.devices = selectedPoint.value.devices.filter(d => d.id !== device.id)
-    if (selectedDeviceForRule.value?.id === device.id) {
-      selectedDeviceForRule.value = null
+  bindPointEquipment(currentRow.value.pointId, [bindForm.value.equipmentId]).then(() => {
+    proxy.$modal.msgSuccess("关联成功");
+    bindForm.value.equipmentId = undefined;
+    loadPointDetail(currentRow.value.pointId, bindDetail);
+    if (detailOpen.value && detailForm.value?.pointInfo?.pointId === currentRow.value.pointId) {
+      loadPointDetail(currentRow.value.pointId, detailForm);
     }
-    alert("设备已解绑")
-  }
-}
-
-// 预警规则配置
-const openRuleModal = (device) => {
-  selectedDeviceForRule.value = device
-  currentRule.value = { ...device.rule } || {
-    minThreshold: 0,
-    maxThreshold: 100,
-    alertLevel: "warning",
-    enableCapture: false,
-    enableRecord: false,
-    enableNotify: true,
-    recordDuration: 30
-  }
-}
-
-const saveRule = () => {
-  if (selectedDeviceForRule.value) {
-    selectedDeviceForRule.value.rule = { ...currentRule.value }
-    alert(`预警规则已保存到设备 "${selectedDeviceForRule.value.name}"`)
-  }
+  });
+}
+
+function handleUnbind(row) {
+  proxy.$modal
+    .confirm(`是否确认解绑设备“${row.equipmentName}”?`)
+    .then(() => unbindPointEquipment(currentRow.value.pointId, [row.equipmentId]))
+    .then(() => {
+      proxy.$modal.msgSuccess("解绑成功");
+      loadPointDetail(currentRow.value.pointId, bindDetail);
+      if (detailOpen.value && detailForm.value?.pointInfo?.pointId === currentRow.value.pointId) {
+        loadPointDetail(currentRow.value.pointId, detailForm);
+      }
+    });
 }
 
-const clearRuleSelection = () => {
-  selectedDeviceForRule.value = null
-  currentRule.value = {
-    minThreshold: 0,
-    maxThreshold: 100,
-    alertLevel: "warning",
-    enableCapture: false,
-    enableRecord: false,
-    enableNotify: true,
-    recordDuration: 30
-  }
-}
+onMounted(() => {
+  reset();
+  Promise.all([getList(), loadAssistData()]);
+});
 </script>
-
-<style scoped>
-* {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-}
-
-.prototype-container {
-  max-width: 1600px;
-  margin: 0 auto;
-  background: #ffffff;
-  border-radius: 28px;
-  box-shadow: 0 20px 35px -12px rgba(0, 0, 0, 0.15);
-  overflow: hidden;
-  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
-}
-
-/* 头部 */
-.header {
-  background: #0a2b3c;
-  padding: 18px 28px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 12px;
-  border-bottom: 3px solid #3498db;
-}
-
-.logo h2 {
-  color: white;
-  font-weight: 600;
-  font-size: 1.3rem;
-}
-
-.logo p {
-  color: #bdd8e8;
-  font-size: 0.7rem;
-}
-
-.badge-stats {
-  background: #3498db;
-  padding: 6px 18px;
-  border-radius: 30px;
-  color: white;
-  font-weight: 500;
-  font-size: 0.8rem;
-}
-
-/* 主体布局 */
-.main-layout {
-  display: flex;
-  flex-wrap: wrap;
-  min-height: 700px;
-}
-
-.left-panel {
-  width: 340px;
-  background: #f9fbfd;
-  border-right: 1px solid #e2edf2;
-  padding: 20px 16px;
-}
-
-.right-panel {
-  flex: 1;
-  background: #ffffff;
-  padding: 20px 24px;
-  min-width: 500px;
-}
-
-/* 卡片 */
-.card {
-  background: white;
-  border-radius: 20px;
-  border: 1px solid #e6edf3;
-  overflow: hidden;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
-  margin-bottom: 20px;
-}
-
-.card-header {
-  background: #f9fafc;
-  padding: 14px 18px;
-  border-bottom: 1px solid #eef2f6;
-  font-weight: 700;
-  font-size: 0.85rem;
-  color: #1d5a78;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-}
-
-.card-body {
-  padding: 16px;
-}
-
-/* 按钮样式 */
-.btn-primary {
-  background: #3498db;
-  border: none;
-  color: white;
-  padding: 8px 16px;
-  border-radius: 30px;
-  font-weight: 600;
-  font-size: 0.75rem;
-  cursor: pointer;
-  transition: 0.2s;
-}
-
-.btn-primary:hover {
-  background: #2980b9;
-}
-
-.btn-outline {
-  background: white;
-  border: 1px solid #3498db;
-  color: #3498db;
-  padding: 6px 12px;
-  border-radius: 30px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-.btn-danger {
-  background: #e74c3c;
-  border: none;
-  color: white;
-  padding: 6px 12px;
-  border-radius: 30px;
-  font-size: 0.7rem;
-  cursor: pointer;
-}
-
-.btn-danger-outline {
-  background: white;
-  border: 1px solid #e74c3c;
-  color: #e74c3c;
-  padding: 4px 10px;
-  border-radius: 30px;
-  font-size: 0.65rem;
-  cursor: pointer;
-}
-
-.btn-sm {
-  padding: 5px 12px;
-  font-size: 0.7rem;
-}
-
-.header-actions {
-  display: flex;
-  gap: 8px;
-}
-
-/* 监测点列表 */
-.search-group {
-  display: flex;
-  gap: 8px;
-  margin-bottom: 16px;
-}
-
-.search-input {
-  flex: 1;
-  padding: 8px 12px;
-  border-radius: 12px;
-  border: 1px solid #cbdde6;
-  font-size: 0.75rem;
-}
-
-.point-list {
-  max-height: 500px;
-  overflow-y: auto;
-}
-
-.point-item {
-  background: #fef9f2;
-  border-radius: 14px;
-  padding: 12px;
-  margin-bottom: 10px;
-  border-left: 3px solid #3498db;
-  cursor: pointer;
-  transition: 0.1s;
-}
-
-.point-item:hover {
-  background: #f0f7fe;
-}
-
-.point-item.active {
-  background: #e3f0fd;
-  border-left-color: #2980b9;
-}
-
-.point-name {
-  font-weight: 700;
-  font-size: 0.8rem;
-  margin-bottom: 4px;
-}
-
-.point-info {
-  display: flex;
-  gap: 12px;
-  font-size: 0.65rem;
-  color: #6f8ea8;
-  margin-bottom: 4px;
-}
-
-.point-code {
-  font-family: monospace;
-}
-
-.point-location {
-  font-size: 0.65rem;
-  color: #7f8c8d;
-}
-
-.empty-state {
-  text-align: center;
-  padding: 40px;
-  color: #8aaec2;
-  font-size: 0.8rem;
-}
-
-/* 监测点详情 */
-.point-detail {
-  animation: fadeIn 0.2s ease;
-}
-
-.info-grid {
-  display: grid;
-  grid-template-columns: repeat(2, 1fr);
-  gap: 12px;
-}
-
-.info-item {
-  font-size: 0.75rem;
-}
-
-.info-item.full-width {
-  grid-column: span 2;
-}
-
-.info-label {
-  font-weight: 600;
-  color: #2c5a72;
-}
-
-/* 设备列表 */
-.device-list {
-  display: flex;
-  flex-direction: column;
-  gap: 12px;
-}
-
-.device-item {
-  background: #f8fafc;
-  border-radius: 14px;
-  padding: 12px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 12px;
-  border: 1px solid #eef2f6;
-}
-
-.device-name {
-  font-weight: 700;
-  font-size: 0.8rem;
-}
-
-.device-meta {
-  display: flex;
-  gap: 12px;
-  font-size: 0.65rem;
-  color: #6f8ea8;
-  margin-top: 4px;
-}
-
-.device-actions {
-  display: flex;
-  gap: 8px;
-}
-
-.empty-device {
-  text-align: center;
-  padding: 30px;
-  color: #8aaec2;
-  font-size: 0.75rem;
-}
-
-.empty-selection {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  height: 400px;
-  color: #8aaec2;
-}
-
-.empty-icon {
-  font-size: 4rem;
-  margin-bottom: 16px;
-  opacity: 0.5;
-}
-
-/* 预警规则表单 */
-.rule-form {
-  padding: 8px 0;
-}
-
-.threshold-group {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-}
-
-.threshold-input {
-  width: 100px;
-  padding: 6px 10px;
-  border-radius: 10px;
-  border: 1px solid #cbdde6;
-  font-size: 0.75rem;
-}
-
-.unit {
-  font-size: 0.75rem;
-  color: #6f8ea8;
-}
-
-.switch-label {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  font-size: 0.75rem;
-  cursor: pointer;
-}
-
-.duration-input {
-  width: 70px;
-  padding: 4px 8px;
-  border-radius: 10px;
-  border: 1px solid #cbdde6;
-  font-size: 0.7rem;
-}
-
-.form-actions {
-  display: flex;
-  gap: 12px;
-  margin-top: 20px;
-}
-
-.device-name-tag {
-  background: #e8f4fd;
-  padding: 4px 12px;
-  border-radius: 20px;
-  font-size: 0.7rem;
-  font-weight: normal;
-}
-
-/* 模态框 */
-.modal-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background: rgba(0, 0, 0, 0.5);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.modal-content {
-  background: white;
-  border-radius: 24px;
-  width: 500px;
-  max-width: 90%;
-  padding: 24px;
-  max-height: 85vh;
-  overflow-y: auto;
-}
-
-.form-group {
-  margin-bottom: 16px;
-}
-
-.form-label {
-  font-size: 0.7rem;
-  font-weight: 600;
-  margin-bottom: 6px;
-  display: block;
-  color: #2c5a72;
-}
-
-.form-input, .form-select, .form-textarea {
-  width: 100%;
-  padding: 8px 12px;
-  border-radius: 12px;
-  border: 1px solid #cbdde6;
-  font-size: 0.75rem;
-  background: white;
-}
-
-.form-row {
-  display: flex;
-  gap: 12px;
-}
-
-.form-row .form-group {
-  flex: 1;
-}
-
-.device-preview {
-  background: #f8fafc;
-  border-radius: 14px;
-  padding: 12px;
-  margin-top: 12px;
-}
-
-.preview-title {
-  font-weight: 600;
-  font-size: 0.7rem;
-  margin-bottom: 8px;
-  color: #2c5a72;
-}
-
-.preview-row {
-  font-size: 0.7rem;
-  color: #6f8ea8;
-  margin-bottom: 4px;
-}
-
-@keyframes fadeIn {
-  from { opacity: 0; transform: translateY(10px); }
-  to { opacity: 1; transform: translateY(0); }
-}
-</style>

+ 1 - 1
src/views/subSystem/pipeNetwork/phome/pHome.vue

@@ -5,7 +5,7 @@
 
 <template>
   <div class="app-container">
-    <h1>管网设施智能管控系统</h1>
+    <h1>管网设施智能管控系统123</h1>
   </div>
 </template>
 

+ 1 - 1
vite.config.js

@@ -31,7 +31,7 @@ export default defineConfig(({ mode, command }) => {
       proxy: {
         '/dev-api': {
           // target: 'http://192.168.110.235:8300/pipe',
-          target: 'http://192.168.110.235:8301',
+          target: 'http://111.23.174.45:8301',
           changeOrigin: true,
           rewrite: (p) => p.replace(/^\/dev-api/, '')
         }