houzekong 5 дней назад
Родитель
Сommit
eb08f51092
28 измененных файлов с 1541 добавлено и 1021 удалено
  1. 135 103
      public/js/global.js
  2. 8 8
      src/components/Configurable/preset/IdentifyResult.vue
  3. 7 8
      src/layouts/default/feature/components/LeafPopup.vue
  4. 3 1
      src/settings/projectSetting.ts
  5. 12 12
      src/views/analysis/warningAnalysis/globalAlarm/globalAlarm.api.ts
  6. 228 0
      src/views/analysis/warningAnalysis/globalAlarm/globalAlarm.data.ts
  7. 90 90
      src/views/analysis/warningAnalysis/globalAlarm/index.vue
  8. 83 15
      src/views/analysis/warningAnalysis/windPointManage/index.vue
  9. 63 25
      src/views/analysis/warningAnalysis/windPointManage/windPointManage.api.ts
  10. 42 21
      src/views/analysis/warningAnalysis/windPointManage/windPointManage.data.ts
  11. 50 52
      src/views/analysis/warningAnalysis/windPointManage/windTopology/hooks/useTopology.ts
  12. 3 3
      src/views/analysis/warningAnalysis/windPointManage/windTopology/index.vue
  13. 21 29
      src/views/analysis/warningAnalysis/windPointManage/windTopology/windTopology.api.ts
  14. 88 146
      src/views/analysis/warningAnalysis/windPointManage/windTopology/windTopology.data.ts
  15. 0 232
      src/views/analysis/warningAnalysis/windSpeedOverlimit/windSpeedOverlimit.data.ts
  16. 157 17
      src/views/dashboard/HiddenSurface/configurable.data.ts
  17. 1 1
      src/views/dashboard/HiddenSurface/index.vue
  18. 0 21
      src/views/monitor/enforceMonitor/enforceMonitor.api.ts
  19. 0 172
      src/views/monitor/enforceMonitor/enforceMonitor.data.ts
  20. 0 0
      src/views/monitor/sensorMonitor/hooks/form.ts
  21. 19 65
      src/views/monitor/sensorMonitor/index.vue
  22. 19 0
      src/views/monitor/sensorMonitor/sensorMonitor.api.ts
  23. 177 0
      src/views/monitor/sensorMonitor/sensorMonitor.data.ts
  24. 29 0
      src/views/monitor/surfaceMonitor/hooks/form.ts
  25. 143 0
      src/views/monitor/surfaceMonitor/index.vue
  26. 9 0
      src/views/monitor/surfaceMonitor/surfaceMonitor.api.ts
  27. 152 0
      src/views/monitor/surfaceMonitor/surfaceMonitor.data.ts
  28. 2 0
      types/config.d.ts

+ 135 - 103
public/js/global.js

@@ -108,18 +108,18 @@ const __STATIC_ROUTES__ = [
     path: '/basicinfo',
     component: 'LAYOUT',
     children: [
-      {
-        path: '/basicinfo/overhaul',
-        component: 'dashboard/Overhaul',
-        meta: {
-          keepAlive: true,
-          internalOrExternal: false,
-          icon: '',
-          componentName: 'index',
-          title: '信息汇总',
-        },
-        name: 'basicinfo-overhaul',
-      },
+      // {
+      //   path: '/basicinfo/overhaul',
+      //   component: 'dashboard/Overhaul',
+      //   meta: {
+      //     keepAlive: true,
+      //     internalOrExternal: false,
+      //     icon: '',
+      //     componentName: 'index',
+      //     title: '信息汇总',
+      //   },
+      //   name: 'basicinfo-overhaul',
+      // },
       {
         path: '/basicinfo/mines-info',
         component: 'dashboard/basicInfo/minesInfo',
@@ -190,37 +190,7 @@ const __STATIC_ROUTES__ = [
     },
     name: 'basicInfo',
   },
-  {
-    redirect: undefined,
-    path: '/enforce',
-    component: '/monitor/enforceMonitor/index',
-    children: [
-      {
-        path: '/enforce/${id}',
-        component: '/monitor/enforceMonitor/index',
-        meta: {
-          keepAlive: true,
-          internalOrExternal: false,
-          icon: '',
-          componentName: 'index',
-          title: '${departName}',
-          hideMenu: true,
-          generation: false,
-          // orderNo: '${departOrder}',
-        },
-        name: 'enforce-${id}',
-      }
-    ],
-    meta: {
-      keepAlive: false,
-      internalOrExternal: false,
-      icon: 'menu-analysis|svg',
-      componentName: 'index',
-      title: '密闭监测预警全览',
-      generation: true,
-    },
-    name: 'sealed',
-  },
+  
   {
     redirect: undefined,
     path: '/warning-analysis',
@@ -347,16 +317,16 @@ const __STATIC_ROUTES__ = [
       //   name: 'warningAnalysis-connect',
       // },
       {
-        path: '/warningAnalysis/wind-speed-overlimit',
-        component: '/analysis/warningAnalysis/windSpeedOverlimit/index',
+        path: '/warningAnalysis/global-alarm',
+        component: '/analysis/warningAnalysis/globalAlarm/index',
         meta: {
           keepAlive: true,
           internalOrExternal: false,
           icon: '',
           componentName: 'index',
-          title: '风速风量超限判识',
+          title: '预警信息全览',
         },
-        name: 'warningAnalysis-wind-speed-overlimit',
+        name: 'warningAnalysis-global-alarm',
       },
       {
         path: '/warningAnalysis/wind-point-manage',
@@ -366,7 +336,7 @@ const __STATIC_ROUTES__ = [
           internalOrExternal: false,
           icon: '',
           componentName: 'index',
-          title: '测风点位与模型管理',
+          title: '测风点位管理',
         },
         name: 'warningAnalysis-wind-point-manage',
       },
@@ -380,6 +350,68 @@ const __STATIC_ROUTES__ = [
     },
     name: 'warningAnalysis',
   },
+  {
+    redirect: undefined,
+    path: '/surface',
+    component: '/monitor/surfaceMonitor/index',
+    children: [
+      {
+        path: '/surface/${id}',
+        component: '/monitor/surfaceMonitor/index',
+        meta: {
+          keepAlive: true,
+          internalOrExternal: false,
+          icon: '',
+          componentName: 'index',
+          title: '${departName}',
+          hideMenu: true,
+          generation: false,
+          // orderNo: '${departOrder}',
+        },
+        name: 'surface-${id}',
+      }
+    ],
+    meta: {
+      keepAlive: false,
+      internalOrExternal: false,
+      icon: 'menu-analysis|svg',
+      componentName: 'index',
+      title: '隐蔽工作面监测',
+      generation: true,
+    },
+    name: 'surface',
+  },
+  {
+    redirect: undefined,
+    path: '/sensor',
+    component: '/monitor/sensorMonitor/index',
+    children: [
+      {
+        path: '/sensor/${id}',
+        component: '/monitor/sensorMonitor/index',
+        meta: {
+          keepAlive: true,
+          internalOrExternal: false,
+          icon: '',
+          componentName: 'index',
+          title: '${departName}',
+          hideMenu: true,
+          generation: false,
+          // orderNo: '${departOrder}',
+        },
+        name: 'sensor-${id}',
+      }
+    ],
+    meta: {
+      keepAlive: false,
+      internalOrExternal: false,
+      icon: 'menu-analysis|svg',
+      componentName: 'index',
+      title: '风速风量监测',
+      generation: true,
+    },
+    name: 'sensor',
+  },
   // {
   //   redirect: undefined,
   //   path: '/smart-analysis',
@@ -407,61 +439,61 @@ const __STATIC_ROUTES__ = [
   //   },
   //   name: 'smartAnalysis',
   // },
-  {
-    redirect: undefined,
-    path: '/manage',
-    component: 'LAYOUT',
-    children: [
-      {
-        path: '/manage/map',
-        component: '/system/cadFile/index',
-        meta: {
-          keepAlive: true,
-          internalOrExternal: false,
-          icon: '',
-          componentName: 'index',
-          title: '地图管理',
-          // hideMenu: true,
-        },
-        name: 'cadFile',
-      },
-      {
-        path: '/manage/mapView',
-        component: '/system/cadFile/mapView/index',
-        meta: {
-          keepAlive: true,
-          internalOrExternal: false,
-          icon: '',
-          componentName: 'index',
-          title: '图纸布点',
-          hideMenu: true,
-        },
-        name: 'cadFile-mapView',
-      },
-      // 预警模型管理:配置煤层/采空区预警判据的关联表达式
-      {
-        path: '/manage/model',
-        component: '/system/algorithm/index',
-        meta: {
-          keepAlive: true,
-          internalOrExternal: false,
-          // compact: true,
-          icon: '',
-          componentName: 'index',
-          title: '预警模型管理',
-        },
-        name: 'association',
-      },
-    ],
-    meta: {
-      keepAlive: false,
-      internalOrExternal: false,
-      icon: 'menu-model|svg',
-      componentName: 'index',
-      title: '模型与地图管理',
-    },
-    name: 'manage',
-  },
+  // {
+  //   redirect: undefined,
+  //   path: '/manage',
+  //   component: 'LAYOUT',
+  //   children: [
+  //     {
+  //       path: '/manage/map',
+  //       component: '/system/cadFile/index',
+  //       meta: {
+  //         keepAlive: true,
+  //         internalOrExternal: false,
+  //         icon: '',
+  //         componentName: 'index',
+  //         title: '地图管理',
+  //         // hideMenu: true,
+  //       },
+  //       name: 'cadFile',
+  //     },
+  //     {
+  //       path: '/manage/mapView',
+  //       component: '/system/cadFile/mapView/index',
+  //       meta: {
+  //         keepAlive: true,
+  //         internalOrExternal: false,
+  //         icon: '',
+  //         componentName: 'index',
+  //         title: '图纸布点',
+  //         hideMenu: true,
+  //       },
+  //       name: 'cadFile-mapView',
+  //     },
+  //     // 预警模型管理:配置煤层/采空区预警判据的关联表达式
+  //     {
+  //       path: '/manage/model',
+  //       component: '/system/algorithm/index',
+  //       meta: {
+  //         keepAlive: true,
+  //         internalOrExternal: false,
+  //         // compact: true,
+  //         icon: '',
+  //         componentName: 'index',
+  //         title: '预警模型管理',
+  //       },
+  //       name: 'association',
+  //     },
+  //   ],
+  //   meta: {
+  //     keepAlive: false,
+  //     internalOrExternal: false,
+  //     icon: 'menu-model|svg',
+  //     componentName: 'index',
+  //     title: '模型与地图管理',
+  //   },
+  //   name: 'manage',
+  // },
   {
     redirect: undefined,
     path: '/system',

+ 8 - 8
src/components/Configurable/preset/IdentifyResult.vue

@@ -100,13 +100,13 @@
         white-space: nowrap;
       }
       .conclusion-value {
-        font-size: 20px;
+        font-size: 28px;
         // letter-spacing: 4px;
       }
     }
 
     .section-title {
-      font-size: 13px;
+      font-size: 16px;
       font-weight: 600;
       color: @text-color-base;
       // margin-bottom: 6px;
@@ -118,11 +118,11 @@
       border-radius: 6px;
 
       .basis-label {
-        font-size: 13px;
+        font-size: 16px;
         color: #6b7280;
       }
       .basis-value {
-        font-size: 13px;
+        font-size: 24px;
         color: #d97706;
       }
     }
@@ -131,13 +131,13 @@
       line-height: 1.5;
 
       .suggestion-dot {
-        width: 6px;
-        height: 6px;
-        margin-top: 6px;
+        width: 8px;
+        height: 8px;
+        margin-top: 7px;
         background: #60a5fa;
       }
       .suggestion-text {
-        font-size: 12px;
+        font-size: 15px;
         color: #4b5563;
         flex: 1;
       }

+ 7 - 8
src/layouts/default/feature/components/LeafPopup.vue

@@ -15,23 +15,22 @@
       <div>22</div>
     </div>
     <div class="vjmapgis-popup-content__board mb-1">
-      <div class="mr-5px">风量异常</div>
+      <div class="mr-5px">风量异常</div>
       <div>11</div>
     </div>
     <div class="vjmapgis-popup-content__board">
       <div class="mr-5px">判识结果</div>
       <div>正常</div>
     </div>
+    <div class="vjmapgis-popup-content__title">主要风险</div>
     <div class="vjmapgis-popup-content__divider"></div>
     <!-- 主要风险(判定依据) -->
-    <div class="risk-section" v-if="riskItems.length > 0">
-      <div class="risk-list">
-        <div class="risk-item" v-for="(item, idx) in riskItems" :key="'risk-' + idx">
-          <span class="risk-label">{{ item.label }}</span>
-          <span class="risk-value">{{ item.value }}</span>
-        </div>
+    <template v-if="riskItems.length > 0">
+      <div class="vjmapgis-popup-content__board mb-1" v-for="(item, idx) in riskItems" :key="'risk-' + idx">
+        <div class="mr-5px">{{ item.label }}</div>
+        <div>{{ item.value }}</div>
       </div>
-    </div>
+    </template>
     <!-- <div class="vjmapgis-popup-content__table_container">
       <table class="vjmapgis-popup-content__table w-full mt-1">
         <thead>

+ 3 - 1
src/settings/projectSetting.ts

@@ -21,7 +21,7 @@ const { themeColor, headerBgColor, sideBgColor, split, mode } = getConfigByMenuT
 // ! 改动后需要清空浏览器缓存
 const setting: ProjectConfig = {
   // 是否显示SettingButton
-  showSettingButton: false,
+  showSettingButton: true,
 
   // 是否显示主题切换按钮
   showDarkModeToggle: false,
@@ -88,6 +88,8 @@ const setting: ProjectConfig = {
     showNotice: false,
     // 显示菜单搜索按钮
     showSearch: false,
+    // 显示头部时间
+    showHeaderTime: true,
   },
 
   // 菜单配置

+ 12 - 12
src/views/analysis/warningAnalysis/windSpeedOverlimit/windSpeedOverlimit.api.ts → src/views/analysis/warningAnalysis/globalAlarm/globalAlarm.api.ts

@@ -1,13 +1,13 @@
 import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
-  getAlarmList = '/province/wind/getWindOverlimitAlarm',
-  getAlarmHistory = '/province/wind/getWindOverlimitAlarmHistory',
+  getAlarmList = '/workingface/alarm/getAlarmInfo',
+  getAlarmHistory = '/workingface/alarm/getAlarmRecord',
   getBoardNum = '/province/wind/getWindOverlimitBoardNum',
-  getPointList = '/province/wind/getWindMonitorPointList',
+  /* getPointList = '/workingface/windrect/getWindrectList', */
   getAlarmTrend = '/province/wind/getAlarmTrend',
-  resolveAlarm = '/province/wind/resolveAlarm',
-  getHandleRecords = '/province/wind/getHandleRecords',
+  /* resolveAlarm = '/province/wind/resolveAlarm',
+  getHandleRecords = '/province/wind/getHandleRecords', */
   exportAlarm = '/province/wind/exportWindOverlimitAlarm',
 }
 
@@ -15,26 +15,26 @@ enum Api {
 export const getBoardNum = (params?: any) =>
   defHttp.post({ url: Api.getBoardNum, params }, { joinParamsToUrl: true });
 
-/** 查询超限报警实时列表 */
+/** 查询报警实时数据(AlarmController.getAlarmInfo) */
 export const getAlarmList = (params?: any) =>
   defHttp.post({ url: Api.getAlarmList, params }, { joinParamsToUrl: true });
 
-/** 查询超限报警历史数据 */
+/** 分页查询报警历史记录(AlarmController.getAlarmRecord) */
 export const getAlarmHistory = (params?: any) =>
   defHttp.post({ url: Api.getAlarmHistory, params }, { joinParamsToUrl: true });
 
-/** 查询测风点监测地点列表 */
+/* 查询测风装置列表(暂注释,待接口就绪后恢复)
 export const getPointList = (params?: any) =>
-  defHttp.post({ url: Api.getPointList, params }, { joinParamsToUrl: true });
+  defHttp.post({ url: Api.getPointList, params }, { joinParamsToUrl: true }); */
 
 /** 查询报警趋势数据 */
 export const getAlarmTrend = (params?: any) =>
   defHttp.post({ url: Api.getAlarmTrend, params }, { joinParamsToUrl: true });
 
-/** 处理报警 */
+/* 处理报警(暂注释,待接口就绪后恢复)
 export const resolveAlarm = (params?: any) =>
   defHttp.post({ url: Api.resolveAlarm, params }, { joinParamsToUrl: true });
 
-/** 查询处理记录 */
+/* 查询处理记录(暂注释,待接口就绪后恢复)
 export const getHandleRecords = (params?: any) =>
-  defHttp.post({ url: Api.getHandleRecords, params }, { joinParamsToUrl: true });
+  defHttp.post({ url: Api.getHandleRecords, params }, { joinParamsToUrl: true }); */

+ 228 - 0
src/views/analysis/warningAnalysis/globalAlarm/globalAlarm.data.ts

@@ -0,0 +1,228 @@
+import type { BasicColumn, FormSchema } from '/@/components/Table';
+// import { h } from 'vue';
+// import { StatusColorEnum } from '/@/enums/jeecgEnum';
+import dayjs from 'dayjs';
+
+/** 顶部统计卡片 */
+export const boardData = [
+  { label: '风速超限报警', value: '-' },
+  { label: '风量不足报警', value: '-' },
+  { label: '风量不闭合报警', value: '-' },
+  { label: '今日已处理报警', value: '-' },
+];
+
+/** 报警类型映射(AlarmController alarmType 枚举) */
+export const alarmTypeMap: Record<string, string> = {
+  vaOverLimit: '风速超限',
+  m3Lack: '风量不足',
+  m3NotClosed: '风量不闭合',
+};
+
+/** 报警全览实时监测表格列(AlarmInfo) */
+export const columns: BasicColumn[] = [
+  {
+    title: '煤矿名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '测风点名称',
+    dataIndex: 'mineAreaName',
+    width: 160,
+  },
+  {
+    title: '报警类型',
+    dataIndex: 'alarmType',
+    width: 120,
+    customRender: ({ text }) => alarmTypeMap[text] || text,
+  },
+  {
+    title: '实测值',
+    dataIndex: 'realVal',
+    width: 100,
+  },
+  {
+    title: '标准/阈值',
+    dataIndex: 'expectVal',
+    width: 100,
+  },
+  {
+    title: '报警时间',
+    dataIndex: 'createTime',
+    width: 170,
+  },
+];
+
+/** 报警全览历史数据表格列(AlarmRecord) */
+export const historyColumns: BasicColumn[] = [
+  {
+    title: '煤矿名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '测风点名称',
+    dataIndex: 'mineAreaName',
+    width: 160,
+  },
+  {
+    title: '报警类型',
+    dataIndex: 'alarmType',
+    width: 120,
+    customRender: ({ text }) => alarmTypeMap[text] || text,
+  },
+  {
+    title: '标准/阈值',
+    dataIndex: 'expectVal',
+    width: 100,
+  },
+  {
+    title: '报警时间',
+    dataIndex: 'createTime',
+    width: 170,
+  },
+  {
+    title: '结束时间',
+    dataIndex: 'endTime',
+    width: 170,
+  },
+];
+
+/* 测风装置列表表格列(暂注释,待接口就绪后恢复)
+export const pointListColumns: BasicColumn[] = [
+  {
+    title: '测风点编号',
+    dataIndex: 'deviceCode',
+    width: 130,
+  },
+  {
+    title: '监测地点名称',
+    dataIndex: 'devicePos',
+    width: 200,
+  },
+  {
+    title: '当前状态',
+    dataIndex: 'status',
+    width: 100,
+    customRender: ({ text }) => {
+      const normal = String(text) === '1';
+      const color = normal ? StatusColorEnum.green : StatusColorEnum.red;
+      const label = normal ? '正常' : '停用';
+      return h('span', { style: { color, fontWeight: 'bold' } }, label);
+    },
+  },
+]; */
+
+/** 实时监测查询表单(getAlarmInfo) */
+export const schemas: FormSchema[] = [
+  {
+    label: '煤矿名称',
+    field: 'deptId',
+    component: 'MineCascader',
+    colProps: { span: 6 },
+    rules: [],
+  },
+  {
+    label: '报警类型',
+    field: 'alarmType',
+    component: 'Select',
+    colProps: { span: 6 },
+    componentProps: {
+      options: [
+        { label: '全部', value: '' },
+        { label: '风速超限', value: 'vaOverLimit' },
+        { label: '风量不足', value: 'm3Lack' },
+        { label: '风量不闭合', value: 'm3NotClosed' },
+      ],
+    },
+    rules: [],
+  },
+];
+
+/** 历史数据查询表单(getAlarmRecord 支持 startTime/endTime) */
+export const historySchemas: FormSchema[] = [
+  {
+    label: '报警类型',
+    field: 'alarmType',
+    component: 'Select',
+    colProps: { span: 6 },
+    componentProps: {
+      options: [
+        { label: '全部', value: '' },
+        { label: '风速超限', value: 'vaOverLimit' },
+        { label: '风量不足', value: 'm3Lack' },
+        { label: '风量不闭合', value: 'm3NotClosed' },
+      ],
+    },
+    rules: [],
+  },
+  {
+    field: 'startTime',
+    label: '起始日期',
+    component: 'DatePicker',
+    componentProps: {
+      showTime: true,
+      format: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    },
+    defaultValue: dayjs().add(-30, 'day').format('YYYY-MM-DD 00:00:00'),
+    colProps: { span: 6 },
+  },
+  {
+    field: 'endTime',
+    label: '结束日期',
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    },
+    defaultValue: dayjs().format('YYYY-MM-DD 23:59:59'),
+    colProps: { span: 6 },
+  },
+];
+
+/* 处理记录表格列(暂注释,待接口就绪后恢复)
+export const handleRecordColumns: BasicColumn[] = [
+  {
+    title: '煤矿名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '报警类型',
+    dataIndex: 'alarmType',
+    width: 120,
+    customRender: ({ text }) => {
+      const map: Record<string, string> = {
+        windSpeedOver: '风速超限',
+        windVolumeLow: '风量不足',
+        windVolumeUnclosed: '风量不闭合',
+      };
+      return map[text] || text;
+    },
+  },
+  {
+    title: '测风点名称',
+    dataIndex: 'pointName',
+    width: 160,
+  },
+  {
+    title: '处理人',
+    dataIndex: 'handler',
+    width: 100,
+  },
+  {
+    title: '处理情况',
+    dataIndex: 'handleContent',
+    width: 250,
+    ellipsis: true,
+  },
+  {
+    title: '处理时间',
+    dataIndex: 'handleTime',
+    width: 170,
+  },
+]; */

+ 90 - 90
src/views/analysis/warningAnalysis/windSpeedOverlimit/index.vue → src/views/analysis/warningAnalysis/globalAlarm/index.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div class="wind-speed-overlimit">
+  <div class="global-alarm">
     <!-- 顶部统计卡片 -->
     <div class="board-info">
       <MiniBoard
@@ -14,15 +14,17 @@
       />
     </div>
 
-    <!-- Tab 切换:实时报警 / 历史报警 -->
+    <!-- Tab 切换:实时监测 / 历史数据 -->
     <Tabs v-model:activeKey="activeTab" type="line" class="common-page-tabs">
-      <TabPane tab="实时报警" key="realtime">
+      <TabPane tab="实时监测" key="realtime">
         <BasicTable @register="registerRealtimeTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #action="{ record }">
             <div class="action-buttons">
+              <!-- 报警处理(暂注释,待接口就绪后恢复)
               <button v-if="record.status !== '2'" @click="openResolveModal(record)" class="action-btn resolved-btn" title="处理">
                 <SvgIcon name="solved" />
               </button>
+              -->
               <button @click="handleViewDetail(record)" class="action-btn" title="详情">
                 <SvgIcon name="details" />
               </button>
@@ -37,7 +39,7 @@
         </BasicTable>
       </TabPane>
 
-      <TabPane tab="历史报警" key="history">
+      <TabPane tab="历史数据" key="history">
         <BasicTable @register="registerHistoryTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #action="{ record }">
             <div class="action-buttons">
@@ -49,12 +51,10 @@
           <template #resetBefore>
             <a-button type="default" class="ml-8px" preIcon="mdi:download" @click="onExportXls"> 导出 </a-button>
           </template>
-          <template #form-goaf-select>
-            <a-select v-model:value="goafId" :options="goafOptions" placeholder="请选择工作面" @change="historyTable.reload" />
-          </template>
         </BasicTable>
       </TabPane>
 
+      <!-- 处理记录(暂注释,待接口就绪后恢复)
       <TabPane tab="处理记录" key="handleRecord">
         <BasicTable @register="registerHandleRecordTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #resetBefore>
@@ -62,11 +62,12 @@
           </template>
         </BasicTable>
       </TabPane>
+      -->
     </Tabs>
 
-    <!-- 下方:趋势图 + 测风点列表 -->
+    <!-- 下方:近7日报警趋势 -->
     <a-row :gutter="12" class="bottom-section">
-      <a-col :span="14">
+      <a-col :span="24">
         <div class="chart-card">
           <div class="chart-header">
             <span class="chart-title">近7日报警趋势</span>
@@ -74,6 +75,7 @@
           <div ref="chartRef" class="trend-chart"></div>
         </div>
       </a-col>
+      <!-- 测风点监测地点列表(暂注释,待接口就绪后恢复)
       <a-col :span="10">
         <div class="point-list-card">
           <div class="chart-header">
@@ -82,9 +84,10 @@
           <BasicTable @register="registerPointTable" :scroll="{ x: 'max-content', y: 240 }" :pagination="false" />
         </div>
       </a-col>
+      -->
     </a-row>
 
-    <!-- 处理弹窗 -->
+    <!-- 报警处理弹窗(暂注释,待接口就绪后恢复)
     <BasicModal @register="registerModal" :width="600" :minHeight="100" centered title="报警处理" @ok="handleResolve">
       <a-textarea
         class="ml-10px"
@@ -94,24 +97,22 @@
         :rows="4"
       />
     </BasicModal>
+    -->
   </div>
 </template>
 
 <script setup lang="ts">
   import { ref, onMounted, onUnmounted, nextTick } from 'vue';
   import { BasicTable } from '/@/components/Table';
-  import { Tabs, TabPane, message } from 'ant-design-vue';
+  import { Tabs, TabPane } from 'ant-design-vue';
   import MiniBoard from '/@/components/Configurable/detail/MiniBoard.vue';
   import { SvgIcon } from '/@/components/Icon';
-  import { BasicModal } from '/@/components/Modal/index';
-  import { useModal } from '/@/components/Modal';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { useInitForm } from '../../common/analysis';
-  import { historicalFormSchema } from '/@/views/monitor/sealedMonitor/monitor.data';
   import { advancedRoutePush } from '/@/utils';
   import * as echarts from 'echarts';
-  import { boardData, columns, pointListColumns, handleRecordColumns, schemas } from './windSpeedOverlimit.data';
-  import { getAlarmList, getAlarmHistory, getBoardNum, getPointList, getAlarmTrend, getHandleRecords, resolveAlarm as resolveAlarmApi } from './windSpeedOverlimit.api';
+  import { boardData, columns, historyColumns, schemas, historySchemas } from './globalAlarm.data';
+  import { getAlarmList, getAlarmHistory, getBoardNum, getAlarmTrend } from './globalAlarm.api';
 
   // 激活的Tab页签
   const activeTab = ref('realtime');
@@ -119,7 +120,7 @@
   // 卡片数据
   const boardDataRef = ref(boardData.map((item) => ({ ...item })));
 
-  // ====== 实时数据表格 ======
+  // ====== 实时监测表格(getAlarmInfo)======
   const wrappedGetMineData = (params) => {
     return Promise.all([loadBoardData(params), getAlarmList(params)]).then(([__, res]) => res);
   };
@@ -151,27 +152,20 @@
     },
     exportConfig: {
       url: '/province/wind/exportWindOverlimitAlarm',
-      name: '风速风量超限报警',
+      name: '报警全览实时数据',
       params: {},
     },
   });
   const [registerRealtimeTable] = ctxRealtime;
 
-  // ====== 历史数据表格 ======
-  const { goafOptions, goafId, hiscode, resolveValue, registerModal, initGoafOptions } = useInitForm();
+  // ====== 历史数据表格(getAlarmRecord)======
+  const { hiscode } = useInitForm();
 
   const { tableContext, onExportXls } = useListPage({
     tableProps: {
       immediate: false,
-      columns,
-      api: async (params) => {
-        await initGoafOptions(params.deptId);
-        if (!goafId.value) {
-          return Promise.resolve([]);
-        }
-        params.goafId = goafId.value;
-        return getAlarmHistory(params);
-      },
+      columns: historyColumns,
+      api: getAlarmHistory,
       formConfig: {
         autoSearch: true,
         model: { deptId: hiscode },
@@ -189,7 +183,7 @@
             colProps: { span: 6 },
             rules: [],
           },
-          ...historicalFormSchema,
+          ...historySchemas,
         ],
         showAdvancedButton: false,
         schemaGroupNames: ['常规查询'],
@@ -202,46 +196,10 @@
     },
     exportConfig: {
       url: '/province/wind/exportWindOverlimitAlarmHistory',
-      name: '历史报警',
-      params: { goafId },
+      name: '报警全览历史数据',
     },
   });
-  const [registerHistoryTable, historyTable] = tableContext;
-
-  // ====== 测风点监测地点列表 ======
-  const { tableContext: pointCtx } = useListPage({
-    tableProps: {
-      immediate: true,
-      columns: pointListColumns,
-      api: getPointList,
-      pagination: false,
-      striped: true,
-      bordered: true,
-      showIndexColumn: true,
-      showActionColumn: false,
-    },
-  });
-  const [registerPointTable] = pointCtx;
-
-  // ====== 处理记录表格 ======
-  const { tableContext: handleRecordCtx, onExportXls: onExportHandleRecord } = useListPage({
-    tableProps: {
-      immediate: true,
-      columns: handleRecordColumns,
-      api: getHandleRecords,
-      pagination: true,
-      striped: true,
-      bordered: true,
-      showIndexColumn: true,
-      showActionColumn: false,
-    },
-    exportConfig: {
-      url: '/province/wind/exportHandleRecords',
-      name: '处理记录',
-      params: {},
-    },
-  });
-  const [registerHandleRecordTable] = handleRecordCtx;
+  const [registerHistoryTable] = tableContext;
 
   // ====== 加载卡片数据 ======
   async function loadBoardData(params?: any) {
@@ -256,27 +214,7 @@
     }
   }
 
-  // ====== 弹窗处理 ======
-  const [, modalCtx] = useModal();
-  const resolveId = ref('');
-
-  function openResolveModal(record) {
-    resolveId.value = record.id;
-    resolveValue.value = '';
-    modalCtx.openModal(true);
-  }
-
-  async function handleResolve() {
-    try {
-      await resolveAlarmApi({ id: resolveId.value, content: resolveValue.value });
-      message.success('处理成功');
-      modalCtx.closeModal();
-    } catch {
-      message.error('处理失败');
-    }
-  }
-
-  // ====== 趋势图 ======
+  // ====== 趋势图(近7日报警趋势)======
   const chartRef = ref<HTMLDivElement>();
   let chartInstance: echarts.ECharts | null = null;
 
@@ -333,12 +271,74 @@
     window.removeEventListener('resize', handleResize);
     chartInstance?.dispose();
   });
+
+  // ====== 测风点监测地点列表(暂注释,待接口就绪后恢复)======
+  /*
+  const { tableContext: pointCtx } = useListPage({
+    tableProps: {
+      immediate: true,
+      columns: pointListColumns,
+      api: (params?: any) => getPointList({ ...(params || {}), deptId: mineStore.getDepartId || mineStore.getRootId }),
+      pagination: false,
+      striped: true,
+      bordered: true,
+      showIndexColumn: true,
+      showActionColumn: false,
+    },
+  });
+  const [registerPointTable] = pointCtx;
+  */
+
+  // ====== 处理记录表格(暂注释,待接口就绪后恢复)======
+  /*
+  const { tableContext: handleRecordCtx, onExportXls: onExportHandleRecord } = useListPage({
+    tableProps: {
+      immediate: true,
+      columns: handleRecordColumns,
+      api: getHandleRecords,
+      pagination: true,
+      striped: true,
+      bordered: true,
+      showIndexColumn: true,
+      showActionColumn: false,
+    },
+    exportConfig: {
+      url: '/province/wind/exportHandleRecords',
+      name: '处理记录',
+      params: {},
+    },
+  });
+  const [registerHandleRecordTable] = handleRecordCtx;
+  */
+
+  // ====== 报警处理弹窗(暂注释,待接口就绪后恢复)======
+  /*
+  const [, modalCtx] = useModal();
+  const resolveId = ref('');
+  const { resolveValue, registerModal } = useInitForm();
+
+  function openResolveModal(record) {
+    resolveId.value = record.id;
+    resolveValue.value = '';
+    modalCtx.openModal(true);
+  }
+
+  async function handleResolve() {
+    try {
+      await resolveAlarmApi({ id: resolveId.value, content: resolveValue.value });
+      message.success('处理成功');
+      modalCtx.closeModal();
+    } catch {
+      message.error('处理失败');
+    }
+  }
+  */
 </script>
 
 <style lang="less" scoped>
   @import url(../../common/board.less);
 
-  .wind-speed-overlimit {
+  .global-alarm {
     height: 100%;
     overflow-y: auto;
   }

+ 83 - 15
src/views/analysis/warningAnalysis/windPointManage/index.vue

@@ -16,6 +16,10 @@
                     <SvgIcon name="delete" />
                   </button>
                 </a-popconfirm>
+                <a-button size="small" type="link" class="bind-btn" @click="handleBind(record)"> 绑定 </a-button>
+                <a-popconfirm title="确认解绑?" @confirm="handleUnbind(record)">
+                  <a-button size="small" type="link" danger class="bind-btn"> 解绑 </a-button>
+                </a-popconfirm>
               </template>
               <template #resetBefore>
                 <a-button class="ml-2" preIcon="ant-design:plus-outlined" @click="openAddModal"> 新增 </a-button>
@@ -24,12 +28,12 @@
             </BasicTable>
           </a-col>
           <a-col :span="10">
-            <BasicTable @register="registerComplianceTable" :scroll="{ x: 'max-content', y: 420 }" :pagination="false" :style="{ padding: 0 }" />
+            <BasicTable @register="registerWindrectTable" :scroll="{ x: 'max-content', y: 420 }" :pagination="false" :style="{ padding: 0 }" />
           </a-col>
         </a-row>
       </TabPane>
 
-      <!-- 判识模型管理 -->
+      <!-- 判识模型管理(暂注释,待接口就绪后恢复)
       <TabPane tab="判识模型管理" key="modelConfig">
         <BasicTable @register="registerModelConfigTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #action="{ record }">
@@ -46,6 +50,7 @@
           <a-alert type="info" message="修改参数后,系统将重新计算判识指标。请确保参数值在合理范围内。" show-icon :closable="false" />
         </div>
       </TabPane>
+      -->
 
       <!-- 测风网络拓扑 -->
       <TabPane tab="测风网络拓扑" key="windTopology">
@@ -58,10 +63,11 @@
       <BasicForm @register="registerForm" />
     </BasicModal>
 
-    <!-- 判识模型参数编辑弹窗 -->
+    <!-- 判识模型参数编辑弹窗(暂注释,待接口就绪后恢复)
     <BasicModal @register="registerModelModal" :width="600" :minHeight="200" centered :title="modelModalTitle" @ok="handleSubmitModel" destroyOnClose>
       <BasicForm @register="registerModelForm" />
     </BasicModal>
+    -->
   </div>
 </template>
 
@@ -74,8 +80,18 @@
   import { BasicModal } from '/@/components/Modal/index';
   import { useModal } from '/@/components/Modal';
   import { useListPage } from '/@/hooks/system/useListPage';
-  import { pointColumns, complianceColumns, modelConfigColumns, defaultModelConfigs, formSchema, modelConfigFormSchema } from './windPointManage.data';
-  import { getPointList, savePoint, deletePoint, getComplianceCheck, getModelConfigs, saveModelConfigs } from './windPointManage.api';
+  import { pointColumns, windrectColumns, /* modelConfigColumns, defaultModelConfigs, */ formSchema /*, modelConfigFormSchema */ } from './windPointManage.data';
+  import {
+    getPointList,
+    savePoint,
+    deletePoint,
+    getWindrectList,
+    getMineAreaRelation,
+    addMineAreaRelation,
+    deleteMineAreaRelation,
+    /* getModelConfigs,
+    saveModelConfigs, */
+  } from './windPointManage.api';
   import WindTopology from './windTopology/index.vue';
 
   // 激活的Tab页签
@@ -127,7 +143,7 @@
       bordered: true,
       showIndexColumn: true,
       actionColumn: {
-        width: 120,
+        width: 180,
         title: '操作',
         dataIndex: 'action',
         slots: { customRender: 'action' },
@@ -136,10 +152,10 @@
   });
   const [registerPointTable, pointTable] = pointCtx;
 
-  // ====== 布点合规校验表格 ======
-  const { tableContext: complianceCtx } = useListPage({
+  // ====== 上传数据布点表格(getWindrectList)======
+  const { tableContext: windrectCtx } = useListPage({
     tableProps: {
-      title: '上传数据布点合规校验',
+      title: '上传数据布点',
       formConfig: {
         autoSearch: true,
         labelWidth: 120,
@@ -161,18 +177,21 @@
       },
       useSearchForm: true,
       immediate: true,
-      columns: complianceColumns,
-      api: getComplianceCheck,
+      columns: windrectColumns,
+      api: getWindrectList,
       pagination: false,
       striped: true,
       bordered: true,
       showIndexColumn: true,
       showActionColumn: false,
+      // 单选一行测风装置,供左侧注册点位绑定
+      rowSelection: { type: 'radio' },
     },
   });
-  const [registerComplianceTable] = complianceCtx;
+  const [registerWindrectTable, windrectTable, { selectedRows: windrectSelectedRows }] = windrectCtx;
 
-  // ====== 判识模型参数表格 ======
+  // ====== 判识模型参数表格(暂注释,待接口就绪后恢复)======
+  /*
   const modelConfigs = ref<any[]>([]);
 
   async function loadModelConfigs() {
@@ -226,8 +245,10 @@
     },
   });
   const [registerModelConfigTable] = modelCtx;
+  */
 
-  // ====== 保存模型配置 ======
+  /*
+  // ====== 保存模型配置(暂注释,待接口就绪后恢复)======
   async function handleSaveModelConfig() {
     try {
       await saveModelConfigs({ configs: modelConfigs.value });
@@ -241,6 +262,45 @@
     modelConfigs.value = JSON.parse(JSON.stringify(defaultModelConfigs));
     message.success('已恢复默认配置');
   }
+  */
+
+  // ====== 绑定/解绑(addMineAreaRelation / deleteMineAreaRelation)======
+  async function handleBind(record: any) {
+    const windrect = windrectSelectedRows.value[0];
+    if (!windrect) {
+      message.warn('请先在右侧"上传数据布点"中选择要绑定的测风装置');
+      return;
+    }
+    try {
+      await addMineAreaRelation({ mineCode: record.mineCode, parentId: record.id, childId: windrect.id });
+      message.success('绑定成功');
+      pointTable?.reload();
+      windrectTable?.reload();
+    } catch {
+      message.error('绑定失败');
+    }
+  }
+
+  async function handleUnbind(record: any) {
+    try {
+      const res = await getMineAreaRelation({ mineCode: record.mineCode });
+      const relList = res?.mineAreaRelationList || [];
+      const windrectId = windrectSelectedRows.value[0]?.id || record.windrectId;
+      const rel =
+        relList.find((r: any) => r.parentId === record.id && r.childId === windrectId) ||
+        relList.find((r: any) => r.parentId === record.id || r.childId === record.id);
+      if (!rel) {
+        message.warn('未找到该测风点位的绑定关系');
+        return;
+      }
+      await deleteMineAreaRelation({ ids: rel.id });
+      message.success('解绑成功');
+      pointTable?.reload();
+      windrectTable?.reload();
+    } catch {
+      message.error('解绑失败');
+    }
+  }
 
   // ====== 新增/编辑点位弹窗 ======
   const isUpdate = ref(true);
@@ -274,7 +334,8 @@
     return setFieldsValue({ ...record });
   }
 
-  // ====== 判识模型参数编辑弹窗 ======
+  // ====== 判识模型参数编辑弹窗(暂注释,待接口就绪后恢复)======
+  /*
   const isModelUpdate = ref(true);
   const modelModalTitle = computed(() => (!isModelUpdate.value ? '新增判识模型参数' : '编辑判识模型参数'));
 
@@ -311,6 +372,7 @@
       setModelModalProps({ confirmLoading: false });
     }
   }
+  */
 
   async function handleDelete(record: any) {
     try {
@@ -368,7 +430,13 @@
     height: 100%;
   }
 
+  .bind-btn {
+    padding: 0 4px;
+  }
+
+  /*
   .config-note {
     margin-top: 12px;
   }
+  */
 </style>

+ 63 - 25
src/views/analysis/warningAnalysis/windPointManage/windPointManage.api.ts

@@ -1,13 +1,18 @@
 import { defHttp } from '/@/utils/http/axios';
+import { useMineDepartmentStore } from '/@/store/modules/mine';
 
 enum Api {
   getPointList = '/workingface/mineArea/getMineAreaList',
   addMineArea = '/workingface/mineArea/addMineArea',
   updateMineArea = '/workingface/mineArea/updateMineArea',
   deleteMineArea = '/workingface/mineArea/deleteMineArea',
-  getComplianceCheck = '/province/windpoint/getComplianceCheck',
-  getModelConfigs = '/province/windpoint/getModelConfigs',
-  saveModelConfigs = '/province/windpoint/saveModelConfigs',
+  getWindrectList = '/workingface/windrect/getWindrectList',
+  getWindrectRegulation = '/workingface/mineData/getWindrectRegulation',
+  getMineAreaRelation = '/workingface/mineArea/getMineAreaRelation',
+  addMineAreaRelation = '/workingface/mineArea/addMineAreaRelation',
+  deleteMineAreaRelation = '/workingface/mineArea/deleteMineAreaRelation',
+  /* getModelConfigs = '/province/windpoint/getModelConfigs',
+  saveModelConfigs = '/province/windpoint/saveModelConfigs', */
 }
 
 /** 模拟成功响应 */
@@ -15,41 +20,74 @@ const mockSuccess = { success: true, code: 200, message: '操作成功' };
 
 /** 模拟点位列表数据 */
 const mockPointList = [
-  { id: 'p001', mineCode: 'M001', name: '榆林执法处-大柳塔煤矿北翼回风巷', level: 4, airVolume: 1800, windrectId: 'W001', status: 'active', createTime: '2026-07-27 10:00:00' },
-  { id: 'p002', mineCode: 'M001', name: '榆林执法处-大柳塔煤矿南翼进风巷', level: 4, airVolume: 2100, windrectId: 'W002', status: 'active' },
-  { id: 'p003', mineCode: 'M002', name: '延安执法处-黄陵一号矿101工作面', level: 4, airVolume: 720, windrectId: 'W003', status: 'active' },
-  { id: 'p004', mineCode: 'M003', name: '铜川执法处-红柳林煤矿东翼回风大巷', level: 4, airVolume: 1600, windrectId: 'W004', status: 'active' },
-  { id: 'p005', mineCode: 'M001', name: '榆林执法处-活鸡兔煤矿副立井', level: 4, airVolume: 2800, windrectId: 'W005', status: 'active' },
-  { id: 'm001', mineCode: 'M101', name: '大柳塔煤矿', level: 3, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'm002', mineCode: 'M102', name: '活鸡兔煤矿', level: 3, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'm003', mineCode: 'M106', name: '黄陵一号矿', level: 3, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'm004', mineCode: 'M107', name: '红柳林煤矿', level: 3, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'e001', mineCode: 'M001', name: '榆林执法处', level: 2, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'e002', mineCode: 'M002', name: '延安执法处', level: 2, airVolume: 0, windrectId: '', status: 'active' },
-  { id: 'e003', mineCode: 'M003', name: '铜川执法处', level: 2, airVolume: 0, windrectId: '', status: 'active' },
+  { id: 'p001', mineCode: 'M001', name: '榆林执法处-大柳塔煤矿北翼回风巷', level: 4, airVolume: 1800, regulationId: '1', windrectId: 'W001', status: 'active', createTime: '2026-07-27 10:00:00' },
+  { id: 'p002', mineCode: 'M001', name: '榆林执法处-大柳塔煤矿南翼进风巷', level: 4, airVolume: 2100, regulationId: '1', windrectId: 'W002', status: 'active' },
+  { id: 'p003', mineCode: 'M002', name: '延安执法处-黄陵一号矿101工作面', level: 4, airVolume: 720, regulationId: '2', windrectId: 'W003', status: 'active' },
+  { id: 'p004', mineCode: 'M003', name: '铜川执法处-红柳林煤矿东翼回风大巷', level: 4, airVolume: 1600, regulationId: '2', windrectId: 'W004', status: 'active' },
+  { id: 'p005', mineCode: 'M001', name: '榆林执法处-活鸡兔煤矿副立井', level: 4, airVolume: 2800, regulationId: '3', windrectId: 'W005', status: 'active' },
+  { id: 'm001', mineCode: 'M101', name: '大柳塔煤矿', level: 3, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'm002', mineCode: 'M102', name: '活鸡兔煤矿', level: 3, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'm003', mineCode: 'M106', name: '黄陵一号矿', level: 3, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'm004', mineCode: 'M107', name: '红柳林煤矿', level: 3, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'e001', mineCode: 'M001', name: '榆林执法处', level: 2, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'e002', mineCode: 'M002', name: '延安执法处', level: 2, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
+  { id: 'e003', mineCode: 'M003', name: '铜川执法处', level: 2, airVolume: 0, regulationId: '', windrectId: '', status: 'active' },
 ];
 
 /** 获取 MineArea 列表(后端未部署时回退到模拟数据) */
-export const getPointList = (params?: any) =>
-  defHttp.post({ url: Api.getPointList, params }, { joinParamsToUrl: true }).catch(() => mockPointList);
+export const getPointList = (params?: any) => {
+  const p = { ...params };
+  // 搜索表单 MineCascader 提交的是部门 id,需换算为 API 查询条件要求的矿编码(fax)
+  if (p.deptId) {
+    const mine = useMineDepartmentStore().findDepartById(p.deptId);
+    if (mine?.fax) p.mineCode = mine.fax;
+    delete p.deptId;
+  }
+  return defHttp.post({ url: Api.getPointList, params: p }, { joinParamsToUrl: true }).catch(() => mockPointList);
+};
 
 /** 新增或编辑 MineArea(根据是否有 id 自动切换;后端未部署时返回模拟成功) */
 export const savePoint = (params?: any) => {
   const url = params?.id ? Api.updateMineArea : Api.addMineArea;
-  return defHttp.post({ url, params }).catch(() => mockSuccess);
+  const payload = { ...params };
+  // 表单 mineCode 为 MineCascader 的部门 id,需换算为 API 需要的矿编码(fax)
+  if (payload.mineCode) {
+    const mine = useMineDepartmentStore().findDepartById(payload.mineCode);
+    if (mine?.fax) payload.mineCode = mine.fax;
+  }
+  return defHttp.post({ url, params: payload }).catch(() => mockSuccess);
 };
 
-/** 删除 MineArea(直接模拟成功,不请求后端) */
-export const deletePoint = (_params?: any) => Promise.resolve(mockSuccess);
+/** 删除 MineArea(含关联关系;后端未部署时返回模拟成功) */
+export const deletePoint = (params?: any) =>
+  defHttp.post({ url: Api.deleteMineArea, params }, { joinParamsToUrl: true }).catch(() => mockSuccess);
+
+/** 根据矿ID查询下面所有测风装置信息(WindrectController.getWindrectList) */
+export const getWindrectList = (params?: any) =>
+  defHttp.post({ url: Api.getWindrectList, params }, { joinParamsToUrl: true });
+
+/** 查询规程值列表(MineDataController.getWindrectRegulation,无参数) */
+export const getWindrectRegulation = (params?: any) =>
+  defHttp.get({ url: Api.getWindrectRegulation, params }, { joinParamsToUrl: true });
+
+/** 查询 MineArea 关联关系(返回 { mineAreaList, mineAreaRelationList }) */
+export const getMineAreaRelation = (params?: any) =>
+  defHttp.post({ url: Api.getMineAreaRelation, params }, { joinParamsToUrl: true });
+
+/** 绑定 MineArea 关联关系(RequestBody:mineCode/parentId/childId) */
+export const addMineAreaRelation = (params?: any) =>
+  defHttp.post({ url: Api.addMineAreaRelation, params });
 
-/** 获取上传数据合规校验结果 */
-export const getComplianceCheck = (params?: any) =>
-  defHttp.post({ url: Api.getComplianceCheck, params }, { joinParamsToUrl: true });
+/** 删除 MineArea 关联关系(ids 必填,逗号分隔) */
+export const deleteMineAreaRelation = (params?: any) =>
+  defHttp.post({ url: Api.deleteMineAreaRelation, params }, { joinParamsToUrl: true });
 
-/** 获取判识模型配置 */
+/* ====== 判识模型配置接口(暂注释,待接口就绪后恢复)======
+/* 获取判识模型配置
 export const getModelConfigs = (params?: any) =>
   defHttp.post({ url: Api.getModelConfigs, params }, { joinParamsToUrl: true });
 
-/** 保存判识模型配置 */
+/* 保存判识模型配置
 export const saveModelConfigs = (params?: any) =>
   defHttp.post({ url: Api.saveModelConfigs, params }, { joinParamsToUrl: true });
+*/

+ 42 - 21
src/views/analysis/warningAnalysis/windPointManage/windPointManage.data.ts

@@ -2,6 +2,7 @@ import type { BasicColumn } from '/@/components/Table';
 import type { FormSchema } from '/@/components/Table';
 import { h } from 'vue';
 import { StatusColorEnum } from '/@/enums/jeecgEnum';
+import { getWindrectRegulation } from './windPointManage.api';
 
 /** 注册测风点位管理表格列 */
 export const pointColumns: BasicColumn[] = [
@@ -36,6 +37,11 @@ export const pointColumns: BasicColumn[] = [
     dataIndex: 'airVolume',
     width: 100,
   },
+  {
+    title: '规程值',
+    dataIndex: 'regulationId',
+    width: 90,
+  },
   {
     title: '测风设备',
     dataIndex: 'windrectId',
@@ -59,36 +65,38 @@ export const pointColumns: BasicColumn[] = [
   // },
 ];
 
-/** 上传数据布点合规校验表格列 */
-export const complianceColumns: BasicColumn[] = [
+/** 上传数据布点表格列(Windrect) */
+export const windrectColumns: BasicColumn[] = [
   {
-    title: '注册点位',
-    dataIndex: 'pointCode',
+    title: '设备编码',
+    dataIndex: 'deviceCode',
     width: 130,
     fixed: 'left',
   },
   {
-    title: '上传数据',
-    dataIndex: 'pointName',
-    width: 180,
+    title: '设备位置',
+    dataIndex: 'devicePos',
+    width: 200,
   },
   {
-    title: '校验结果',
-    dataIndex: 'checkResult',
+    title: '矿井名称',
+    dataIndex: 'mineName',
+    width: 160,
+  },
+  {
+    title: '状态',
+    dataIndex: 'status',
     width: 100,
     customRender: ({ text }) => {
-      const map: Record<string, { label: string; color: string }> = {
-        match: { label: '一致', color: StatusColorEnum.green },
-        missing: { label: '缺失报警', color: StatusColorEnum.red },
-        unregistered: { label: '未注册提醒', color: StatusColorEnum.orange },
-      };
-      const info = map[text];
-      return info ? h('span', { style: { color: info.color, fontWeight: 'bold' } }, info.label) : text;
+      const normal = String(text) === '1';
+      const color = normal ? StatusColorEnum.green : StatusColorEnum.red;
+      const label = normal ? '正常' : '停用';
+      return h('span', { style: { color, fontWeight: 'bold' } }, label);
     },
   },
   {
-    title: '问题说明',
-    dataIndex: 'uploadPointName',
+    title: '创建时间',
+    dataIndex: 'createTime',
     width: 160,
   },
 ];
@@ -136,6 +144,17 @@ export const formSchema: FormSchema[] = [
       style: 'width: 100%',
     },
   },
+  {
+    label: '规程值',
+    field: 'regulationId',
+    component: 'ApiSelect',
+    componentProps: {
+      api: getWindrectRegulation,
+      labelField: 'name',
+      valueField: 'id',
+      placeholder: '请选择规程值',
+    },
+  },
   {
     label: '测风设备',
     field: 'windrectId',
@@ -146,7 +165,8 @@ export const formSchema: FormSchema[] = [
   },
 ];
 
-/** 判识模型参数配置表格列 */
+/* ====== 判识模型管理(暂注释,待接口就绪后恢复)======
+/* 判识模型参数配置表格列
 export const modelConfigColumns: BasicColumn[] = [
   {
     title: '判识指标',
@@ -188,7 +208,7 @@ export const modelConfigColumns: BasicColumn[] = [
   },
 ];
 
-/** 判识模型参数编辑表单(与 modelConfigColumns 字段对齐) */
+/* 判识模型参数编辑表单(与 modelConfigColumns 字段对齐)
 export const modelConfigFormSchema: FormSchema[] = [
   {
     label: '判识指标',
@@ -248,7 +268,7 @@ export const modelConfigFormSchema: FormSchema[] = [
   },
 ];
 
-/** 判识模型默认配置数据 */
+/* 判识模型默认配置数据
 export const defaultModelConfigs = [
   {
     paramName: '风速上限',
@@ -315,3 +335,4 @@ export const defaultModelConfigs = [
     description: '采区有效风量率低于此值即触发预警',
   },
 ];
+*/

+ 50 - 52
src/views/analysis/warningAnalysis/windPointManage/windTopology/hooks/useTopology.ts

@@ -9,10 +9,15 @@ import {
   nodeDetailFields,
   levelY,
   weightKey,
-  isOneToManyChild,
 } from '../windTopology.data';
 import type { TopologyData, TopoNodeData } from '../windTopology.data';
-import { addMineAreaRelation, deleteMineAreaRelation, getTopologyData } from '../windTopology.api';
+import { transformToTopologyData } from '../windTopology.data';
+import { getTopologyData, resolveMineCode } from '../windTopology.api';
+import { addMineAreaRelation, deleteMineAreaRelation } from '../../windPointManage.api';
+
+/** 节点分类索引:0=测风点位(源),1=数据布点(目标) */
+const CAT_POINT = 0;
+const CAT_DEVICE = 1;
 
 export function useTopology() {
   const chartRef = ref<HTMLDivElement | null>(null);
@@ -36,7 +41,7 @@ export function useTopology() {
     return chartInstance;
   }
 
-  // ==================== 层级布局 ====================
+  // ==================== 两行布局 ====================
 
   function applyHierarchicalLayout(echartsNodes: any[], forceUnfixed = false, chartW = 1200, chartH = 700) {
     const groups: Record<number, any[]> = {};
@@ -155,7 +160,6 @@ export function useTopology() {
       // 普通模式下拖拽 → 高亮关联路径(节点不移动)
       if (!editMode.value) {
         highlightPath(params.data.id);
-        // fixed 节点拖不动,但触发高亮后复位
         return;
       }
 
@@ -167,11 +171,17 @@ export function useTopology() {
   // ==================== 选择目标态 ====================
 
   function enterSelectMode(sourceId: string) {
+    const src = topologyData.nodes.find((n) => n.id === sourceId);
+    if (!src) return;
+    // 仅允许以「测风点位」为绑定源
+    if (src.category !== CAT_POINT) {
+      message.info('请双击「测风点位」节点作为绑定源,再单击「数据布点」节点绑定');
+      return;
+    }
     selectMode.value = true;
     selectedSourceId.value = sourceId;
-    const src = topologyData.nodes.find((n) => n.id === sourceId);
     highlightPath(sourceId);
-    message.info(`已选中"${src?.name || sourceId}",请单击另一节点进行绑定。双击空白处取消。`);
+    message.info(`已选中"${src.name}",请单击一个「数据布点」节点进行绑定。双击空白处取消。`);
   }
 
   function exitSelectMode() {
@@ -192,6 +202,12 @@ export function useTopology() {
     const tgt = topologyData.nodes.find((n) => n.id === targetId);
     if (!src || !tgt) return;
 
+    // 仅允许「测风点位」→「数据布点」方向(与测风点位管理一致)
+    if (src.category !== CAT_POINT || tgt.category !== CAT_DEVICE) {
+      message.warning('仅支持「测风点位」绑定到「数据布点」');
+      return;
+    }
+
     // 检查是否已存在该绑定
     const exists = topologyData.links.some((l) => l.source === sourceId && l.target === targetId);
     if (exists) {
@@ -199,46 +215,22 @@ export function useTopology() {
       return;
     }
 
-    async function doBind() {
-      try {
-        await addMineAreaRelation({ parentId: sourceId, childId: targetId });
-        const freshData = await getTopologyData({ mineCode: 'M001' });
-        renderTopology(freshData, true);
-        message.success(`绑定成功:${src!.name} → ${tgt!.name}`);
-      } catch {
-        message.error('绑定失败');
-      }
-    }
-
-    if (isOneToManyChild(tgt.category)) {
-      // ——— 一对多:覆盖绑定 ———
-      const existingLink = topologyData.links.find((l) => l.target === targetId);
-      const oldName = existingLink
-        ? topologyData.nodes.find((n) => n.id === existingLink.source)?.name || '未知'
-        : '无';
-
-      Modal.confirm({
-        title: '确认覆盖绑定',
-        content: `"${tgt.name}" 当前从属于 "${oldName}",是否覆盖为从属于 "${src.name}"?`,
-        okText: '确认覆盖',
-        cancelText: '取消',
-        onOk: async () => {
-          if (existingLink?.id) {
-            await deleteMineAreaRelation({ ids: existingLink.id });
-          }
-          await doBind();
-        },
-      });
-    } else {
-      // ——— 多对多:直接绑定 ———
-      Modal.confirm({
-        title: '确认绑定',
-        content: `确认建立"${src.name}" → "${tgt.name}"的绑定关系?`,
-        okText: '确认绑定',
-        cancelText: '取消',
-        onOk: doBind,
-      });
-    }
+    Modal.confirm({
+      title: '确认绑定',
+      content: `确认建立"${src.name}" → "${tgt.name}"的绑定关系?`,
+      okText: '确认绑定',
+      cancelText: '取消',
+      onOk: async () => {
+        try {
+          await addMineAreaRelation({ mineCode: resolveMineCode(), parentId: sourceId, childId: targetId });
+          const freshData = await getTopologyData({ mineCode: resolveMineCode() });
+          renderTopology(transformToTopologyData(freshData), true);
+          message.success(`绑定成功:${src!.name} → ${tgt!.name}`);
+        } catch {
+          message.error('绑定失败');
+        }
+      },
+    });
   }
 
   // ==================== 解绑逻辑 ====================
@@ -256,10 +248,12 @@ export function useTopology() {
         if (link?.id) {
           try {
             await deleteMineAreaRelation({ ids: link.id });
-            const freshData = await getTopologyData({ mineCode: 'M001' });
-            renderTopology(freshData, true);
+            const freshData = await getTopologyData({ mineCode: resolveMineCode() });
+            renderTopology(transformToTopologyData(freshData), true);
             message.success('解绑成功');
-          } catch { message.error('解绑失败'); }
+          } catch {
+            message.error('解绑失败');
+          }
         } else {
           message.warning('未找到对应绑定关系');
         }
@@ -331,7 +325,7 @@ export function useTopology() {
     if (on) {
       renderTopology(topologyData, true);
       chartInstance.setOption({ series: [{ roam: false }] as any });
-      message.info('绑定模式已开启:双击节点选择源 → 单击另一节点绑定;双击连线解绑');
+      message.info('绑定模式已开启:双击「测风点位」节点选择源 → 单击「数据布点」节点绑定;双击连线解绑');
     } else {
       renderTopology(topologyData);
       message.info('已退出绑定模式');
@@ -340,7 +334,9 @@ export function useTopology() {
 
   // ==================== resize / dispose ====================
 
-  function handleResize() { chartInstance?.resize(); }
+  function handleResize() {
+    chartInstance?.resize();
+  }
 
   function dispose() {
     window.removeEventListener('resize', handleResize);
@@ -356,7 +352,9 @@ export function useTopology() {
     detailFields,
     initChart,
     renderTopology,
-    zoomIn, zoomOut, resetView,
+    zoomIn,
+    zoomOut,
+    resetView,
     highlightPath,
     setEditMode,
     clearSelection,

+ 3 - 3
src/views/analysis/warningAnalysis/windPointManage/windTopology/index.vue

@@ -19,7 +19,7 @@
           刷新
         </a-button>
         <a-divider type="vertical" />
-        <span v-if="editMode" class="select-text">双击节点启用节点绑定,单击目标节点确认;双击连线解绑</span>
+        <span v-if="editMode" class="select-text">双击「测风点位」节点选择绑定源,单击「数据布点」节点确认绑定;双击连线解绑</span>
       </div>
 
       <!-- 图例 -->
@@ -70,7 +70,7 @@
   import { ref, onMounted, onUnmounted } from 'vue';
   import { SvgIcon } from '/@/components/Icon';
   import { categories } from './windTopology.data';
-  import { getTopologyData } from './windTopology.api';
+  import { getTopologyData, resolveMineCode } from './windTopology.api';
   import { useTopology } from './hooks/useTopology';
 
   const {
@@ -94,7 +94,7 @@
     setEditMode(!editMode.value);
   }
 
-  const mineCode = ref('M001');
+  const mineCode = ref(resolveMineCode());
 
   async function refreshData() {
     try {

+ 21 - 29
src/views/analysis/warningAnalysis/windPointManage/windTopology/windTopology.api.ts

@@ -1,38 +1,30 @@
 import { defHttp } from '/@/utils/http/axios';
-import type { TopologyData, MineAreaApiResponse, MineAreaRelation } from './windTopology.data';
-import { transformToTopologyData, mockMineAreaApiResponse } from './windTopology.data';
+import { useMineDepartmentStore } from '/@/store/modules/mine';
+import type { MineAreaApiResponse, WindrectNode } from './windTopology.data';
 
 enum Api {
   getMineAreaRelation = '/workingface/mineArea/getMineAreaRelation',
-  addMineAreaRelation = '/workingface/mineArea/addMineAreaRelation',
-  deleteMineAreaRelation = '/workingface/mineArea/deleteMineAreaRelation',
+  getWindrectList = '/workingface/windrect/getWindrectList',
 }
 
-/** 模拟成功响应 */
-const mockSuccess = { success: true, code: 200, message: '操作成功' };
-
-/** 获取拓扑结构(后端未部署时回退到模拟数据) */
-export const getTopologyData = (params?: any): Promise<TopologyData> =>
-  defHttp
-    .post<MineAreaApiResponse>({ url: Api.getMineAreaRelation, params }, { joinParamsToUrl: true })
-    .then((res) => transformToTopologyData(res))
-    .catch(() => transformToTopologyData(mockMineAreaApiResponse));
-
-/** 绑定关联关系(直接更新模拟数据,供下次 getTopologyData 读取) */
-export const addMineAreaRelation = (params: { mineCode?: string; parentId: string; childId: string }): Promise<any> => {
-  const newRel: MineAreaRelation = {
-    id: `rel-mock-${Date.now()}`,
-    mineCode: params.mineCode || 'M001',
-    parentId: params.parentId,
-    childId: params.childId,
-  };
-  mockMineAreaApiResponse.mineAreaRelationList.push(newRel);
-  return defHttp.post({ url: Api.addMineAreaRelation, params }).catch(() => mockSuccess);
+/** 解析当前矿编码:取组织树根节点(当前登录机构)的 id,无值时保留 'M001' 兜底 */
+export const resolveMineCode = (): string => {
+  const rootId = useMineDepartmentStore().getRoot?.id;
+  return rootId || 'M001';
 };
 
-/** 解绑关联关系(直接更新模拟数据,供下次 getTopologyData 读取) */
-export const deleteMineAreaRelation = (params: { ids: string }): Promise<any> => {
-  const idx = mockMineAreaApiResponse.mineAreaRelationList.findIndex((r) => r.id === params.ids);
-  if (idx > -1) mockMineAreaApiResponse.mineAreaRelationList.splice(idx, 1);
-  return defHttp.post({ url: Api.deleteMineAreaRelation, params }, { joinParamsToUrl: true }).catch(() => mockSuccess);
+/** 获取测风点位/数据布点绑定关系(getMineAreaRelation + getWindrectList,均为真实接口) */
+export const getTopologyData = async (params?: any): Promise<MineAreaApiResponse> => {
+  const p = { ...params };
+  if (!p.mineCode) p.mineCode = resolveMineCode();
+  const [relationRes, windrectRes] = await Promise.all([
+    defHttp.post({ url: Api.getMineAreaRelation, params: p }, { joinParamsToUrl: true }),
+    defHttp.post({ url: Api.getWindrectList, params: p }, { joinParamsToUrl: true }),
+  ]);
+  const windrectList: WindrectNode[] = Array.isArray(windrectRes) ? windrectRes : [];
+  return {
+    mineAreaList: relationRes?.mineAreaList || [],
+    mineAreaRelationList: relationRes?.mineAreaRelationList || [],
+    windrectList,
+  };
 };

+ 88 - 146
src/views/analysis/warningAnalysis/windPointManage/windTopology/windTopology.data.ts

@@ -9,12 +9,10 @@ export interface CategoryDef {
   symbolSize: number; // 节点大小
 }
 
-/** 4 类节点:省局、执法处、煤矿、测风点 */
+/** 2 类节点:测风点位(注册的 level=4 测风点)、数据布点(Windrect 测风装置) */
 export const categories: CategoryDef[] = [
-  { name: '省局', color: '#0960bd', symbol: 'diamond', symbolSize: 50 },
-  { name: '执法处', color: '#1890ff', symbol: 'roundRect', symbolSize: 40 },
-  { name: '煤矿', color: '#52c41a', symbol: 'circle', symbolSize: 35 },
-  { name: '测风点', color: '#fa8c16', symbol: 'pin', symbolSize: 25 },
+  { name: '测风点位', color: '#fa8c16', symbol: 'pin', symbolSize: 30 },
+  { name: '数据布点', color: '#1890ff', symbol: 'roundRect', symbolSize: 28 },
 ];
 
 // ==================== 状态颜色映射 ====================
@@ -25,17 +23,14 @@ export const statusColorMap: Record<string, string> = {
   offline: '#999999', // 离线
 };
 
-// ==================== 层级布局参数(树形但本质是图) ====================
+// ==================== 两行布局参数 ====================
 
-/** 每个层级在画布高度中的百分比 y 坐标(从上到下) */
-export const levelY = [8, 30, 55, 85]; // 省局、执法处、煤矿、测风点
+/** 每个分类在画布高度中的百分比 y 坐标(从上到下):测风点位在上、数据布点在下 */
+export const levelY = [30, 70];
 
 /** 每类节点用于排序的权重字段(值越大越靠左) */
 export const weightKey: Record<number, string> = {
-  0: 'childCount', // 省局
-  1: 'childCount', // 执法处
-  2: 'childCount', // 煤矿(按管辖测风点数排序)
-  3: 'windVolume', // 测风点
+  0: 'childCount', // 测风点位:按已绑定数据布点数排序
 };
 
 /** 节点横向间距基数(px),实际 = basePadding / 该层节点数 */
@@ -85,59 +80,34 @@ export interface DetailField {
 }
 
 export const nodeDetailFields: Record<string, DetailField[]> = {
-  省局: [
-    { label: '机构名称', key: 'name' },
-    { label: '管辖执法处数', key: 'childCount' },
+  测风点位: [
+    { label: '测风点位名称', key: 'name' },
+    { label: '风量(m³/min)', key: 'windVolume' },
+    { label: '已绑定数据布点数', key: 'childCount' },
+    { label: '测风设备ID', key: 'windrectId' },
   ],
-  执法处: [
-    { label: '名称', key: 'name' },
-    { label: '管辖煤矿数', key: 'childCount' },
-    { label: '在线率', key: 'onlineRate' },
-  ],
-  煤矿: [
-    { label: '煤矿名称', key: 'name' },
-    { label: '测风点数', key: 'childCount' },
-    { label: '在线/应接', key: 'onlineRatio' },
-    { label: '风量异常', key: 'windAbnormal' },
-  ],
-  测风点: [
-    { label: '测风点名称', key: 'name' },
-    { label: '实时风速', key: 'windSpeed' },
-    { label: '实时风量', key: 'windVolume' },
-    { label: '状态', key: 'status' },
+  数据布点: [
+    { label: '设备编码', key: 'deviceCode' },
+    { label: '设备位置', key: 'devicePos' },
+    { label: '矿井名称', key: 'mineName' },
+    { label: '状态', key: 'statusText' },
   ],
 };
 
-// ==================== 多对多 + 一对多 关系类型 ====================
-
-/** 测风点分类索引(一对多的子端) */
-export const CHILD_CATEGORY = 3;
-
-/**
- * 判断目标分类是否为一对多关系的"子端"
- * 一对多:煤矿(2)→测风点(3),一个测风点只能属于一个煤矿
- * 多对多:执法处(1)↔煤矿(2),一个执法处管多个矿,一个矿可被多个执法处管
- */
-export function isOneToManyChild(category: number): boolean {
-  return category === CHILD_CATEGORY;
-}
-
-/** 拖拽绑定时判定"吸附"的距离阈值(像素) */
-export const BIND_THRESHOLD = 35;
-
-// ==================== 模拟拓扑数据 ====================
+// ==================== 拓扑数据类型 ====================
 
 export interface TopoNodeData {
   id: string;
   name: string;
   category: number; // categories 索引
   status?: string; // normal / abnormal / offline
-  windSpeed?: number;
   windVolume?: number;
   childCount?: number;
-  onlineRate?: string;
-  onlineRatio?: string;
-  windAbnormal?: number;
+  windrectId?: string;
+  mineCode?: string;
+  deviceCode?: string;
+  devicePos?: string;
+  mineName?: string;
   [key: string]: any;
 }
 
@@ -155,13 +125,14 @@ export interface TopologyData {
 
 // ==================== API 响应类型 ====================
 
-/** API -> MineArea 节点 */
+/** API -> MineArea 节点(注册的测风点位) */
 export interface MineAreaNode {
   id: string;
   mineCode: string;
   name: string;
   level: number; // 1=省局 2=执法处 3=煤矿 4=测风点
   airVolume: number;
+  regulationId?: string;
   windrectId: string;
   createTime?: string;
   updateTime?: string;
@@ -178,110 +149,81 @@ export interface MineAreaRelation {
   updateTime?: string;
 }
 
-/** API -> getMineAreaRelation 返回值 */
+/** API -> Windrect(数据布点/测风装置) */
+export interface WindrectNode {
+  id: string;
+  mineCode: string;
+  mineName?: string;
+  deviceCode?: string;
+  devicePos?: string;
+  status?: number;
+  createTime?: string;
+  [key: string]: any;
+}
+
+/** API -> getTopologyData 合并返回值 */
 export interface MineAreaApiResponse {
   mineAreaList: MineAreaNode[];
   mineAreaRelationList: MineAreaRelation[];
+  windrectList: WindrectNode[];
 }
 
-/** level(1-4) 转 category(0-3) */
-const levelToCategory: Record<number, number> = { 1: 0, 2: 1, 3: 2, 4: 3 };
+/** 状态渲染文本 */
+export const statusTextMap: Record<string, string> = {
+  normal: '正常',
+  abnormal: '异常',
+  offline: '离线',
+};
 
 /**
  * 将 API 响应转换为 TopologyData
- * mineAreaList -> nodes, mineAreaRelationList -> links
+ * mineAreaList(level=4) -> 测风点位节点,windrectList -> 数据布点节点,
+ * mineAreaRelationList(parentId=测风点位, childId=数据布点) -> 边
  */
 export function transformToTopologyData(apiResp: MineAreaApiResponse): TopologyData {
-  const { mineAreaList = [], mineAreaRelationList = [] } = apiResp;
-
-  // 计算每个节点的子节点数
-  const childCountMap: Record<string, number> = {};
-  for (const rel of mineAreaRelationList) {
-    childCountMap[rel.parentId] = (childCountMap[rel.parentId] || 0) + 1;
-  }
+  const { mineAreaList = [], mineAreaRelationList = [], windrectList = [] } = apiResp;
 
-  const nodes: TopoNodeData[] = mineAreaList.map((item) => ({
-    id: item.id,
-    name: item.name,
-    category: levelToCategory[item.level] ?? 0,
-    status: 'normal',
-    windVolume: item.airVolume,
-    childCount: childCountMap[item.id] || 0,
-    mineCode: item.mineCode,
-    windrectId: item.windrectId,
-  }));
+  const pointIds = new Set<string>(
+    mineAreaList.filter((item) => Number(item.level) === 4).map((item) => item.id)
+  );
+  const deviceIds = new Set<string>(windrectList.map((item) => item.id));
 
-  const links: TopoLinkData[] = mineAreaRelationList.map((rel) => ({
-    source: rel.parentId,
-    target: rel.childId,
-    id: rel.id,
-  }));
+  // 边:仅保留两端都能在图中找到的绑定关系(测风点位→数据布点)
+  const childCountMap: Record<string, number> = {};
+  const links: TopoLinkData[] = mineAreaRelationList
+    .filter((rel) => pointIds.has(rel.parentId) && deviceIds.has(rel.childId))
+    .map((rel) => {
+      childCountMap[rel.parentId] = (childCountMap[rel.parentId] || 0) + 1;
+      return { source: rel.parentId, target: rel.childId, id: rel.id };
+    });
+
+  const nodes: TopoNodeData[] = [
+    // 测风点位节点
+    ...mineAreaList
+      .filter((item) => Number(item.level) === 4)
+      .map((item) => ({
+        id: item.id,
+        name: item.name,
+        category: 0,
+        status: 'normal',
+        windVolume: item.airVolume,
+        childCount: childCountMap[item.id] || 0,
+        windrectId: item.windrectId,
+        mineCode: item.mineCode,
+      })),
+    // 数据布点节点(Windrect 测风装置)
+    ...windrectList.map((item) => ({
+      id: item.id,
+      name: item.devicePos || item.deviceCode || item.id,
+      category: 1,
+      status: String(item.status) === '1' ? 'normal' : 'offline',
+      statusText: String(item.status) === '1' ? '正常' : '停用',
+      deviceCode: item.deviceCode,
+      devicePos: item.devicePos,
+      mineName: item.mineName,
+      mineCode: item.mineCode,
+    })),
+  ];
 
   return { nodes, links };
 }
-
-// ==================== 模拟 API 响应数据(后端未部署时回退) ====================
-
-/** 模拟 getMineAreaRelation 的 API 响应 */
-export const mockMineAreaApiResponse: MineAreaApiResponse = {
-  mineAreaList: [
-    // === 省局 level=1 ===
-    { id: 'province', mineCode: 'M000', name: '陕西省煤矿安全监察局', level: 1, airVolume: 0, windrectId: '' },
-    // === 执法处 level=2 ===
-    { id: 'enf-1', mineCode: 'M001', name: '榆林执法处', level: 2, airVolume: 0, windrectId: '' },
-    { id: 'enf-2', mineCode: 'M002', name: '延安执法处', level: 2, airVolume: 0, windrectId: '' },
-    { id: 'enf-3', mineCode: 'M003', name: '铜川执法处', level: 2, airVolume: 0, windrectId: '' },
-    { id: 'enf-4', mineCode: 'M004', name: '渭南执法处', level: 2, airVolume: 0, windrectId: '' },
-    { id: 'enf-5', mineCode: 'M005', name: '咸阳执法处', level: 2, airVolume: 0, windrectId: '' },
-    // === 煤矿 level=3 ===
-    { id: 'mine-1', mineCode: 'M101', name: '大柳塔煤矿', level: 3, airVolume: 0, windrectId: 'W001' },
-    { id: 'mine-2', mineCode: 'M102', name: '活鸡兔煤矿', level: 3, airVolume: 0, windrectId: 'W002' },
-    { id: 'mine-3', mineCode: 'M103', name: '哈拉沟煤矿', level: 3, airVolume: 0, windrectId: 'W003' },
-    { id: 'mine-4', mineCode: 'M104', name: '榆家梁煤矿', level: 3, airVolume: 0, windrectId: 'W004' },
-    { id: 'mine-5', mineCode: 'M105', name: '三道沟煤矿', level: 3, airVolume: 0, windrectId: 'W005' },
-    { id: 'mine-6', mineCode: 'M106', name: '黄陵一号矿', level: 3, airVolume: 0, windrectId: 'W006' },
-    { id: 'mine-7', mineCode: 'M107', name: '红柳林煤矿', level: 3, airVolume: 0, windrectId: 'W007' },
-    { id: 'mine-8', mineCode: 'M108', name: '凉水井煤矿', level: 3, airVolume: 0, windrectId: 'W008' },
-    // === 测风点 level=4 ===
-    { id: 'point-1', mineCode: 'M001', name: '北翼回风巷', level: 4, airVolume: 1800, windrectId: 'W101' },
-    { id: 'point-2', mineCode: 'M001', name: '南翼进风巷', level: 4, airVolume: 2100, windrectId: 'W102' },
-    { id: 'point-3', mineCode: 'M001', name: '三采区回风巷', level: 4, airVolume: 950, windrectId: 'W103' },
-    { id: 'point-4', mineCode: 'M001', name: '主斜井', level: 4, airVolume: 3200, windrectId: 'W104' },
-    { id: 'point-5', mineCode: 'M002', name: '副立井', level: 4, airVolume: 2800, windrectId: 'W105' },
-    { id: 'point-6', mineCode: 'M002', name: '二盘区回风巷', level: 4, airVolume: 1350, windrectId: 'W106' },
-    { id: 'point-7', mineCode: 'M002', name: '101工作面', level: 4, airVolume: 720, windrectId: 'W107' },
-    { id: 'point-8', mineCode: 'M003', name: '102工作面', level: 4, airVolume: 880, windrectId: 'W108' },
-    { id: 'point-9', mineCode: 'M003', name: '东翼回风大巷', level: 4, airVolume: 1600, windrectId: 'W109' },
-    { id: 'point-10', mineCode: 'M004', name: '西翼进风大巷', level: 4, airVolume: 1500, windrectId: 'W110' },
-  ],
-  mineAreaRelationList: [
-    // 省局→执法处
-    { id: 'rel-1', mineCode: 'M000', parentId: 'province', childId: 'enf-1' },
-    { id: 'rel-2', mineCode: 'M000', parentId: 'province', childId: 'enf-2' },
-    { id: 'rel-3', mineCode: 'M000', parentId: 'province', childId: 'enf-3' },
-    { id: 'rel-4', mineCode: 'M000', parentId: 'province', childId: 'enf-4' },
-    { id: 'rel-5', mineCode: 'M000', parentId: 'province', childId: 'enf-5' },
-    // 执法处→煤矿
-    { id: 'rel-6', mineCode: 'M001', parentId: 'enf-1', childId: 'mine-1' },
-    { id: 'rel-7', mineCode: 'M001', parentId: 'enf-1', childId: 'mine-2' },
-    { id: 'rel-8', mineCode: 'M001', parentId: 'enf-1', childId: 'mine-3' },
-    { id: 'rel-9', mineCode: 'M002', parentId: 'enf-2', childId: 'mine-4' },
-    { id: 'rel-10', mineCode: 'M002', parentId: 'enf-2', childId: 'mine-5' },
-    { id: 'rel-11', mineCode: 'M003', parentId: 'enf-3', childId: 'mine-6' },
-    { id: 'rel-12', mineCode: 'M003', parentId: 'enf-3', childId: 'mine-7' },
-    { id: 'rel-13', mineCode: 'M004', parentId: 'enf-4', childId: 'mine-1' },
-    { id: 'rel-14', mineCode: 'M005', parentId: 'enf-5', childId: 'mine-7' },
-    { id: 'rel-15', mineCode: 'M005', parentId: 'enf-5', childId: 'mine-8' },
-    // 煤矿→测风点
-    { id: 'rel-16', mineCode: 'M101', parentId: 'mine-1', childId: 'point-1' },
-    { id: 'rel-17', mineCode: 'M101', parentId: 'mine-1', childId: 'point-2' },
-    { id: 'rel-18', mineCode: 'M101', parentId: 'mine-1', childId: 'point-3' },
-    { id: 'rel-19', mineCode: 'M101', parentId: 'mine-1', childId: 'point-4' },
-    { id: 'rel-20', mineCode: 'M102', parentId: 'mine-2', childId: 'point-5' },
-    { id: 'rel-21', mineCode: 'M102', parentId: 'mine-2', childId: 'point-6' },
-    { id: 'rel-22', mineCode: 'M102', parentId: 'mine-2', childId: 'point-7' },
-    { id: 'rel-23', mineCode: 'M103', parentId: 'mine-3', childId: 'point-8' },
-    { id: 'rel-24', mineCode: 'M103', parentId: 'mine-3', childId: 'point-9' },
-    { id: 'rel-25', mineCode: 'M104', parentId: 'mine-4', childId: 'point-10' },
-  ],
-};

+ 0 - 232
src/views/analysis/warningAnalysis/windSpeedOverlimit/windSpeedOverlimit.data.ts

@@ -1,232 +0,0 @@
-import type { BasicColumn, FormSchema } from '/@/components/Table';
-import { h } from 'vue';
-import { StatusColorEnum } from '/@/enums/jeecgEnum';
-
-/** 顶部统计卡片 */
-export const boardData = [
-  { label: '风速超限报警', value: '-' },
-  { label: '风量不足报警', value: '-' },
-  { label: '风量不闭合报警', value: '-' },
-  { label: '今日已处理报警', value: '-' },
-];
-
-/** 报警级别映射 */
-export const alarmLevelMap: Record<string, { label: string; color: string }> = {
-  '1': { label: '一级', color: StatusColorEnum.red },
-  '2': { label: '二级', color: StatusColorEnum.orange },
-  '3': { label: '三级', color: StatusColorEnum.yellow },
-};
-
-/** 报警状态映射 */
-export const alarmStatusMap: Record<string, { label: string; color: string }> = {
-  '0': { label: '未处理', color: StatusColorEnum.red },
-  '1': { label: '处理中', color: StatusColorEnum.orange },
-  '2': { label: '已处理', color: StatusColorEnum.green },
-};
-
-/** 超限报警列表表格列 */
-export const columns: BasicColumn[] = [
-  {
-    title: '煤矿名称',
-    dataIndex: 'mineName',
-    fixed: 'left',
-    width: 180,
-  },
-  {
-    title: '测风点名称',
-    dataIndex: 'pointName',
-    width: 160,
-  },
-  {
-    title: '监测区域',
-    dataIndex: 'monitorArea',
-    width: 120,
-  },
-  {
-    title: '报警类型',
-    dataIndex: 'alarmType',
-    width: 120,
-    customRender: ({ text }) => {
-      const map: Record<string, string> = {
-        windSpeedOver: '风速超限',
-        windVolumeLow: '风量不足',
-        windVolumeUnclosed: '风量不闭合',
-      };
-      return map[text] || text;
-    },
-  },
-  {
-    title: '实测值',
-    dataIndex: 'measuredValue',
-    width: 100,
-  },
-  {
-    title: '标准/阈值',
-    dataIndex: 'thresholdValue',
-    width: 100,
-  },
-  {
-    title: '偏差',
-    dataIndex: 'deviation',
-    width: 90,
-    customRender: ({ text }) => (text != null ? `${text}%` : '-'),
-  },
-  {
-    title: '报警级别',
-    dataIndex: 'alarmLevel',
-    width: 90,
-    customRender: ({ text }) => {
-      const info = alarmLevelMap[text];
-      return info ? h('span', { style: { color: info.color, fontWeight: 'bold' } }, info.label) : text;
-    },
-  },
-  {
-    title: '报警时间',
-    dataIndex: 'alarmTime',
-    width: 170,
-  },
-  {
-    title: '状态',
-    dataIndex: 'status',
-    width: 90,
-    customRender: ({ text }) => {
-      const info = alarmStatusMap[text];
-      return info ? h('span', { style: { color: info.color } }, info.label) : text;
-    },
-  },
-];
-
-/** 测风点监测地点列表表格列 */
-export const pointListColumns: BasicColumn[] = [
-  {
-    title: '测风点编号',
-    dataIndex: 'pointCode',
-    width: 130,
-  },
-  {
-    title: '监测地点名称',
-    dataIndex: 'locationName',
-    width: 200,
-  },
-  {
-    title: '类型',
-    dataIndex: 'pointType',
-    width: 120,
-    customRender: ({ text }) => {
-      const map: Record<string, string> = {
-        totalInlet: '总进风',
-        totalOutlet: '总回风',
-        workingFace: '工作面',
-        districtReturn: '采区回风',
-        headingFace: '掘进面',
-      };
-      return map[text] || text;
-    },
-  },
-  {
-    title: '当前状态',
-    dataIndex: 'currentStatus',
-    width: 100,
-    customRender: ({ text }) => {
-      const color = text === 'normal' ? StatusColorEnum.green : StatusColorEnum.red;
-      const label = text === 'normal' ? '正常' : '异常';
-      return h('span', { style: { color, fontWeight: 'bold' } }, label);
-    },
-  },
-];
-
-/** 查询表单 */
-export const schemas: FormSchema[] = [
-  {
-    label: '煤矿名称',
-    field: 'deptId',
-    component: 'MineCascader',
-    colProps: { span: 6 },
-    rules: [],
-  },
-  {
-    label: '报警类型',
-    field: 'alarmType',
-    component: 'Select',
-    colProps: { span: 6 },
-    componentProps: {
-      options: [
-        { label: '全部', value: '' },
-        { label: '风速超限', value: 'windSpeedOver' },
-        { label: '风量不足', value: 'windVolumeLow' },
-        { label: '风量不闭合', value: 'windVolumeUnclosed' },
-      ],
-    },
-    rules: [],
-  },
-  {
-    label: '报警级别',
-    field: 'alarmLevel',
-    component: 'Select',
-    colProps: { span: 6 },
-    componentProps: {
-      options: [
-        { label: '全部', value: '' },
-        { label: '一级', value: '1' },
-        { label: '二级', value: '2' },
-        { label: '三级', value: '3' },
-      ],
-    },
-    rules: [],
-  },
-  {
-    label: '日期范围',
-    field: 'dateRange',
-    component: 'RangePicker',
-    colProps: { span: 8 },
-    componentProps: {
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
-      showTime: { format: 'HH:mm:ss' },
-    },
-    rules: [],
-  },
-];
-
-/** 处理记录表格列 */
-export const handleRecordColumns: BasicColumn[] = [
-  {
-    title: '煤矿名称',
-    dataIndex: 'mineName',
-    fixed: 'left',
-    width: 180,
-  },
-  {
-    title: '报警类型',
-    dataIndex: 'alarmType',
-    width: 120,
-    customRender: ({ text }) => {
-      const map: Record<string, string> = {
-        windSpeedOver: '风速超限',
-        windVolumeLow: '风量不足',
-        windVolumeUnclosed: '风量不闭合',
-      };
-      return map[text] || text;
-    },
-  },
-  {
-    title: '测风点名称',
-    dataIndex: 'pointName',
-    width: 160,
-  },
-  {
-    title: '处理人',
-    dataIndex: 'handler',
-    width: 100,
-  },
-  {
-    title: '处理情况',
-    dataIndex: 'handleContent',
-    width: 250,
-    ellipsis: true,
-  },
-  {
-    title: '处理时间',
-    dataIndex: 'handleTime',
-    width: 170,
-  },
-];

+ 157 - 17
src/views/dashboard/HiddenSurface/configurable.data.ts

@@ -8,7 +8,7 @@ export const testConfigProvinceMonitor: Config[] = [
   // 1. 省域监测总览(统计指标卡片)
   {
     deviceType: 'province_overview',
-    moduleName: '省域监测总览',
+    moduleName: '全省监测总体情况',
     pageType: 'hidden_surface',
     moduleData: {
       header: {
@@ -44,7 +44,7 @@ export const testConfigProvinceMonitor: Config[] = [
               to: '/basicinfo/mines-info',
             },
             {
-              label: '测风点在线数',
+              label: '在线测风点',
               value: '1245',
               to: '/basicinfo/mines-info',
             },
@@ -56,12 +56,12 @@ export const testConfigProvinceMonitor: Config[] = [
             {
               label: '风量异常矿井',
               value: '23',
-              to: '/warningAnalysis/windSpeedOverlimit',
+              to: '/warningAnalysis/globalAlarm',
             },
             {
               label: '疑似隐蔽工作面',
               value: '8',
-              to: '/warningAnalysis/windSpeedOverlimit',
+              to: '/warningAnalysis/globalAlarm',
             },
           ],
         },
@@ -70,7 +70,7 @@ export const testConfigProvinceMonitor: Config[] = [
     showStyle: {
       size: 'width:400px;height:200px;',
       version: '原版',
-      position: 'top:30px;right:25px;',
+      position: 'top:100px;left:25px;',
     },
   },
   // 2. 执法处判识情况列表
@@ -98,9 +98,8 @@ export const testConfigProvinceMonitor: Config[] = [
           columns: [
             { name: '执法处', prop: 'officeName' },
             { name: '矿井数', prop: 'mineCount' },
-            { name: '在线率', prop: 'onlineRate' },
             { name: '风量异常', prop: 'abnormalCount' },
-            { name: '疑似工作面', prop: 'suspectedCount' },
+            { name: '疑似', prop: 'suspectedCount' },
           ],
         },
       ],
@@ -109,9 +108,113 @@ export const testConfigProvinceMonitor: Config[] = [
       preset: [],
     },
     showStyle: {
-      size: 'width:400px;height:600px;',
+      size: 'width:400px;height:370px;',
+      version: '原版',
+      position: 'top:30px;right:25px;',
+    },
+  },
+  // 3. 风速风量传感器(左下角,表格展示传感器返回数据)
+  {
+    deviceType: 'wind_speed_sensor',
+    moduleName: '风速风量传感器',
+    pageType: 'hidden_surface',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: { show: false, value: '' },
+        slot: { show: false, value: '' },
+      },
+      background: { show: false, type: 'video', link: '' },
+      layout: { direction: 'column', items: [{ name: 'table', basis: '100%', overflow: true }] },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      list: [],
+      complex_list: [],
+      preset: [],
+      table: [
+        {
+          type: 'D',
+          readFrom: 'windSensors',
+          columns: [
+            { name: '矿井名称', prop: 'mineName' },
+            { name: '测点名称', prop: 'pointName' },
+            { name: '风速(m/s)', prop: 'windSpeed' },
+            { name: '风量(m³/min)', prop: 'windVolume' },
+            // { name: '状态', prop: 'status' },
+          ],
+        },
+      ],
+      // 暂无接口对接,使用模拟数据先行展示
+      mock: {
+        windSensors: [
+          { mineName: '大同一矿', pointName: '主井进风', windSpeed: 5.2, windVolume: 2850, status: '正常' },
+          { mineName: '阳泉二矿', pointName: '副井进风', windSpeed: 4.8, windVolume: 2630, status: '正常' },
+          { mineName: '朔州三矿', pointName: '北翼回风', windSpeed: 6.8, windVolume: 3720, status: '异常' },
+          { mineName: '临汾一矿', pointName: '南翼回风', windSpeed: 4.1, windVolume: 2250, status: '正常' },
+          { mineName: '晋中二矿', pointName: '1201工作面', windSpeed: 3.5, windVolume: 1920, status: '正常' },
+          { mineName: '长治一矿', pointName: '1202工作面', windSpeed: 0, windVolume: 0, status: '缺失' },
+        ],
+      },
+    },
+    showStyle: {
+      size: 'width:400px;height:580px;',
+      version: '原版',
+      position: 'top:300px;left:25px;',
+    },
+  },
+  // 4. 隐蔽工作面(右下角,表格展示)
+  {
+    deviceType: 'hidden_workface',
+    moduleName: '隐蔽工作面',
+    pageType: 'hidden_surface',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: { show: false, value: '' },
+        slot: { show: false, value: '' },
+      },
+      background: { show: false, type: 'video', link: '' },
+      layout: { direction: 'column', items: [{ name: 'table', basis: '100%', overflow: true }] },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      list: [],
+      complex_list: [],
+      preset: [],
+      table: [
+        {
+          type: 'D',
+          readFrom: 'hiddenWorkfaces',
+          columns: [
+            { name: '矿井名称', prop: 'mineName' },
+            { name: '工作面名称', prop: 'goafName' },
+            // { name: '风险等级', prop: 'riskLevel' },
+            { name: '判识类型', prop: 'identifyType' },
+            { name: '发现时间', prop: 'detectTime' },
+          ],
+        },
+      ],
+      // 暂无接口对接,使用模拟数据先行展示
+      mock: {
+        hiddenWorkfaces: [
+          { mineName: '朔州三矿', goafName: '北翼采空区', riskLevel: '高风险', identifyType: '风量不闭合', detectTime: '2025-07-28 11:45' },
+          { mineName: '晋中二矿', goafName: '1201采空区', riskLevel: '较高风险', identifyType: '风量较均值偏低', detectTime: '2025-07-28 09:30' },
+          { mineName: '大同一矿', goafName: '主井东侧采空区', riskLevel: '一般风险', identifyType: '进回风不闭合', detectTime: '2025-07-27 16:20' },
+          { mineName: '长治一矿', goafName: '1202采空区', riskLevel: '较高风险', identifyType: '测风点缺失', detectTime: '2025-07-27 08:00' },
+          { mineName: '临汾一矿', goafName: '南翼采空区', riskLevel: '一般风险', identifyType: '多测点关联异常', detectTime: '2025-07-26 14:10' },
+          { mineName: '阳泉二矿', goafName: '副井西侧采空区', riskLevel: '低风险', identifyType: '风量较均值偏低', detectTime: '2025-07-26 10:05' },
+        ],
+      },
+    },
+    showStyle: {
+      size: 'width:400px;height:500px;',
       version: '原版',
-      position: 'top:250px;right:25px;',
+      position: 'top:400px;right:25px;',
     },
   },
 ];
@@ -174,9 +277,9 @@ export const testConfigVentilationMonitor: Config[] = [
       ],
     },
     showStyle: {
-      size: 'width:400px;height:180px;',
+      size: 'width:400px;height:200px;',
       version: '原版',
-      position: 'top:30px;right:25px;',
+      position: 'top:150px;left:25px;',
     },
   },
   {
@@ -212,18 +315,55 @@ export const testConfigVentilationMonitor: Config[] = [
             { label: '缺失规定测风点数', prop: 'missingCount', unit: '个' },
             { label: '多测点关联异常数', prop: 'relatedAbnormal', unit: '个' },
           ],
-          suggestions: [
-            '请现场核查疑似隐蔽巷道的通风设施状态',
-            '建议对该区域风量不闭合点进行复测',
-            '缺失测风点应尽快补装并接入系统',
+          suggestions: ['请现场核查疑似隐蔽巷道的通风设施状态', '建议对该区域风量不闭合点进行复测', '缺失测风点应尽快补装并接入系统'],
+        },
+      ],
+    },
+    showStyle: {
+      size: 'width:400px;height:480px;',
+      version: '原版',
+      position: 'top:30px;right:25px;',
+    },
+  },
+  // 3. 风速风量传感器(左下角,表格展示测风点实时数据)
+  {
+    deviceType: 'wind_speed_sensor',
+    moduleName: '风速风量传感器',
+    pageType: 'hidden_surface',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: { show: false, value: '' },
+        slot: { show: false, value: '' },
+      },
+      background: { show: false, type: 'video', link: '' },
+      layout: { direction: 'column', items: [{ name: 'table', basis: '100%', overflow: true }] },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      list: [],
+      complex_list: [],
+      preset: [],
+      table: [
+        {
+          type: 'D',
+          readFrom: 'pointRecords',
+          columns: [
+            { name: '测点编号', prop: 'pointCode' },
+            { name: '测点名称', prop: 'pointName' },
+            { name: '风速(m/s)', prop: 'windSpeed' },
+            { name: '风量(m³/min)', prop: 'windVolume' },
+            // { name: '状态', prop: 'status' },
           ],
         },
       ],
     },
     showStyle: {
-      size: 'width:400px;height:400px;',
+      size: 'width:400px;height:300px;',
       version: '原版',
-      position: 'top:220px;right:25px;',
+      position: 'top:350px;left:25px;',
     },
   },
 ];

+ 1 - 1
src/views/dashboard/HiddenSurface/index.vue

@@ -247,7 +247,7 @@
     width: 100%;
     height: 100%;
     color: @white;
-    background-image: linear-gradient(90deg, transparent 0%, transparent 70%, @map-bg 80%, @map-bg 100%);
+    background-image: linear-gradient(90deg, @map-bg 0%, @map-bg 20%, transparent 30%, transparent 70%, @map-bg 80%, @map-bg 100%);
     background-repeat: no-repeat;
     background-size: 100% 100%;
     z-index: @layout-basic-z-index;

+ 0 - 21
src/views/monitor/enforceMonitor/enforceMonitor.api.ts

@@ -1,21 +0,0 @@
-import { defHttp } from '/@/utils/http/axios';
-
-enum Api {
-  getBoardNum = '/enforce/monitor/getBoardNum',
-  getRealtimeList = '/enforce/monitor/getRealtimeList',
-  getHistoryList = '/enforce/monitor/getHistoryList',
-  exportRealtime = '/enforce/monitor/exportRealtime',
-  exportHistory = '/enforce/monitor/exportHistory',
-}
-
-/** 获取顶部统计卡片数据 */
-export const getBoardNum = (params?: any) =>
-  defHttp.post({ url: Api.getBoardNum, params }, { joinParamsToUrl: true });
-
-/** 查询实时监测列表 */
-export const getRealtimeList = (params?: any) =>
-  defHttp.post({ url: Api.getRealtimeList, params }, { joinParamsToUrl: true });
-
-/** 查询历史监测列表 */
-export const getHistoryList = (params?: any) =>
-  defHttp.post({ url: Api.getHistoryList, params }, { joinParamsToUrl: true });

+ 0 - 172
src/views/monitor/enforceMonitor/enforceMonitor.data.ts

@@ -1,172 +0,0 @@
-import type { BasicColumn, FormSchema } from '/@/components/Table';
-
-/** 顶部统计卡片 */
-export const boardData = [
-  { label: '辖区矿井数', value: '-' },
-  { label: '测风点在线率', value: '-' },
-  { label: '风量异常矿井', value: '-' },
-  { label: '疑似隐蔽工作面', value: '-' },
-];
-
-/** 生产状态映射 */
-export const productionStatusMap: Record<string, { label: string; color: string }> = {
-  normal: { label: '正常生产', color: '#52c41a' },
- 停产: { label: '停产', color: '#faad14' },
- 建设: { label: '建设', color: '#1890ff' },
-};
-
-/** 风量闭合映射 */
-export const windClosedMap: Record<string, { label: string; color: string }> = {
-  closed: { label: '闭合', color: '#52c41a' },
-  deviation: { label: '偏差', color: '#fa8c16' },
-  unclosed: { label: '不闭合', color: '#f5222d' },
-};
-
-/** 判识结果映射 */
-export const judgeResultMap: Record<string, { label: string; color: string }> = {
-  suspected: { label: '疑似', color: '#f5222d' },
-  normal: { label: '正常', color: '#52c41a' },
-  attention: { label: '关注', color: '#fa8c16' },
-  insufficient: { label: '数据不足', color: '#999' },
-};
-
-/** 实时监测数据表格列 —— 对应文档表3-1 */
-export const columns: BasicColumn[] = [
-  {
-    title: '煤矿编号',
-    dataIndex: 'mineCode',
-    fixed: 'left',
-    width: 130,
-  },
-  {
-    title: '煤矿名称/简称',
-    dataIndex: 'mineName',
-    fixed: 'left',
-    width: 180,
-  },
-  {
-    title: '所属区域',
-    dataIndex: 'areaName',
-    width: 120,
-  },
-  {
-    title: '生产状态',
-    dataIndex: 'productionStatus',
-    width: 100,
-    customRender: ({ text }) => {
-      const info = productionStatusMap[text];
-      if (!info) return text;
-      return `<span style="color:${info.color};font-weight:bold;">${info.label}</span>`;
-    },
-  },
-  {
-    title: '测风点数',
-    dataIndex: 'pointCount',
-    width: 90,
-    align: 'center',
-  },
-  {
-    title: '在线/应接',
-    dataIndex: 'onlineRatio',
-    width: 100,
-    align: 'center',
-    customRender: ({ text }) => text ?? '-',
-  },
-  {
-    title: '风量异常',
-    dataIndex: 'windAbnormal',
-    width: 90,
-    align: 'center',
-    customRender: ({ text }) => {
-      if (!text || text === '0') return text ?? '0';
-      return `<span style="color:#f5222d;font-weight:bold;">${text}</span>`;
-    },
-  },
-  {
-    title: '测风点缺失',
-    dataIndex: 'pointMissing',
-    width: 100,
-    align: 'center',
-    customRender: ({ text }) => {
-      if (!text || text === '0') return text ?? '0';
-      return `<span style="color:#f5222d;font-weight:bold;">${text}</span>`;
-    },
-  },
-  {
-    title: '风量闭合',
-    dataIndex: 'windClosed',
-    width: 100,
-    align: 'center',
-    customRender: ({ text }) => {
-      const info = windClosedMap[text];
-      if (!info) return text;
-      return `<span style="color:${info.color};font-weight:bold;">${info.label}</span>`;
-    },
-  },
-  {
-    title: '判识结果',
-    dataIndex: 'judgeResult',
-    width: 100,
-    align: 'center',
-    customRender: ({ text }) => {
-      const info = judgeResultMap[text];
-      if (!info) return text;
-      return `<span style="color:${info.color};font-weight:bold;">${info.label}</span>`;
-    },
-  },
-  {
-    title: '操作',
-    dataIndex: 'action',
-    width: 130,
-    fixed: 'right',
-  },
-];
-
-/** 查询表单 */
-export const schemas: FormSchema[] = [
-  {
-    label: '煤矿名称',
-    field: 'mineName',
-    component: 'Input',
-    colProps: { span: 6 },
-    rules: [],
-  },
-  {
-    label: '所属区域',
-    field: 'areaName',
-    component: 'Input',
-    colProps: { span: 6 },
-    rules: [],
-  },
-  {
-    label: '生产状态',
-    field: 'productionStatus',
-    component: 'Select',
-    colProps: { span: 6 },
-    componentProps: {
-      options: [
-        { label: '全部', value: '' },
-        { label: '正常生产', value: 'normal' },
-        { label: '停产', value: '停产' },
-        { label: '建设', value: '建设' },
-      ],
-    },
-    rules: [],
-  },
-  {
-    label: '判识结果',
-    field: 'judgeResult',
-    component: 'Select',
-    colProps: { span: 6 },
-    componentProps: {
-      options: [
-        { label: '全部', value: '' },
-        { label: '疑似', value: 'suspected' },
-        { label: '正常', value: 'normal' },
-        { label: '关注', value: 'attention' },
-        { label: '数据不足', value: 'insufficient' },
-      ],
-    },
-    rules: [],
-  },
-];

+ 0 - 0
src/views/monitor/enforceMonitor/hooks/form.ts → src/views/monitor/sensorMonitor/hooks/form.ts


+ 19 - 65
src/views/monitor/enforceMonitor/index.vue → src/views/monitor/sensorMonitor/index.vue

@@ -1,7 +1,7 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div class="enforce-monitor">
-    <!-- 顶部统计卡片 -->
+  <div class="sensor-monitor">
+    <!-- 顶部统计卡片(占位,接口就绪后接入) -->
     <div class="board-info">
       <MiniBoard
         v-for="(item, index) in boardData"
@@ -20,9 +20,6 @@
         <BasicTable @register="registerRealtimeTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #action="{ record }">
             <div class="action-buttons">
-              <button @click="handleViewDetail(record)" class="action-btn" title="详情">
-                <SvgIcon name="details" />
-              </button>
               <button @click="handleViewChart(record)" class="action-btn" title="图表">
                 <SvgIcon name="chart" />
               </button>
@@ -41,9 +38,6 @@
         <BasicTable @register="registerHistoryTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
           <template #action="{ record }">
             <div class="action-buttons">
-              <button @click="handleViewDetail(record)" class="action-btn" title="详情">
-                <SvgIcon name="details" />
-              </button>
               <button @click="handleViewChart(record)" class="action-btn" title="图表">
                 <SvgIcon name="chart" />
               </button>
@@ -66,43 +60,24 @@
   import { SvgIcon } from '/@/components/Icon';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { advancedRoutePush } from '/@/utils';
-  import { boardData, columns, schemas } from './enforceMonitor.data';
-  import { getBoardNum, getRealtimeList, getHistoryList } from './enforceMonitor.api';
+  import { useMineDepartmentStore } from '/@/store/modules/mine';
+  import { boardData, columns, historyColumns, schemas, historySchemas } from './sensorMonitor.data';
+  import { getWindrectData, getWindrectHistory } from './sensorMonitor.api';
   import { useInitForm } from './hooks/form';
 
   // 路由参数初始化(迁移自密闭监测)
   const { departId, rawcode, hiscode } = useInitForm();
+  const mineStore = useMineDepartmentStore();
 
   // 激活的Tab页签
   const activeTab = ref('realtime');
 
-  // 卡片数据
-  const boardDataRef = ref(boardData.map((item) => ({ ...item })));
-
-  // ====== 加载卡片数据 ======
-  async function loadBoardData(params?: any) {
-    try {
-      const result = await getBoardNum(params);
-      boardDataRef.value[0].value = result.mineTotal ?? '-';
-      boardDataRef.value[1].value = result.onlineRate ?? '-';
-      boardDataRef.value[2].value = result.windAbnormalMine ?? '-';
-      boardDataRef.value[3].value = result.suspectedGoaf ?? '-';
-    } catch {
-      // 使用默认值
-    }
-  }
-
-  // 包装实时列表请求:先加载卡片数据
-  const wrappedGetRealtime = (params) => {
-    return Promise.all([loadBoardData(params), getRealtimeList(params)]).then(([__, res]) => res);
-  };
-
-  // ====== 实时监测表格 ======
+  // ====== 实时监测表格(getWindrectData)======
   const { tableContext: ctxRealtime, onExportXls: onExportXlsTime } = useListPage({
     tableProps: {
       immediate: false,
       columns,
-      api: wrappedGetRealtime,
+      api: getWindrectData,
       formConfig: {
         autoSearch: true,
         labelWidth: 120,
@@ -130,7 +105,7 @@
       bordered: true,
       showIndexColumn: false,
       actionColumn: {
-        width: 110,
+        width: 90,
         title: '操作',
         dataIndex: 'action',
         slots: { customRender: 'action' },
@@ -138,38 +113,24 @@
       },
     },
     exportConfig: {
-      url: '/enforce/monitor/exportRealtime',
-      name: '执法处辖区监测实时数据',
+      url: '/workingface/windrect/exportRealtime',
+      name: '风速风量实时监测数据',
       params: {},
     },
   });
   const [registerRealtimeTable] = ctxRealtime;
 
-  // ====== 历史数据表格 ======
+  // ====== 历史数据表格(getWindrectHistory)======
   const { tableContext, onExportXls } = useListPage({
     tableProps: {
       immediate: false,
-      columns,
-      api: getHistoryList,
+      columns: historyColumns,
+      api: getWindrectHistory,
       formConfig: {
         autoSearch: true,
         labelWidth: 120,
         model: { deptId: hiscode },
-        schemas: [
-          {
-            field: 'deptId',
-            label: '煤矿名称',
-            component: 'MineCascader',
-            colProps: { span: 6 },
-            required: true,
-            componentProps: {
-              initFromStore: false,
-              syncToStore: false,
-              rootId: departId,
-            },
-          },
-          ...schemas,
-        ],
+        schemas: historySchemas,
         showAdvancedButton: false,
         schemaGroupNames: ['常规查询'],
       },
@@ -180,25 +141,18 @@
       showIndexColumn: true,
     },
     exportConfig: {
-      url: '/enforce/monitor/exportHistory',
-      name: '执法处辖区监测历史数据',
+      url: '/workingface/windrect/exportHistory',
+      name: '风速风量历史监测数据',
       params: {},
     },
   });
   const [registerHistoryTable] = tableContext;
 
   // ====== 跳转 ======
-  function handleViewDetail(record: any) {
-    advancedRoutePush({
-      path: '/enforce/${id}',
-      query: { deptId: record.deptId },
-    });
-  }
-
   function handleViewChart(record: any) {
     advancedRoutePush({
       path: '/warningAnalysis/connectAnalysis',
-      query: { deptId: record.deptId, filter: 'windSpeed,windVolume' },
+      query: { deptId: record.deptId || rawcode || mineStore.getDepartId, filter: 'windSpeed,windVolume' },
     });
   }
 </script>
@@ -206,7 +160,7 @@
 <style lang="less" scoped>
   @import url(../../analysis/common/board.less);
 
-  .enforce-monitor {
+  .sensor-monitor {
     height: 100%;
     overflow-y: auto;
   }

+ 19 - 0
src/views/monitor/sensorMonitor/sensorMonitor.api.ts

@@ -0,0 +1,19 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  getWindrectData = '/workingface/windrect/getWindrectData',
+  getWindrectHistory = '/workingface/windrect/getWindrectHistory',
+  getWindrectList = '/workingface/windrect/getWindrectList',
+}
+
+/** 查询采空区监测实时数据(WindrectController.getWindrectData,分页) */
+export const getWindrectData = (params?: any) =>
+  defHttp.post({ url: Api.getWindrectData, params }, { joinParamsToUrl: true });
+
+/** 查询历史跨天分页列表(WindrectController.getWindrectHistory) */
+export const getWindrectHistory = (params?: any) =>
+  defHttp.get({ url: Api.getWindrectHistory, params }, { joinParamsToUrl: true });
+
+/** 根据矿ID查询下面所有测风装置信息(WindrectController.getWindrectList,供历史查询选择测风装置) */
+export const getWindrectList = (params?: any) =>
+  defHttp.post({ url: Api.getWindrectList, params }, { joinParamsToUrl: true });

+ 177 - 0
src/views/monitor/sensorMonitor/sensorMonitor.data.ts

@@ -0,0 +1,177 @@
+import type { BasicColumn, FormSchema } from '/@/components/Table';
+import { h } from 'vue';
+import { StatusColorEnum } from '/@/enums/jeecgEnum';
+import dayjs from 'dayjs';
+import { getWindrectList } from './sensorMonitor.api';
+
+/** 顶部统计卡片(暂为占位,接口就绪后接入) */
+export const boardData = [
+  { label: '在线测风装置', value: '-' },
+  { label: '平均风速(m/s)', value: '-' },
+  { label: '风速超限报警', value: '-' },
+  { label: '风量异常报警', value: '-' },
+];
+
+/** 数据状态映射(WindrectData.status) */
+export const statusMap: Record<string, string> = {
+  '1': '正常',
+  '0': '异常',
+};
+
+/** 风速风量实时监测表格列(WindrectData) */
+export const columns: BasicColumn[] = [
+  {
+    title: '矿井名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '矿编码',
+    dataIndex: 'mineCode',
+    width: 110,
+  },
+  {
+    title: '设备编码',
+    dataIndex: 'deviceCode',
+    width: 140,
+  },
+  {
+    title: '设备位置',
+    dataIndex: 'devicePos',
+    width: 200,
+  },
+  {
+    title: '风速(m/s)',
+    dataIndex: 'va',
+    width: 110,
+  },
+  {
+    title: '风量(m³/min)',
+    dataIndex: 'm3',
+    width: 120,
+  },
+  {
+    title: '数据状态',
+    dataIndex: 'status',
+    width: 100,
+    customRender: ({ text }) => {
+      const label = statusMap[String(text)] ?? '-';
+      const color = String(text) === '1' ? StatusColorEnum.green : StatusColorEnum.red;
+      return h('span', { style: { color, fontWeight: 'bold' } }, label);
+    },
+  },
+  {
+    title: '数据读取时间',
+    dataIndex: 'readTime',
+    width: 170,
+  },
+];
+
+/** 风速风量历史数据表格列(WindrectHistory) */
+export const historyColumns: BasicColumn[] = [
+  {
+    title: '矿井名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '设备编码',
+    dataIndex: 'deviceCode',
+    width: 140,
+  },
+  {
+    title: '设备位置',
+    dataIndex: 'devicePos',
+    width: 200,
+  },
+  {
+    title: '风速(m/s)',
+    dataIndex: 'va',
+    width: 110,
+  },
+  {
+    title: '风量(m³/min)',
+    dataIndex: 'm3',
+    width: 120,
+  },
+  {
+    title: '创建时间',
+    dataIndex: 'createTime',
+    width: 170,
+  },
+];
+
+/** 实时监测查询表单(getWindrectData:deptId 必填) */
+export const schemas: FormSchema[] = [
+  {
+    label: '测风装置',
+    field: 'windrectId',
+    component: 'ApiSelect',
+    colProps: { span: 6 },
+    componentProps: {
+      api: getWindrectList,
+      labelField: 'devicePos',
+      valueField: 'id',
+      placeholder: '请选择测风装置',
+      params: {},
+    },
+  },
+  {
+    label: '煤矿状态',
+    field: 'gjMineStatus',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '瓦斯等级',
+    field: 'gasLevelName',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+];
+
+/** 历史数据查询表单(getWindrectHistory:startTime/endTime/windrectId 必填) */
+export const historySchemas: FormSchema[] = [
+  {
+    field: 'startTime',
+    label: '开始时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      format: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    },
+    defaultValue: dayjs().add(-30, 'day').format('YYYY-MM-DD 00:00:00'),
+    colProps: { span: 6 },
+  },
+  {
+    field: 'endTime',
+    label: '结束时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      format: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    },
+    defaultValue: dayjs().format('YYYY-MM-DD 23:59:59'),
+    colProps: { span: 6 },
+  },
+  {
+    label: '测风装置',
+    field: 'windrectId',
+    component: 'ApiSelect',
+    required: true,
+    colProps: { span: 6 },
+    componentProps: {
+      api: getWindrectList,
+      labelField: 'devicePos',
+      valueField: 'id',
+      placeholder: '请选择测风装置',
+      params: {},
+    },
+  },
+];

+ 29 - 0
src/views/monitor/surfaceMonitor/hooks/form.ts

@@ -0,0 +1,29 @@
+import { get, last } from 'lodash-es';
+import { useRoute } from 'vue-router';
+import { useMineDepartmentStore } from '/@/store/modules/mine';
+
+export function useInitForm() {
+  const mineStore = useMineDepartmentStore();
+  const route = useRoute();
+
+  // 如果generation为true,表示是模板路由直接使用,不会有/:id后缀
+  const departId = route.meta.generation ? undefined : (last(route.path.split('/')) as string);
+  // 获取到路由携带的id后进行过滤
+  const dep = mineStore.findDepartById(departId);
+  // 获取到query携带的矿id,如有就默认选中该矿
+  const rawcode = route.query.deptId as string;
+  // 默认填充的矿码
+  const hiscode = rawcode
+    ? rawcode
+    : get(
+        mineStore.findDepart((e) => e.isLeaf, dep || mineStore.getRoot),
+        'id'
+      );
+
+  return {
+    departId,
+    rawcode,
+    hiscode,
+    route,
+  };
+}

+ 143 - 0
src/views/monitor/surfaceMonitor/index.vue

@@ -0,0 +1,143 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="surface-monitor">
+    <!-- 顶部统计卡片(占位,接口就绪后接入) -->
+    <div class="board-info">
+      <MiniBoard
+        v-for="(item, index) in boardData"
+        :key="index"
+        type="A"
+        :label="item.label"
+        :value="item.value"
+        layout="label-top"
+        class="board-item"
+      />
+    </div>
+
+    <!-- Tab 切换 -->
+    <Tabs v-model:activeKey="activeTab" type="line" class="common-page-tabs">
+      <TabPane tab="实时监测" key="realtime">
+        <BasicTable @register="registerRealtimeTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
+          <template #resetBefore>
+            <a-button type="default" class="ml-8px" preIcon="mdi:download" @click="onExportXlsTime"> 导出 </a-button>
+          </template>
+          <template #empty>
+            <span class="empty-placeholder">-</span>
+          </template>
+        </BasicTable>
+      </TabPane>
+
+      <TabPane tab="历史数据" key="history">
+        <BasicTable @register="registerHistoryTable" :scroll="{ x: 'max-content' }" :style="{ padding: 0 }">
+          <template #resetBefore>
+            <a-button type="default" class="ml-8px" preIcon="mdi:download" @click="onExportXls"> 导出 </a-button>
+          </template>
+        </BasicTable>
+      </TabPane>
+    </Tabs>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import { BasicTable } from '/@/components/Table';
+  import { Tabs, TabPane } from 'ant-design-vue';
+  import MiniBoard from '/@/components/Configurable/detail/MiniBoard.vue';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import { boardData, columns, historyColumns, schemas, historySchemas } from './surfaceMonitor.data';
+  import { getMineData } from './surfaceMonitor.api';
+  import { useInitForm } from './hooks/form';
+
+  // 路由参数初始化(迁移自密闭监测)
+  const { departId, rawcode } = useInitForm();
+
+  // 激活的Tab页签
+  const activeTab = ref('realtime');
+
+  // ====== 实时监测表格(getMineData)======
+  const { tableContext: ctxRealtime, onExportXls: onExportXlsTime } = useListPage({
+    tableProps: {
+      immediate: false,
+      columns,
+      api: getMineData,
+      formConfig: {
+        autoSearch: true,
+        labelWidth: 120,
+        model: { deptId: rawcode },
+        schemas: [
+          {
+            field: 'deptId',
+            label: '煤矿名称',
+            component: 'MineCascader',
+            colProps: { span: 6 },
+            required: true,
+            componentProps: {
+              initFromStore: false,
+              rootId: departId,
+            },
+          },
+          ...schemas,
+        ],
+        showAdvancedButton: false,
+        schemaGroupNames: ['常规查询'],
+      },
+      pagination: true,
+      striped: true,
+      useSearchForm: true,
+      bordered: true,
+      showIndexColumn: false,
+      showActionColumn: false,
+    },
+    exportConfig: {
+      url: '/workingface/mineData/exportRealtime',
+      name: '隐蔽工作面判识实时数据',
+      params: {},
+    },
+  });
+  const [registerRealtimeTable] = ctxRealtime;
+
+  // ====== 历史数据表格(暂无接口,空态占位)======
+  const { tableContext, onExportXls } = useListPage({
+    tableProps: {
+      immediate: false,
+      columns: historyColumns,
+      // 历史数据接口暂未提供,返回空分页数据占位
+      api: async () => ({ records: [], total: 0 }),
+      formConfig: {
+        autoSearch: true,
+        labelWidth: 120,
+        schemas: historySchemas,
+        showAdvancedButton: false,
+        schemaGroupNames: ['常规查询'],
+      },
+      pagination: true,
+      striped: true,
+      useSearchForm: true,
+      bordered: true,
+      showIndexColumn: true,
+      showActionColumn: false,
+    },
+    exportConfig: {
+      url: '/workingface/mineData/exportHistory',
+      name: '隐蔽工作面判识历史数据',
+      params: {},
+    },
+  });
+  const [registerHistoryTable] = tableContext;
+</script>
+
+<style lang="less" scoped>
+  @import url(../../analysis/common/board.less);
+
+  .surface-monitor {
+    height: 100%;
+    overflow-y: auto;
+  }
+
+  .empty-placeholder {
+    display: block;
+    text-align: center;
+    color: #999;
+    padding: 16px 0;
+  }
+</style>

+ 9 - 0
src/views/monitor/surfaceMonitor/surfaceMonitor.api.ts

@@ -0,0 +1,9 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  getMineData = '/workingface/mineData/getMineData',
+}
+
+/** 煤矿列表查询(MineDataController.getMineData,分页,deptId 必填) */
+export const getMineData = (params?: any) =>
+  defHttp.post({ url: Api.getMineData, params }, { joinParamsToUrl: true });

+ 152 - 0
src/views/monitor/surfaceMonitor/surfaceMonitor.data.ts

@@ -0,0 +1,152 @@
+import type { BasicColumn, FormSchema } from '/@/components/Table';
+import { h } from 'vue';
+import { StatusColorEnum } from '/@/enums/jeecgEnum';
+
+/** 顶部统计卡片(暂为占位,接口就绪后接入) */
+export const boardData = [
+  { label: '接入矿井总数', value: '-' },
+  { label: '在线率', value: '-' },
+  { label: '风量异常矿井', value: '-' },
+  { label: '疑似隐蔽工作面', value: '-' },
+];
+
+/** 接入状态映射(Mine.accessStatus:1已接入、0未接入) */
+export const accessStatusMap: Record<string, string> = {
+  '1': '已接入',
+  '0': '未接入',
+};
+
+/** 隐蔽工作面判识全览实时表格列(getMineData → Mine) */
+export const columns: BasicColumn[] = [
+  {
+    title: '矿井名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '矿编码',
+    dataIndex: 'mineCode',
+    width: 110,
+  },
+  {
+    title: '矿井全称',
+    dataIndex: 'corpName',
+    width: 220,
+    ellipsis: true,
+  },
+  {
+    title: '瓦斯等级',
+    dataIndex: 'gasLevelName',
+    width: 120,
+  },
+  {
+    title: '接入状态',
+    dataIndex: 'accessStatus',
+    width: 110,
+    customRender: ({ text }) => {
+      const label = accessStatusMap[String(text)] ?? '-';
+      const color = String(text) === '1' ? StatusColorEnum.green : StatusColorEnum.red;
+      return h('span', { style: { color, fontWeight: 'bold' } }, label);
+    },
+  },
+  {
+    title: '煤矿状态',
+    dataIndex: 'mkMineStatus',
+    width: 110,
+  },
+  {
+    title: '测风地点数',
+    dataIndex: 'mineAreaList',
+    width: 110,
+    customRender: ({ text }) => (Array.isArray(text) ? text.length : '-'),
+  },
+  {
+    title: '测风装置数',
+    dataIndex: 'windrectList',
+    width: 110,
+    customRender: ({ text }) => (Array.isArray(text) ? text.length : '-'),
+  },
+  {
+    title: '上次实时数据上传时间',
+    dataIndex: 'lastCdssTime',
+    width: 180,
+  },
+  {
+    title: '上次定义数据上传时间',
+    dataIndex: 'lastCddyTime',
+    width: 180,
+  },
+];
+
+/** 历史数据表格列(暂无接口,先用同构占位列) */
+export const historyColumns: BasicColumn[] = [
+  {
+    title: '矿井名称',
+    dataIndex: 'mineName',
+    fixed: 'left',
+    width: 180,
+  },
+  {
+    title: '矿编码',
+    dataIndex: 'mineCode',
+    width: 110,
+  },
+  {
+    title: '接入状态',
+    dataIndex: 'accessStatus',
+    width: 110,
+    customRender: ({ text }) => accessStatusMap[String(text)] ?? '-',
+  },
+  {
+    title: '测风地点数',
+    dataIndex: 'mineAreaList',
+    width: 110,
+    customRender: ({ text }) => (Array.isArray(text) ? text.length : '-'),
+  },
+  {
+    title: '测风装置数',
+    dataIndex: 'windrectList',
+    width: 110,
+    customRender: ({ text }) => (Array.isArray(text) ? text.length : '-'),
+  },
+  {
+    title: '上次实时数据上传时间',
+    dataIndex: 'lastCdssTime',
+    width: 180,
+  },
+];
+
+/** 实时监测查询表单(getMineData:deptId 必填) */
+export const schemas: FormSchema[] = [
+  {
+    label: '矿井名称',
+    field: 'mineName',
+    component: 'Input',
+    colProps: { span: 6 },
+    componentProps: {
+      placeholder: '请输入矿井名称',
+    },
+  },
+  {
+    label: '接入状态',
+    field: 'accessStatus',
+    component: 'Select',
+    colProps: { span: 6 },
+    componentProps: {
+      options: [
+        { label: '已接入', value: 1 },
+        { label: '未接入', value: 0 },
+      ],
+    },
+  },
+  {
+    label: '瓦斯等级',
+    field: 'gasLevelName',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+];
+
+/** 历史数据查询表单(暂无接口,占位) */
+export const historySchemas: FormSchema[] = [];

+ 2 - 0
types/config.d.ts

@@ -60,6 +60,8 @@ export interface HeaderSetting {
   showNotice: boolean;
   // 是否显示搜索按钮
   showSearch: boolean;
+  // 是否显示头部时间
+  showHeaderTime: boolean;
 }
 
 export interface LocaleSetting {