Sfoglia il codice sorgente

Merge branch 'master' of http://39.97.59.228:8013/hrx/mky-vent-base

lxh 2 giorni fa
parent
commit
8ef320099b
22 ha cambiato i file con 935 aggiunte e 746 eliminazioni
  1. BIN
      src/assets/images/beltFire/listAll.png
  2. 30 8
      src/hooks/system/useMethods.ts
  3. 4 4
      src/layouts/page/index.vue
  4. 2 1
      src/utils/http/axios/index.ts
  5. 377 378
      src/views/vent/home/configurable/belt/belt-new.vue
  6. 127 122
      src/views/vent/home/configurable/belt/belt.vue
  7. 59 13
      src/views/vent/home/configurable/belt/components/detail/gateBoard.vue
  8. 1 1
      src/views/vent/home/configurable/belt/configurable.data.ts
  9. 22 13
      src/views/vent/home/configurable/components/belt/CameraList.vue
  10. 21 6
      src/views/vent/home/configurable/components/belt/ComplexList1Belt.vue
  11. 25 20
      src/views/vent/home/configurable/components/belt/CustomTableBelt.vue
  12. 69 21
      src/views/vent/home/configurable/components/belt/SprayControl.vue
  13. 15 4
      src/views/vent/home/configurable/components/belt/WarningResultList.vue
  14. 7 7
      src/views/vent/home/configurable/configurable.data.ts
  15. 1 1
      src/views/vent/home/configurable/configurable.data.wz.ts
  16. 47 20
      src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts
  17. 3 3
      src/views/vent/monitorManager/deviceMonitor/components/device/index.vue
  18. 103 103
      src/views/vent/monitorManager/gateMonitor/components/CarDamageTable.vue
  19. 9 9
      src/views/vent/monitorManager/gateMonitor/gate.threejs.ts
  20. 3 3
      src/views/vent/monitorManager/gateMonitor/gate.threejs.xr.ts
  21. 3 3
      src/views/vent/monitorManager/gateMonitor/gate.threejs.yy.ts
  22. 7 6
      src/views/vent/monitorManager/gateMonitor/index.vue

BIN
src/assets/images/beltFire/listAll.png


+ 30 - 8
src/hooks/system/useMethods.ts

@@ -27,7 +27,7 @@ export function useMethods() {
     // 显示loading,duration:0 表示不自动关闭
     // 显示loading,duration:0 表示不自动关闭
     message.loading({ content: '正在导出文件,请稍等...', key: loadingKey, duration: 0 });
     message.loading({ content: '正在导出文件,请稍等...', key: loadingKey, duration: 0 });
     try {
     try {
-      const data = await defHttp.get({ url: url, params: params, responseType: 'blob', timeout: 1000 * 1000 }, { isTransformResponse: false });
+      const data = await defHttp.get({ url: url, params: params, responseType: 'blob', timeout: 5 * 60 * 1000 }, { isTransformResponse: false });
       if (!data) {
       if (!data) {
         createMessage.warning('文件下载失败');
         createMessage.warning('文件下载失败');
         return;
         return;
@@ -57,8 +57,15 @@ export function useMethods() {
       // 导出成功提示
       // 导出成功提示
       message.success({ content: '文件导出成功!', key: loadingKey, duration: 2 });
       message.success({ content: '文件导出成功!', key: loadingKey, duration: 2 });
     } catch (error) {
     } catch (error) {
-      createMessage.error('文件导出失败!');
-      console.error('导出失败:', error);
+      if (error && error['code'] == 'ECONNABORTED') {
+        if (url.includes('/export/historydata') || url.includes('/ventanalyAlarmLog/exportXls')) {
+          createMessage.error('导出的数据量太大,请选择合理的时间范围和间隔时间分批导出!');
+        } else {
+          createMessage.error('导出的数据量太大,导出失败!');
+        }
+      } else {
+        createMessage.error('文件导出失败!');
+      }
     } finally {
     } finally {
       message.destroy(loadingKey);
       message.destroy(loadingKey);
     }
     }
@@ -73,7 +80,7 @@ export function useMethods() {
     const loadingKey = 'export-xls-post';
     const loadingKey = 'export-xls-post';
     message.loading({ content: '正在导出,请稍等...', key: loadingKey, duration: 0 });
     message.loading({ content: '正在导出,请稍等...', key: loadingKey, duration: 0 });
     defHttp
     defHttp
-      .post({ url: url, params: params, timeout: 1000 * 1000 }, { isTransformResponse: false })
+      .post({ url: url, params: params, timeout: 5 * 60 * 1000 }, { isTransformResponse: false })
       .then((data) => {
       .then((data) => {
         if (data.code == 200 && data.result) {
         if (data.code == 200 && data.result) {
           const messageArr = data.result.split('/');
           const messageArr = data.result.split('/');
@@ -102,8 +109,16 @@ export function useMethods() {
           message.error({ content: '下载失败!', key: loadingKey, duration: 2 });
           message.error({ content: '下载失败!', key: loadingKey, duration: 2 });
         }
         }
       })
       })
-      .catch(() => {
-        message.error({ content: '下载失败!', key: loadingKey, duration: 2 });
+      .catch((error) => {
+        if (error && error['code'] == 'ECONNABORTED') {
+          if (url.includes('/export/historydata') || url.includes('/ventanalyAlarmLog/exportXls')) {
+            createMessage.error('导出的数据量太大,请选择合理的时间范围和间隔时间分批导出!');
+          } else {
+            createMessage.error('导出的数据量太大,导出失败!');
+          }
+        } else {
+          message.error({ content: '下载失败!', key: loadingKey, duration: 2 });
+        }
       })
       })
       .finally(() => {
       .finally(() => {
         message.destroy(loadingKey);
         message.destroy(loadingKey);
@@ -144,8 +159,15 @@ export function useMethods() {
       }
       }
       message.success({ content: '文件导出成功!', key: loadingKey, duration: 2 });
       message.success({ content: '文件导出成功!', key: loadingKey, duration: 2 });
     } catch (error) {
     } catch (error) {
-      createMessage.error('文件导出失败!');
-      console.error('导出失败:', error);
+      if (error && error['code'] == 'ECONNABORTED') {
+        if (url.includes('/export/historydata') || url.includes('/ventanalyAlarmLog/exportXls')) {
+          createMessage.error('导出的数据量太大,请选择合理的时间范围和间隔时间分批导出!');
+        } else {
+          createMessage.error('导出的数据量太大,导出失败!');
+        }
+      } else {
+        message.error({ content: '下载失败!', key: loadingKey, duration: 2 });
+      }
     } finally {
     } finally {
       message.destroy(loadingKey);
       message.destroy(loadingKey);
     }
     }

+ 4 - 4
src/layouts/page/index.vue

@@ -17,13 +17,13 @@
         <!--      >-->
         <!--      >-->
         <keep-alive v-if="openCache" :include="getCaches">
         <keep-alive v-if="openCache" :include="getCaches">
           <Suspense>
           <Suspense>
-            <!-- <component :is="Component" :key="route.fullPath" /> -->
-            <component :is="Component" :key="route.path" />
+            <component :is="Component" :key="route.fullPath" />
+            <!-- <component :is="Component" :key="route.path" /> -->
           </Suspense>
           </Suspense>
         </keep-alive>
         </keep-alive>
         <Suspense v-else>
         <Suspense v-else>
-          <!-- <component :is="Component" :key="route.fullPath" /> -->
-          <component :is="Component" :key="route.path" />
+          <component :is="Component" :key="route.fullPath" />
+          <!-- <component :is="Component" :key="route.path" /> -->
         </Suspense>
         </Suspense>
 
 
         <!--      </transition>-->
         <!--      </transition>-->

+ 2 - 1
src/utils/http/axios/index.ts

@@ -320,7 +320,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
         // authentication schemes,e.g: Bearer
         // authentication schemes,e.g: Bearer
         // authenticationScheme: 'Bearer',
         // authenticationScheme: 'Bearer',
         authenticationScheme: '',
         authenticationScheme: '',
-        timeout: 10 * 1000,
+        // timeout: 5 * 60 * 1000,
+        timeout: 1000,
         // 基础接口地址
         // 基础接口地址
         // baseURL: globSetting.apiUrl,
         // baseURL: globSetting.apiUrl,
         headers: { 'Content-Type': ContentTypeEnum.JSON },
         headers: { 'Content-Type': ContentTypeEnum.JSON },

+ 377 - 378
src/views/vent/home/configurable/belt/belt-new.vue

@@ -48,316 +48,361 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-  import { onMounted, ref, watch, nextTick, computed, onUnmounted } from 'vue';
-  import customHeader from './components/customHeader-belt.vue';
-  import { useInitConfigs, useInitPage } from '../hooks/useInit';
-  import { testBeltNew, testYjkf, testSpary } from './configurable.data';
-  import ModuleCommon from './components/ModuleCommon.vue';
-  import ModuleCommonDual from './components/ModuleCommonDual.vue';
-  import Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
-  import BeltNav from './components/BeltNav.vue';
-  import { useRouter, useRoute } from 'vue-router';
-  import { getSystem, getMonitorAndAlertBelt, getWarnInfo, getDevice, getDataHome, getWarnResult, getStaffInfo } from './configurable.api';
-  import { modalAnimate, destroy } from './threejs/belt.threejs';
-  import History from './history.vue';
-  import sys from '/@/locales/lang/en/sys';
-  // 初始化配置
-  const { configs, fetchConfigs } = useInitConfigs();
-  const cfgs = computed(() => configs.value.filter((_, index) => index !== 2 && index !== 3));
-  const cfgA = computed<any>(() => configs.value[2]);
-  const cfgB = computed<any>(() => configs.value[3]);
-  const { updateEnhancedConfigs, updateData, data } = useInitPage('矿井全域皮带巷三级防灭火系统');
-  const isInitModal = ref(false);
-  const pageCache = ref({
-    fire_risk_warn: { configs: testBeltNew },
-    emergencyControl: { configs: testYjkf },
-    sprayControl: { configs: testSpary },
-  });
-  let timer = null,
-    modal = null;
-  const pageType = ref('fire_risk_warn');
-  const route = useRoute();
-  const modalMonitorData = ref({});
-  // 下拉框选项
-  /** 场景选项 */
-  const options = ref([]);
-  const optionValue = ref('');
-  async function getSysDataSource() {
-    const res = await getDataHome({ dataList: 'risk_evaluator' }).catch(() => {});
-    options.value = res.risk_evaluator || [];
-    await nextTick();
-    if (options.value.length > 0 && !optionValue.value) {
-      const firstId = options.value[0].sys_id;
-      changeSelectRow(firstId);
-    }
-  }
-  // 切换检测数据
-  function changeSelectRow(deviceID) {
-    optionValue.value = deviceID;
-    refresh();
+import { onMounted, ref, watch, nextTick, computed, onUnmounted } from 'vue';
+import customHeader from './components/customHeader-belt.vue';
+import { useInitConfigs, useInitPage } from '../hooks/useInit';
+import { testBeltNew, testYjkf, testSpary } from './configurable.data';
+import ModuleCommon from './components/ModuleCommon.vue';
+import ModuleCommonDual from './components/ModuleCommonDual.vue';
+import Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
+import BeltNav from './components/BeltNav.vue';
+import { useRouter, useRoute } from 'vue-router';
+import { getSystem, getMonitorAndAlertBelt, getWarnInfo, getDevice, getDataHome, getWarnResult, getStaffInfo } from './configurable.api';
+import { modalAnimate, destroy } from './threejs/belt.threejs';
+import History from './history.vue';
+import sys from '/@/locales/lang/en/sys';
+// 初始化配置
+const { configs, fetchConfigs } = useInitConfigs();
+const cfgs = computed(() => configs.value.filter((_, index) => index !== 2 && index !== 3));
+const cfgA = computed<any>(() => configs.value[2]);
+const cfgB = computed<any>(() => configs.value[3]);
+const { updateEnhancedConfigs, updateData, data } = useInitPage('矿井全域皮带巷三级防灭火系统');
+const isInitModal = ref(false);
+const pageCache = ref({
+  fire_risk_warn: { configs: testBeltNew },
+  emergencyControl: { configs: testYjkf },
+  sprayControl: { configs: testSpary },
+});
+let timer = null,
+  modal = null;
+const pageType = ref('fire_risk_warn');
+const route = useRoute();
+const modalMonitorData = ref({});
+// 下拉框选项
+/** 场景选项 */
+const options = ref([]);
+const optionValue = ref('');
+async function getSysDataSource() {
+  const res = await getDataHome({ dataList: 'risk_evaluator' }).catch(() => {});
+  options.value = res.risk_evaluator || [];
+  await nextTick();
+  if (options.value.length > 0 && !optionValue.value) {
+    const firstId = options.value[0].sys_id;
+    changeSelectRow(firstId);
   }
   }
-  // 预警等级映射
-  const warnTypeMap = {
-    '102': '黄色预警(较大风险)',
-    '103': '橙色预警(重大风险)',
-    '104': '红色预警(特别重大风险)',
-  };
-  // 处理接口返回数据
-  interface WarnResult {
-    warnName: string;
-    coRange?: string;
-    coTrend?: string;
-    tempRange?: string;
-    tempTrend?: string;
-    hclRange?: string;
-    warnCtrl?: string;
-  }
-  // 处理预警指标展示数据格式
-  function groupWarnByType(data: any) {
-    const result: WarnResult[] = [];
-    // 遍历 102、103、104...
-    Object.keys(data).forEach((warnKey) => {
-      const list = data[warnKey] || [];
-      const warnName = warnTypeMap[warnKey as keyof typeof warnTypeMap];
-      function getWarnCtrlByWarnName(warnName) {
-        if (warnName === '黄色预警(较大风险)') return '预警';
-        if (warnName === '橙色预警(重大风险)') return '报警启动喷淋';
-        if (warnName === '红色预警(特别重大风险)') return '启动喷淋与排烟';
-        return '';
-      }
-      // 构建当前预警对象
-      const warnObj: WarnResult = { warnName };
-      warnObj.warnCtrl = getWarnCtrlByWarnName(warnName);
-      list.forEach((item: any) => {
-        const { deviceType, fmin, fmax, trendMin, trendMax, trendCxTimeUnit } = item;
-        // CO
-        if (deviceType === 'modelsensor_co') {
-          if (fmin != null && fmax != null) {
-            warnObj.coRange = `${fmin} - ${fmax}`;
-          } else if (fmin != null && fmax == null) {
-            warnObj.coRange = `> ${fmin}`;
-          }
-          // 处理变化率
-          else if (trendMin != null && trendMax != null) {
-            if (warnName === '黄色预警(较大风险)') {
-              warnObj.coTrend = `加速上升(${trendMin} - ${trendMax})`;
-            } else if (warnName === '橙色预警(重大风险)') {
-              warnObj.coTrend = `急剧上升(${trendMin} - ${trendMax})`;
-            } else if (warnName === '红色预警(特别重大风险)') {
-              warnObj.coTrend = `极端上升(${trendMin} - ${trendMax})`;
-            }
-          } else if (trendMin != null && trendMax == null) {
-            warnObj.coTrend = `极端上升>${trendMin}`;
-          }
+}
+// 切换检测数据
+function changeSelectRow(deviceID) {
+  optionValue.value = deviceID;
+  refresh();
+}
+// 预警等级映射
+const warnTypeMap = {
+  '102': '黄色预警(较大风险)',
+  '103': '橙色预警(重大风险)',
+  '104': '红色预警(特别重大风险)',
+};
+// 处理接口返回数据
+interface WarnResult {
+  warnName: string;
+  coRange?: string;
+  coTrend?: string;
+  tempRange?: string;
+  tempTrend?: string;
+  hclRange?: string;
+  warnCtrl?: string;
+}
+// 处理预警指标展示数据格式
+function groupWarnByType(data: any) {
+  const result: WarnResult[] = [];
+  // 遍历 102、103、104...
+  Object.keys(data).forEach((warnKey) => {
+    const list = data[warnKey] || [];
+    const warnName = warnTypeMap[warnKey as keyof typeof warnTypeMap];
+    function getWarnCtrlByWarnName(warnName) {
+      if (warnName === '黄色预警(较大风险)') return '预警';
+      if (warnName === '橙色预警(重大风险)') return '报警启动喷淋';
+      if (warnName === '红色预警(特别重大风险)') return '启动喷淋与排烟';
+      return '';
+    }
+    // 构建当前预警对象
+    const warnObj: WarnResult = { warnName };
+    warnObj.warnCtrl = getWarnCtrlByWarnName(warnName);
+    list.forEach((item: any) => {
+      const { deviceType, fmin, fmax, trendMin, trendMax, trendCxTimeUnit } = item;
+      // CO
+      if (deviceType === 'modelsensor_co') {
+        if (fmin != null && fmax != null) {
+          warnObj.coRange = `${fmin} - ${fmax}`;
+        } else if (fmin != null && fmax == null) {
+          warnObj.coRange = `> ${fmin}`;
         }
         }
-        // 温度(带单位)
-        else if (deviceType === 'modelsensor_temperature') {
-          if (fmin != null && fmax != null) {
-            warnObj.tempRange = `${fmin} - ${fmax}℃`;
-          } else if (fmin != null && fmax == null) {
-            warnObj.tempRange = `≥ ${fmin}℃(持续高温)`;
-          } else if (trendMin != null) {
-            let unit = '';
-            if (trendCxTimeUnit === 0) unit = '分钟';
-            if (trendCxTimeUnit === 1) unit = '小时';
-            warnObj.tempTrend = `>+${trendMin}℃ /${unit}`;
+        // 处理变化率
+        else if (trendMin != null && trendMax != null) {
+          if (warnName === '黄色预警(较大风险)') {
+            warnObj.coTrend = `加速上升(${trendMin} - ${trendMax})`;
+          } else if (warnName === '橙色预警(重大风险)') {
+            warnObj.coTrend = `急剧上升(${trendMin} - ${trendMax})`;
+          } else if (warnName === '红色预警(特别重大风险)') {
+            warnObj.coTrend = `极端上升(${trendMin} - ${trendMax})`;
           }
           }
+        } else if (trendMin != null && trendMax == null) {
+          warnObj.coTrend = `极端上升>${trendMin}`;
         }
         }
-        // HCL
-        else if (deviceType === 'modelsensor_hcl') {
-          if (fmin != null && fmax != null) {
-            warnObj.hclRange = `${fmin} - ${fmax}`;
-          } else if (fmin != null && fmax == null) {
-            warnObj.hclRange = `≥ ${fmin}`;
-          }
+      }
+      // 温度(带单位)
+      else if (deviceType === 'modelsensor_temperature') {
+        if (fmin != null && fmax != null) {
+          warnObj.tempRange = `${fmin} - ${fmax}℃`;
+        } else if (fmin != null && fmax == null) {
+          warnObj.tempRange = `≥ ${fmin}℃(持续高温)`;
+        } else if (trendMin != null) {
+          let unit = '';
+          if (trendCxTimeUnit === 0) unit = '分钟';
+          if (trendCxTimeUnit === 1) unit = '小时';
+          warnObj.tempTrend = `>+${trendMin}℃ /${unit}`;
         }
         }
-      });
-      result.push(warnObj);
+      }
+      // HCL
+      else if (deviceType === 'modelsensor_hcl') {
+        if (fmin != null && fmax != null) {
+          warnObj.hclRange = `${fmin} - ${fmax}`;
+        } else if (fmin != null && fmax == null) {
+          warnObj.hclRange = `≥ ${fmin}`;
+        }
+      }
     });
     });
+    result.push(warnObj);
+  });
 
 
-    return result;
-  }
-  // 刷新数据
-  async function refresh() {
-    // 由于模型中需要用到风门的监测数据,这里进行公共调用(后期精确调用风门)
-    const modalRes = {};
-    const systemParams = {
-      devicetype: 'sys',
-      systemID: optionValue.value,
-    };
-    const resSys = await getSystem(systemParams);
+  return result;
+}
+// 刷新数据
+async function refresh() {
+  // 由于模型中需要用到风门的监测数据,这里进行公共调用(后期精确调用风门)
+  const modalRes = {};
+  const systemParams = {
+    devicetype: 'sys',
+    systemID: optionValue.value,
+  };
+  const resSys = await getSystem(systemParams);
+  const params = {
+    sysId: optionValue.value,
+    monitorType: 2,
+  };
+  const warnInfo = await getWarnInfo(params);
+  const staffInfo = await getStaffInfo({ sysId: optionValue.value });
+  Object.assign(modalRes, resSys);
+  if (pageType.value == 'fire_risk_warn') {
+    configs.value = [...testBeltNew];
     const params = {
     const params = {
       sysId: optionValue.value,
       sysId: optionValue.value,
-      monitorType: 2,
+      dataList: 'fire_risk_warn,warn_result,vehicle_co_correlate',
+      alarmLevel: '102,103,104',
     };
     };
-    const warnInfo = await getWarnInfo(params);
-    const staffInfo = await getStaffInfo({ sysId: optionValue.value });
-    Object.assign(modalRes, resSys);
-    if (pageType.value == 'fire_risk_warn') {
-      configs.value = [...testBeltNew];
-      const params = {
-        sysId: optionValue.value,
-        dataList: 'fire_risk_warn,warn_result,vehicle_co_correlate',
-        alarmLevel: '102,103,104',
-      };
-      const resWarn = await getMonitorAndAlertBelt(params);
-      resWarn.warnInfo = groupWarnByType(warnInfo);
-      console.log(resWarn.warnInfo, '111111111');
-      resWarn.staffInfo = staffInfo;
-      updateData(resWarn);
-      Object.assign(modalRes, resWarn);
-    } else if (pageType.value == 'emergencyControl') {
-      updateData(resSys);
-      configs.value = [...testYjkf];
-      const alarmParams = {
-        sysId: optionValue.value,
-        alarmLevel: '104',
-      };
-      const alarmRes = await getWarnResult(alarmParams);
-      if (alarmRes.warn_result) {
-        data.value.warn_result = alarmRes.warn_result;
-      }
-      data.value.warnInfo = groupWarnByType(warnInfo);
-      data.value.staffInfo = staffInfo;
-      updateData(data.value);
-    } else if (pageType.value == 'sprayControl') {
-      updateData(resSys);
-      const params1 = {
-        sysId: optionValue.value,
-        alarmLevel: '103,104',
-      };
-      const sprayData = [];
-      const dustData = [];
-      if (data.value?.deviceInfo) {
-        // 遍历对象的所有 value
-        Object.values(data.value.deviceInfo).forEach((item) => {
-          const hasSprayAuto = item.type && item.type.toLowerCase().includes('spray');
-          if (hasSprayAuto) {
-            sprayData.push({ ...item, ...item.readData });
-          }
-        });
-        Object.values(data.value.deviceInfo).forEach((item) => {
-          const hasDustAuto = item.type && item.type.toLowerCase().includes('dustdev');
-          if (hasDustAuto) {
-            dustData.push({ ...item, ...item.readData });
-          }
-        });
-      }
-      data.value.sprayData = sprayData;
-      data.value.dustData = dustData;
-      data.value.warnInfo = groupWarnByType(warnInfo);
-      data.value.staffInfo = staffInfo;
-      const alarmRes = await getWarnResult(params1);
-      if (alarmRes.warn_result) {
-        data.value.warn_result = alarmRes.warn_result;
-      }
-      configs.value = [...testSpary];
-    } else {
-      configs.value = testBeltNew;
+    const resWarn = await getMonitorAndAlertBelt(params);
+    resWarn.warnInfo = groupWarnByType(warnInfo);
+    resWarn.staffInfo = staffInfo;
+    updateData(resWarn);
+    Object.assign(modalRes, resWarn);
+  } else if (pageType.value == 'emergencyControl') {
+    updateData(resSys);
+    configs.value = [...testYjkf];
+    const alarmParams = {
+      sysId: optionValue.value,
+      alarmLevel: '104',
+    };
+    const alarmRes = await getWarnResult(alarmParams);
+    if (alarmRes.warn_result) {
+      data.value.warn_result = alarmRes.warn_result;
+    }
+    data.value.warnInfo = groupWarnByType(warnInfo);
+    data.value.staffInfo = staffInfo;
+    updateData(data.value);
+  } else if (pageType.value == 'sprayControl') {
+    updateData(resSys);
+    const params1 = {
+      sysId: optionValue.value,
+      alarmLevel: '103,104',
+    };
+    const sprayData = [];
+    const dustData = [];
+    if (data.value?.deviceInfo) {
+      // 遍历对象的所有 value
+      Object.values(data.value.deviceInfo).forEach((item) => {
+        const hasSprayAuto = item.type && item.type.toLowerCase().includes('spray');
+        if (hasSprayAuto) {
+          sprayData.push({ ...item, ...item.readData });
+        }
+      });
+      Object.values(data.value.deviceInfo).forEach((item) => {
+        const hasDustAuto = item.type && item.type.toLowerCase().includes('dustdev');
+        if (hasDustAuto) {
+          dustData.push({ ...item, ...item.readData });
+        }
+      });
+    }
+    data.value.sprayData = sprayData;
+    data.value.dustData = dustData;
+    data.value.warnInfo = groupWarnByType(warnInfo);
+    data.value.staffInfo = staffInfo;
+    const alarmRes = await getWarnResult(params1);
+    if (alarmRes.warn_result) {
+      data.value.warn_result = alarmRes.warn_result;
     }
     }
-    modalMonitorData.value = modalRes;
+    configs.value = [...testSpary];
+  } else {
+    configs.value = testBeltNew;
   }
   }
+  modalMonitorData.value = modalRes;
+}
 
 
-  // // 定时刷新
-  function initInterval() {
-    if (timer) clearInterval(timer);
-    timer = setInterval(() => {
-      refresh();
-    }, 60000);
-  }
+// // 定时刷新
+function initInterval() {
+  if (timer) clearInterval(timer);
+  timer = setInterval(() => {
+    refresh();
+  }, 5000);
+}
 
 
-  async function changePage(pageTypeStr) {
-    const target = pageTypeStr || route.query.pageType || 'fire_risk_warn';
-    if (pageType.value === target) return;
-    pageType.value = target;
-    configs.value = pageCache.value[target]?.configs || testBeltNew;
-    await nextTick();
-    await refresh();
-  }
-  // watch(
-  //   // 监听动态路由参数 :type
-  //   () => route.params.type,
-  //   (newVal) => {
-  //     if (newVal) {
-  //       console.log('切换页面类型:', newVal);
-  //       refresh(); // 切换路由自动刷新
-  //     }
-  //   }
-  // );
+async function changePage(pageTypeStr) {
+  const target = pageTypeStr || route.query.pageType || 'fire_risk_warn';
+  if (pageType.value === target) return;
+  pageType.value = target;
+  configs.value = pageCache.value[target]?.configs || testBeltNew;
+  await nextTick();
+  await refresh();
+}
+// watch(
+//   // 监听动态路由参数 :type
+//   () => route.params.type,
+//   (newVal) => {
+//     if (newVal) {
+//       console.log('切换页面类型:', newVal);
+//       refresh(); // 切换路由自动刷新
+//     }
+//   }
+// );
 
 
-  function initModalAnimate(modal3D) {
-    modal = modal3D;
-    modal.isRender = true;
-    modalAnimate(modal, modalMonitorData);
+function initModalAnimate(modal3D) {
+  modal = modal3D;
+  modal.isRender = true;
+  modalAnimate(modal, modalMonitorData);
+}
+function clearTimer() {
+  if (timer) {
+    clearInterval(timer);
+    timer = null;
   }
   }
-  function clearTimer() {
-    if (timer) {
-      clearInterval(timer);
-      timer = null;
+}
+watch(
+  () => route.query.pageType,
+  (newQueryType) => {
+    if (newQueryType) {
+      changePage(newQueryType as string);
     }
     }
-  }
-  watch(
-    () => route.query.pageType,
-    (newQueryType) => {
-      if (newQueryType) {
-        changePage(newQueryType as string);
-      }
-    },
-    { immediate: true } // 初始化立刻执行
-  );
+  },
+  { immediate: true } // 初始化立刻执行
+);
 
 
-  watch(
-    () => modalMonitorData.value,
-    (newData, oldData) => {
-      if (newData && !Object.keys(oldData).length) {
-        isInitModal.value = true;
-      }
+watch(
+  () => modalMonitorData.value,
+  (newData, oldData) => {
+    if (newData && !Object.keys(oldData).length) {
+      isInitModal.value = true;
     }
     }
-  );
+  }
+);
 
 
-  onMounted(async () => {
-    await getSysDataSource();
-    await refresh();
-    initInterval();
-  });
-  onUnmounted(() => {
-    clearTimer();
-    destroy(modal);
-    modal?.destroy();
-  });
+onMounted(async () => {
+  await getSysDataSource();
+  await refresh();
+  initInterval();
+});
+onUnmounted(() => {
+  clearTimer();
+  destroy(modal);
+  modal?.destroy();
+});
 </script>
 </script>
 <style lang="less" scoped>
 <style lang="less" scoped>
-  .company-home {
-    background: url('/@/assets/images/beltFire/baseMap.png') no-repeat center;
+.company-home {
+  background: url('/@/assets/images/beltFire/baseMap.png') no-repeat center;
+  width: 100%;
+  height: 100%;
+  color: @white;
+  position: relative;
+  font-family: 'Microsoft YaHei', sans-serif;
+  .top-bg {
     width: 100%;
     width: 100%;
-    height: 100%;
-    color: @white;
+    height: 56px;
+    position: absolute;
+    margin-top: 10px;
+    z-index: 1;
+  }
+  .header-container {
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    z-index: 10;
+  }
+
+  .border {
+    width: 100%;
+    height: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
     position: relative;
     position: relative;
-    font-family: 'Microsoft YaHei', sans-serif;
-    .top-bg {
-      width: 100%;
-      height: 56px;
-      position: absolute;
-      margin-top: 10px;
-      z-index: 1;
-    }
-    .header-container {
-      position: absolute;
-      top: 20px;
-      left: 20px;
-      z-index: 10;
-    }
+    width: 100%;
+  }
+}
 
 
-    .border {
-      width: 100%;
-      height: 94%;
-      background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
-      background-size: 100% 100%;
-      position: relative;
-      width: 100%;
+.center-warning-container {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+  top: 50%;
+  width: 600px;
+  height: 200px;
+  background-color: rgba(0, 0, 0, 0.7);
+  border-radius: 10px;
+  padding: 15px;
+  box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
+  z-index: 5;
+  color: #fff;
+
+  .warning-header {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 10px;
+    color: #ff6b6b;
+  }
+
+  .warning-list {
+    width: 100%;
+    height: 100%;
+    overflow-y: auto;
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+  }
+
+  .warning-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 8px;
+    background-color: rgba(0, 0, 0, 0.5);
+    border-radius: 5px;
+    border-left: 4px solid #ff6b6b;
+
+    .warning-time {
+      font-size: 14px;
+      color: #ccc;
     }
     }
   }
   }
 
 
+  // 中间预警结果区
   .center-warning-container {
   .center-warning-container {
     position: absolute;
     position: absolute;
     left: 50%;
     left: 50%;
@@ -401,113 +446,67 @@
         font-size: 14px;
         font-size: 14px;
         color: #ccc;
         color: #ccc;
       }
       }
-    }
-
-    // 中间预警结果区
-    .center-warning-container {
-      position: absolute;
-      left: 50%;
-      transform: translateX(-50%);
-      top: 50%;
-      width: 600px;
-      height: 200px;
-      background-color: rgba(0, 0, 0, 0.7);
-      border-radius: 10px;
-      padding: 15px;
-      box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
-      z-index: 5;
-      color: #fff;
 
 
-      .warning-header {
-        font-size: 18px;
+      .warning-level {
+        font-size: 14px;
         font-weight: bold;
         font-weight: bold;
-        margin-bottom: 10px;
-        color: #ff6b6b;
-      }
-
-      .warning-list {
-        width: 100%;
-        height: 100%;
-        overflow-y: auto;
-        display: flex;
-        flex-direction: column;
-        gap: 8px;
-      }
-
-      .warning-item {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        padding: 8px;
-        background-color: rgba(0, 0, 0, 0.5);
-        border-radius: 5px;
-        border-left: 4px solid #ff6b6b;
-
-        .warning-time {
-          font-size: 14px;
-          color: #ccc;
+        padding: 4px 8px;
+        border-radius: 4px;
+        &.level-critical {
+          background-color: #ff6b6b;
+          color: white;
         }
         }
-
-        .warning-level {
-          font-size: 14px;
-          font-weight: bold;
-          padding: 4px 8px;
-          border-radius: 4px;
-          &.level-critical {
-            background-color: #ff6b6b;
-            color: white;
-          }
-          &.level-high {
-            background-color: #ffcc00;
-            color: black;
-          }
-          &.level-normal {
-            background-color: #66cc66;
-            color: white;
-          }
+        &.level-high {
+          background-color: #ffcc00;
+          color: black;
+        }
+        &.level-normal {
+          background-color: #66cc66;
+          color: white;
         }
         }
+      }
 
 
-        .warning-action {
-          .btn-start-spray {
-            background-color: #00e1ff;
-            color: #000;
-            border: none;
-            padding: 4px 10px;
-            border-radius: 4px;
-            cursor: pointer;
-            font-size: 12px;
-            transition: all 0.3s;
-            &:hover {
-              background-color: #00c3e6;
-            }
+      .warning-action {
+        .btn-start-spray {
+          background-color: #00e1ff;
+          color: #000;
+          border: none;
+          padding: 4px 10px;
+          border-radius: 4px;
+          cursor: pointer;
+          font-size: 12px;
+          transition: all 0.3s;
+          &:hover {
+            background-color: #00c3e6;
           }
           }
         }
         }
       }
       }
     }
     }
+  }
 
 
-    // 巷道示意图
-    .belt-diagram {
-      position: absolute;
-      left: 50%;
-      transform: translateX(-50%);
-      bottom: 50px;
-      width: 800px;
-      height: 100px;
-      display: flex;
-      justify-content: center;
-      align-items: center;
+  // 巷道示意图
+  .belt-diagram {
+    position: absolute;
+    left: 50%;
+    transform: translateX(-50%);
+    bottom: 50px;
+    width: 800px;
+    height: 100px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
 
 
-      img {
-        width: 100%;
-        height: 100%;
-        object-fit: contain;
-      }
+    img {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
     }
     }
   }
   }
-  .modal-box {
-    width: 100%;
-    height: 100%;
-    position: absolute;
-    z-index: 1;
-  }
+}
+.modal-box {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  z-index: 1;
+}
 </style>
 </style>

+ 127 - 122
src/views/vent/home/configurable/belt/belt.vue

@@ -6,8 +6,8 @@
       <SubApp />
       <SubApp />
       <div class="box-container">
       <div class="box-container">
         <ModuleCommon
         <ModuleCommon
-          v-for="cfg in configs"
-          :key="cfg.deviceType"
+          v-for="cfg in localConfigs"
+          :key="cfg.moduleName + cfg.deviceType"
           :show-style="cfg.showStyle"
           :show-style="cfg.showStyle"
           :module-data="cfg.moduleData"
           :module-data="cfg.moduleData"
           :module-name="cfg.moduleName"
           :module-name="cfg.moduleName"
@@ -23,140 +23,145 @@
   </div>
   </div>
 </template>
 </template>
 <script setup lang="ts">
 <script setup lang="ts">
-  import { onMounted, onUnmounted, ref, nextTick } from 'vue';
-  import customHeader from './components/customHeader-belt.vue';
-  import { useInitConfigs, useInitPage } from '../hooks/useInit';
-  import { testBeltLaneFire } from './configurable.data';
-  import ModuleCommon from './components/ModuleCommon.vue';
-  import SubApp from '/@/components/vent/micro/createSubApp.vue';
-  import { getDataHome } from './configurable.api';
+import { onMounted, onUnmounted, ref, nextTick, watch } from 'vue';
+import customHeader from './components/customHeader-belt.vue';
+import { useInitConfigs, useInitPage } from '../hooks/useInit';
+import { testBeltLaneFire } from './configurable.data';
+import ModuleCommon from './components/ModuleCommon.vue';
+import SubApp from '/@/components/vent/micro/createSubApp.vue';
+import { getDataHome } from './configurable.api';
 
 
-  const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
-  const { updateEnhancedConfigs, updateData, data } = useInitPage('矿井全域皮带巷三级防灭火系统');
+const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
+const { updateEnhancedConfigs, updateData, data } = useInitPage('矿井全域皮带巷三级防灭火系统');
 
 
-  const currentSelectedId = ref<string>('');
-
-  let timer = null;
-  const showHistory = ref(false);
-  // 接收子组件上报的点击事件,更新全局选中状态
-  const handleItemClick = async (item) => {
-    const clickId = item.id;
-    if (!clickId) return;
-    currentSelectedId.value = clickId;
-    await nextTick();
-    refreshData();
-  };
-
-  // 数据筛选
-  const filterDataById = (sourceData, clickId: string | number) => {
-    if (!sourceData || !clickId) return sourceData;
-    const id = String(clickId);
-    const monitor = sourceData.monitor_alert?.find((item) => String(item.sysId) === id);
-    const spray = sourceData.spray_control?.find((item) => String(item.sysId) === id);
-    const gate = sourceData.gate_control?.find((item) => String(item.sysId) === id);
-    return {
-      ...sourceData,
-      monitor_alert: monitor ? [monitor] : [],
-      spray_control: spray ? [spray] : [],
-      gate_control: gate ? [gate] : [],
-    };
+const currentSelectedId = ref<string>('');
+let timer = null;
+const localConfigs = ref<any[]>([]);
+watch(
+  configs,
+  (newVal) => {
+    if (!newVal || newVal.length === 0) {
+      localConfigs.value = testBeltLaneFire;
+    } else {
+      localConfigs.value = newVal;
+    }
+  },
+  { deep: true, immediate: true }
+);
+// 接收子组件上报的点击事件,更新全局选中状态
+const handleItemClick = async (item) => {
+  const clickId = item.id;
+  if (!clickId) return;
+  currentSelectedId.value = clickId;
+  await nextTick();
+  refreshData();
+};
+// 数据筛选
+const filterDataById = (sourceData, clickId: string | number) => {
+  if (!sourceData || !clickId) return sourceData;
+  const id = String(clickId);
+  const monitor = sourceData.monitor_alert?.find((item) => String(item.sysId) === id);
+  const spray = sourceData.spray_control?.find((item) => String(item.sysId) === id);
+  const gate = sourceData.gate_control?.find((item) => String(item.sysId) === id);
+  return {
+    ...sourceData,
+    monitor_alert: monitor ? [monitor] : [],
+    spray_control: spray ? [spray] : [],
+    gate_control: gate ? [gate] : [],
   };
   };
+};
 
 
-  function refresh() {
-    fetchConfigs('belt').then(() => {
-      if (!configs.value || configs.value.length === 0) {
-        configs.value = testBeltLaneFire;
-      }
-      refreshData();
-    });
-  }
-  function refreshData() {
-    const dataListStr = configs.value
-      .filter((e) => e.deviceType)
-      .map((e) => e.deviceType)
-      .join(',');
+function refresh() {
+  fetchConfigs('belt');
+  refreshData();
+}
 
 
-    getDataHome({ dataList: dataListStr }).then((res: any) => {
-      res.spray_control = [
-        {
-          systemName: '东翼胶带运输大巷',
-          sysId: '2028657172566073346',
-          sysList: [{ netstatus: '1', deviceStatus: '1', plsy: '1#区域 1.4MPa', kzms: '手动' }],
-        },
-        {
-          sysId: '2046500718274756609',
-          systemName: '1101胶带运输顺槽',
-          sysList: [{ netstatus: '1', deviceStatus: '1', plqy: '2#区域', plsy: '1.6MPa', kzms: '自动' }],
-        },
-      ];
+function refreshData() {
+  const dataListStr = localConfigs.value
+    .filter((e) => e.deviceType)
+    .map((e) => e.deviceType)
+    .join(',');
+  getDataHome({ dataList: dataListStr }).then((res: any) => {
+    res.spray_control = [
+      {
+        systemName: '东翼胶带运输大巷',
+        sysId: '2028657172566073346',
+        sysList: [{ netstatus: '1', deviceStatus: '1', plsy: '1#区域 1.4MPa', kzms: '手动' }],
+      },
+      {
+        sysId: '2046500718274756609',
+        systemName: '1101胶带运输顺槽',
+        sysList: [{ netstatus: '1', deviceStatus: '1', plqy: '2#区域', plsy: '1.6MPa', kzms: '自动' }],
+      },
+    ];
 
 
-      let showData = res;
-      if (currentSelectedId.value) {
-        showData = filterDataById(res, currentSelectedId.value);
-      } else {
-        const firstId = res.monitor_alert?.[0]?.sysId;
-        if (firstId) {
-          currentSelectedId.value = firstId;
-          showData = filterDataById(res, firstId);
-        }
+    let showData = res;
+    if (currentSelectedId.value) {
+      showData = filterDataById(res, currentSelectedId.value);
+    } else {
+      const firstId = res.monitor_alert?.[0]?.sysId;
+      if (firstId) {
+        currentSelectedId.value = firstId;
+        showData = filterDataById(res, firstId);
       }
       }
-      updateData(showData);
-    });
-  }
-  // 轮询
-  function initInterval() {
-    if (timer) clearInterval(timer);
-    timer = setInterval(() => {
-      refresh();
-    }, 5000);
-  }
-  onMounted(() => {
-    refresh();
-    initInterval();
+    }
+    updateData(showData);
   });
   });
+}
+function initInterval() {
+  if (timer) clearInterval(timer);
+  timer = setInterval(() => {
+    refresh();
+  }, 5000);
+}
 
 
-  onUnmounted(() => {
-    clearInterval(timer);
-    timer = null;
-  });
+onMounted(() => {
+  refresh();
+  initInterval();
+});
+
+onUnmounted(() => {
+  clearInterval(timer);
+  timer = null;
+});
 </script>
 </script>
 <style lang="less" scoped>
 <style lang="less" scoped>
-  .spray-wrapper {
-    width: 100%;
-    height: 100%;
-    background-image: url('/@/assets/images/beltFire/baseMap.png');
-    background-size: cover;
-  }
+.spray-wrapper {
+  width: 100%;
+  height: 100%;
+  background-image: url('/@/assets/images/beltFire/baseMap.png');
+  background-size: cover;
+}
 
 
-  #spray3D {
-    pointer-events: all;
-  }
+#spray3D {
+  pointer-events: all;
+}
 
 
-  .spray-wrapper :deep(.list-item_L .list-item__icon_L) {
-    background-image: url('/@/assets/images/home-container/configurable/minehome/list-icon-file.png');
-  }
-  .spray-wrapper :deep(.list-item_N:nth-child(1)) {
-    background-image: url('/@/assets/images/home-container/configurable/minehome/list-bg-n5.png');
-  }
-  .spray-wrapper :deep(.list-item_N:nth-child(2)) {
-    background-image: url('/@/assets/images/home-container/configurable/minehome/list-bg-n6.png');
-  }
-  .company-home {
-    background: url('/@/assets/images/beltFire/baseMap.png') no-repeat center;
+.spray-wrapper :deep(.list-item_L .list-item__icon_L) {
+  background-image: url('/@/assets/images/home-container/configurable/minehome/list-icon-file.png');
+}
+.spray-wrapper :deep(.list-item_N:nth-child(1)) {
+  background-image: url('/@/assets/images/home-container/configurable/minehome/list-bg-n5.png');
+}
+.spray-wrapper :deep(.list-item_N:nth-child(2)) {
+  background-image: url('/@/assets/images/home-container/configurable/minehome/list-bg-n6.png');
+}
+.company-home {
+  background: url('/@/assets/images/beltFire/baseMap.png') no-repeat center;
+  width: 100%;
+  height: 100%;
+  color: @white;
+  position: relative;
+  .border {
     width: 100%;
     width: 100%;
-    height: 100%;
-    color: @white;
-    position: relative;
-    .border {
-      width: 100%;
-      height: 94%;
-      background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    height: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
+    margin-top: 50px;
+    .test {
+      background: url('./test.png') no-repeat;
       background-size: 100% 100%;
       background-size: 100% 100%;
-      margin-top: 50px;
-      .test {
-        background: url('./test.png') no-repeat;
-        background-size: 100% 100%;
-      }
     }
     }
   }
   }
-</style>
+}
+</style>

+ 59 - 13
src/views/vent/home/configurable/belt/components/detail/gateBoard.vue

@@ -16,8 +16,8 @@
               <div class="door-name"
               <div class="door-name"
                 ><span>{{ item.strname }}</span></div
                 ><span>{{ item.strname }}</span></div
               >
               >
-              <a-button class="door-btn" @click="oneKeyClose(index)">一键双关</a-button>
-              <a-button class="door-btn" @click="oneKeyOpen(index)">一键双开</a-button>
+              <a-button class="door-btn" @click="playAnimation('一键双开', 'sameTimeOpen', item.deviceID, item.deviceType)">一键双开</a-button>
+              <a-button class="door-btn" @click="playAnimation('一键双关', 'sameTimeClose', item.deviceID, item.deviceType)">一键双关</a-button>
             </div>
             </div>
             <div class="door-header">
             <div class="door-header">
               <div class="info-column" v-for="(i, idx) in config.config.items" :key="idx">
               <div class="info-column" v-for="(i, idx) in config.config.items" :key="idx">
@@ -44,14 +44,23 @@
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
+  <HandleModal
+    v-if="!globalConfig?.simulatedPassword"
+    :modal-is-show="modalIsShow"
+    :modal-title="modalTitle"
+    :modal-type="modalType"
+    @handle-ok="handleOK"
+    @handle-cancel="handleCancel"
+  />
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref, onMounted, defineProps, watch } from 'vue';
+import { ref, onMounted, defineProps, watch, inject } from 'vue';
 import { getFormattedText } from '../../../hooks/helper';
 import { getFormattedText } from '../../../hooks/helper';
-// import gateSVG from '../gateSVG.vue';
+import HandleModal from '/@/views/vent/monitorManager/gateMonitor/modal.vue';
+import { message } from 'ant-design-vue';
+import { deviceControlApi } from '/@/api/vent/index';
 import gateSVG from '../../../../../monitorManager/gateMonitor/components/gateDualSVG.vue';
 import gateSVG from '../../../../../monitorManager/gateMonitor/components/gateDualSVG.vue';
-import { nextTick } from 'process';
 const props = defineProps<{
 const props = defineProps<{
   config: {
   config: {
     config: {
     config: {
@@ -67,6 +76,13 @@ const props = defineProps<{
     [key: string]: any;
     [key: string]: any;
   };
   };
 }>();
 }>();
+const modalIsShow = ref<boolean>(false); // 是否显示模态框
+const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
+const modalType = ref(''); // 模态框内容显示类型,设备操作类型
+const paramcode = ref(''); // 模态框操作代码
+const deviceID = ref('');
+const deviceType = ref('');
+const globalConfig = inject<any>('globalConfig');
 const childRefs = ref<(InstanceType<typeof gateSVG> | null)[]>([]);
 const childRefs = ref<(InstanceType<typeof gateSVG> | null)[]>([]);
 const setChildRef = (el, index) => {
 const setChildRef = (el, index) => {
   if (el) {
   if (el) {
@@ -83,17 +99,47 @@ function monitorAnimation(selectData, index) {
   }
   }
 }
 }
 
 
-function oneKeyOpen(index) {
-  if (childRefs.value[index]) {
-    childRefs.value[index].animate(true, true, true);
+const playAnimation = (title, flag, id, type) => {
+  modalType.value = flag + '';
+  modalTitle.value = title;
+  modalIsShow.value = true;
+  deviceID.value = id;
+  deviceType.value = type;
+  console.log(deviceID.value, '1111111111');
+};
+// 控制
+function handleOK(passWord, handlerState, value?) {
+  console.log('handleOK', passWord, handlerState, value);
+  if (!passWord && !globalConfig?.simulatedPassword) {
+    message.warning('请输入密码');
+    return;
   }
   }
+  let data = {
+    deviceid: deviceID.value,
+    devicetype: deviceType.value,
+    paramcode: handlerState,
+    password: passWord || globalConfig?.simulatedPassword,
+    value: value ? value : null,
+  };
+  deviceControlApi(data)
+    .then((res) => {
+      if (res.success) {
+        message.success('指令已下发成功!');
+      } else {
+        message.error(res.message);
+      }
+    })
+    .finally(() => {
+      handleCancel();
+    });
 }
 }
-function oneKeyClose(index) {
-  if (childRefs.value[index]) {
-    childRefs.value[index].animate(false, false, false);
-  }
+function handleCancel() {
+  modalIsShow.value = false;
+  modalTitle.value = '';
+  modalType.value = '';
+  deviceID.value = '';
+  deviceType.value = '';
 }
 }
-
 watch(
 watch(
   () => props.data,
   () => props.data,
   (newData) => {
   (newData) => {

+ 1 - 1
src/views/vent/home/configurable/belt/configurable.data.ts

@@ -1023,7 +1023,7 @@ export const testSpary: Config[] = [
       complex_list: [],
       complex_list: [],
       preset: [
       preset: [
         {
         {
-          readFrom: 'deviceInfo.gate.datalist',
+          readFrom: '',
           config: {
           config: {
             title: 'name',
             title: 'name',
             contents: [
             contents: [

+ 22 - 13
src/views/vent/home/configurable/components/belt/CameraList.vue

@@ -19,6 +19,7 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import { ref, watch, onBeforeUnmount, nextTick } from 'vue';
 import { ref, watch, onBeforeUnmount, nextTick } from 'vue';
 import { useCamera } from '/@/hooks/system/useCameraPianation';
 import { useCamera } from '/@/hooks/system/useCameraPianation';
+import { isEqual } from 'lodash-es'; // 必须用深比较
 
 
 const props = defineProps({
 const props = defineProps({
   data: { type: Array, default: () => [] },
   data: { type: Array, default: () => [] },
@@ -32,29 +33,37 @@ const defaultVideoList = ref([
   { id: 2, url: '/sparyVideo.mp4' },
   { id: 2, url: '/sparyVideo.mp4' },
   { id: 3, url: '/sparyVideo.mp4' },
   { id: 3, url: '/sparyVideo.mp4' },
 ]);
 ]);
+
+// 缓存上一次的摄像头列表,用于对比是否真的变化
+const lastCameraList = ref<any[]>([]);
+
 watch(
 watch(
   () => props.data,
   () => props.data,
   async (newData) => {
   async (newData) => {
-    removeCamera(playerRef);
-    if (playerRef.value) playerRef.value.innerHTML = '';
-    hasCamera.value = false;
-
-    await nextTick();
-
-    // 2. 提取摄像头(内部判断)
-    const list: any[] = [];
-    if (newData && newData.length > 0) {
+    const newCameraList: any[] = [];
+    if (newData?.length) {
       newData.forEach((device: any) => {
       newData.forEach((device: any) => {
-        if (device.cameras && device.cameras.length > 0) {
+        if (device.cameras?.length) {
           device.cameras.forEach((item) => {
           device.cameras.forEach((item) => {
-            list.push({ ...item, deviceID: device.deviceID });
+            newCameraList.push({ ...item, deviceID: device.deviceID });
           });
           });
         }
         }
       });
       });
     }
     }
-    if (list.length > 0) {
+    if (isEqual(newCameraList, lastCameraList.value)) {
+      return;
+    }
+    removeCamera(playerRef);
+    if (playerRef.value) playerRef.value.innerHTML = '';
+    hasCamera.value = false;
+    await nextTick();
+    // 更新缓存
+    lastCameraList.value = newCameraList;
+
+    //渲染新摄像头
+    if (newCameraList.length > 0) {
       hasCamera.value = true;
       hasCamera.value = true;
-      await getCamera('', playerRef, ref(true), '', list);
+      await getCamera('', playerRef, ref(true), '', newCameraList);
     } else {
     } else {
       hasCamera.value = false;
       hasCamera.value = false;
     }
     }

+ 21 - 6
src/views/vent/home/configurable/components/belt/ComplexList1Belt.vue

@@ -6,7 +6,8 @@
         <div
         <div
           style="cursor: pointer"
           style="cursor: pointer"
           @click="handleItemClick(allMineItem)"
           @click="handleItemClick(allMineItem)"
-          :class="[`list-item__content_${type}`, getBgClass(allMineItem.value), { active: allMineItem.id === activeId }]"
+          class="list-item-all"
+          :class="[`list-item__content_${type}`, getBgClass(allMineItem.value)]"
         >
         >
           <div class="list-item__label">全矿井</div>
           <div class="list-item__label">全矿井</div>
           <div class="list-item__value" :class="`list-item__value_${type}`">
           <div class="list-item__value" :class="`list-item__value_${type}`">
@@ -82,7 +83,7 @@ const firstContent = computed(() => {
   return firstItem.contents[0];
   return firstItem.contents[0];
 });
 });
 
 
-// 全矿井项(自动继承第一条数据的 value)
+// 全矿井项
 const allMineItem = computed(() => ({
 const allMineItem = computed(() => ({
   id: 'allMine',
   id: 'allMine',
   label: '全矿井',
   label: '全矿井',
@@ -91,10 +92,8 @@ const allMineItem = computed(() => ({
   info: firstContent.value?.info,
   info: firstContent.value?.info,
 }));
 }));
 
 
-// 是否显示全矿井(有数据才显示)
+// 是否显示全矿井
 const showAllMineItem = computed(() => !!firstContent.value);
 const showAllMineItem = computed(() => !!firstContent.value);
-// ==============================================
-
 // 获取背景样式
 // 获取背景样式
 const getBgClass = (riskLevel: string) => {
 const getBgClass = (riskLevel: string) => {
   // 统一处理 null  0
   // 统一处理 null  0
@@ -135,7 +134,8 @@ onMounted(() => {});
 @import '/@/design/theme.less';
 @import '/@/design/theme.less';
 
 
 .list {
 .list {
-  padding-left: 20px;
+  padding-left: 10px;
+  padding-right: 10px;
   background-repeat: no-repeat;
   background-repeat: no-repeat;
   position: relative;
   position: relative;
   display: flex;
   display: flex;
@@ -200,6 +200,21 @@ onMounted(() => {});
   z-index: 2;
   z-index: 2;
   pointer-events: none;
   pointer-events: none;
 }
 }
+.list-item-all {
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 35px;
+  padding: 10px 25px;
+  font-size: 14px;
+  font-weight: bold;
+  background: url('/@/assets/images/beltFire/listAll.png');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  z-index: 1;
+}
 .list-item__content_A.bg-lowRisk .list-item__value {
 .list-item__content_A.bg-lowRisk .list-item__value {
   color: #32ddff;
   color: #32ddff;
 }
 }

+ 25 - 20
src/views/vent/home/configurable/components/belt/CustomTableBelt.vue

@@ -1,16 +1,11 @@
 <template>
 <template>
   <div class="table__content">
   <div class="table__content">
     <div class="table__content_label" :class="`table__content_label_${type}`">
     <div class="table__content_label" :class="`table__content_label_${type}`">
-      <div class="label-t" v-for="(item, index) in columns" :key="`svvhbcth-${index}`" :style="{ flexBasis }">{{ item.name }}</div>
+      <div class="label-t" v-for="(item, index) in columns" :key="`svvhbcth-${item.prop}`" :style="{ flexBasis }">{{ item.name }}</div>
     </div>
     </div>
     <div ref="scrollRef" class="table__content_list" :class="`table__content_list_${type}`">
     <div ref="scrollRef" class="table__content_list" :class="`table__content_list_${type}`">
-      <!-- 🔥 修复:空数据时依然渲染一行 -->
-      <div class="table__content_list_row" v-if="data.length === 0">
-        <div class="empty-text" :style="{ flexBasis: '100%' }"> 暂无数据 </div>
-      </div>
-
-      <div class="table__content_list_row" v-else v-for="(item, index) in data" :key="`svvhbct-${index}`">
-        <div v-for="(t, i) in columns" :key="`svvhbctr-${i}`" :style="{ flexBasis }" :class="`table__content__list_item_${type}`">
+      <div class="table__content_list_row" v-for="(item, index) in showData" :key="`svvhbct-${item.id || item.code || item.name || index}`">
+        <div v-for="(t, i) in columns" :key="`svvhbctr-${t.prop}`" :style="{ flexBasis }" :class="`table__content__list_item_${type}`">
           <slot :name="t.prop" :scope="item">
           <slot :name="t.prop" :scope="item">
             <span>
             <span>
               <span
               <span
@@ -27,23 +22,22 @@
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { computed, onMounted, ref } from 'vue';
+import { computed, ref, watch } from 'vue';
 import _ from 'lodash';
 import _ from 'lodash';
 import { useAutoScroll } from '/@/hooks/core/useAutoScroll';
 import { useAutoScroll } from '/@/hooks/core/useAutoScroll';
-
 let props = withDefaults(
 let props = withDefaults(
   defineProps<{
   defineProps<{
     type: string;
     type: string;
     autoScroll: boolean;
     autoScroll: boolean;
     columns: { prop: string; name: string }[];
     columns: { prop: string; name: string }[];
-    data: any;
+    data: any[];
     defaultValue: string;
     defaultValue: string;
   }>(),
   }>(),
   {
   {
     type: 'B',
     type: 'B',
     autoScroll: false,
     autoScroll: false,
     columns: () => [],
     columns: () => [],
-    data: () => ({}),
+    data: () => [],
     defaultValue: '-',
     defaultValue: '-',
   }
   }
 );
 );
@@ -52,6 +46,21 @@ const scrollRef = ref(null);
 if (props.autoScroll) {
 if (props.autoScroll) {
   useAutoScroll(scrollRef);
   useAutoScroll(scrollRef);
 }
 }
+const showData = ref<any[]>([]);
+
+watch(
+  () => props.data,
+  (newData) => {
+    const list = newData || [];
+    // 空数据时显示一行“暂无数据”
+    if (list.length === 0) {
+      showData.value = [{ _empty: true }];
+    } else {
+      showData.value = list;
+    }
+  },
+  { deep: true, immediate: true }
+);
 
 
 const getStatusClass = (status) => {
 const getStatusClass = (status) => {
   switch (status) {
   switch (status) {
@@ -71,11 +80,15 @@ const flexBasis = computed(() => {
 });
 });
 
 
 function get(o, p) {
 function get(o, p) {
+  if (o._empty) return props.defaultValue;
   const d = _.get(o, p);
   const d = _.get(o, p);
   return _.isNil(d) ? props.defaultValue : d === '' ? props.defaultValue : d;
   return _.isNil(d) ? props.defaultValue : d === '' ? props.defaultValue : d;
 }
 }
 
 
 function formatValue(obj, path) {
 function formatValue(obj, path) {
+  if (obj._empty) {
+    return '暂无数据';
+  }
   const value = _.get(obj, path);
   const value = _.get(obj, path);
   if (_.isNil(value) || value === '') {
   if (_.isNil(value) || value === '') {
     return props.defaultValue;
     return props.defaultValue;
@@ -185,13 +198,5 @@ function formatValue(obj, path) {
     background-color: gray;
     background-color: gray;
     box-shadow: 0 0 6px 2px rgba(105, 105, 105, 0.6);
     box-shadow: 0 0 6px 2px rgba(105, 105, 105, 0.6);
   }
   }
-
-  /* 空状态样式(保持表格行高度,不塌陷) */
-  .empty-text {
-    text-align: center;
-    color: #999;
-    line-height: 50px;
-    font-size: 14px;
-  }
 }
 }
 </style>
 </style>

+ 69 - 21
src/views/vent/home/configurable/components/belt/SprayControl.vue

@@ -4,8 +4,8 @@
     <div class="sensor-list">
     <div class="sensor-list">
       <!-- 按钮 -->
       <!-- 按钮 -->
       <div class="control-bar" v-if="config.deviceType != 'dust'">
       <div class="control-bar" v-if="config.deviceType != 'dust'">
-        <a-button class="control-btn" @click="handleSpary(true)">启动喷淋</a-button>
-        <a-button class="control-btn" @click="handleSpary(false)">停止喷淋</a-button>
+        <a-button class="control-btn" @click="handleSpary()">启动喷淋</a-button>
+        <a-button class="control-btn" @click="handleSpary()">停止喷淋</a-button>
         <div class="switch-wrapper">
         <div class="switch-wrapper">
           <span class="text1">自动</span>
           <span class="text1">自动</span>
           <div class="toggle-switch" :class="{ 'is-on': isOn }" @click="toggleSwitch">
           <div class="toggle-switch" :class="{ 'is-on': isOn }" @click="toggleSwitch">
@@ -22,8 +22,8 @@
           <div class="group-title" v-if="config.deviceType != 'dust'">
           <div class="group-title" v-if="config.deviceType != 'dust'">
             <a-checkbox
             <a-checkbox
               class="check-btn"
               class="check-btn"
-              :checked="selectedSids.includes(beltData.sid)"
-              @change="(e) => handleCheckChange(e.target.checked, beltData.sid)"
+              :checked="selectedSids.includes(beltData.deviceID)"
+              @change="(e) => handleCheckChange(e.target.checked, beltData, beltData.deviceType)"
             >
             >
               控制勾选
               控制勾选
             </a-checkbox>
             </a-checkbox>
@@ -56,11 +56,22 @@
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
+  <HandleModal
+    v-if="!globalConfig?.simulatedPassword"
+    :modal-is-show="modalIsShow"
+    :modal-title="modalTitle"
+    :modal-type="modalType"
+    @handle-ok="handleOK"
+    @handle-cancel="handleCancel"
+  />
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { computed, onMounted, ref } from 'vue';
+import { computed, onMounted, ref, inject } from 'vue';
 import { getFormattedText } from '../../hooks/helper';
 import { getFormattedText } from '../../hooks/helper';
+import HandleModal from '/@/views/vent/monitorManager/gateMonitor/modal.vue';
+import { message } from 'ant-design-vue';
+import { deviceControlApi } from '/@/api/vent/index';
 
 
 const props = defineProps<{
 const props = defineProps<{
   config: Array<{
   config: Array<{
@@ -82,37 +93,74 @@ const props = defineProps<{
     [key: string]: any;
     [key: string]: any;
   };
   };
 }>();
 }>();
-
-// --- 存储选中的 sid ---
+const modalIsShow = ref<boolean>(false); // 是否显示模态框
+const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
+const modalType = ref(''); // 模态框内容显示类型,设备操作类型
+const paramcode = ref(''); // 模态框操作代码
+const globalConfig = inject<any>('globalConfig');
+const selectType = ref('');
+// 存储选中id
 const selectedSids = ref<string[]>([]);
 const selectedSids = ref<string[]>([]);
 const isOn = ref(false);
 const isOn = ref(false);
-// --- 处理勾选变化 ---
-const handleCheckChange = (checked: boolean, sid: string) => {
+const openGateControlModal = (customTitle?: string) => {
+  modalIsShow.value = true;
+};
+
+// 处理勾选变化
+const handleCheckChange = (checked: boolean, data, deviceType: string) => {
   if (checked) {
   if (checked) {
-    // 勾选:如果不存在则加入数组
-    if (!selectedSids.value.includes(sid)) {
-      selectedSids.value.push(sid);
+    // 勾选
+    if (!selectedSids.value.includes(data.deviceID)) {
+      selectedSids.value.push(data.deviceID);
+      selectType.value = deviceType;
     }
     }
   } else {
   } else {
-    // 取消勾选:从数组中移除
-    const index = selectedSids.value.indexOf(sid);
+    // 取消勾选
+    const index = selectedSids.value.indexOf(data.deviceID);
     if (index > -1) {
     if (index > -1) {
       selectedSids.value.splice(index, 1);
       selectedSids.value.splice(index, 1);
+      selectType.value = '';
     }
     }
   }
   }
-  console.log('当前选中的 SID 列表:', selectedSids.value);
 };
 };
 const getBgClass = (index) => {
 const getBgClass = (index) => {
   return index % 2 === 0 ? 'bg-1' : 'bg-2';
   return index % 2 === 0 ? 'bg-1' : 'bg-2';
 };
 };
 
 
-const handleSpary = (state: boolean) => {
-  if (state) {
-    console.log('启动喷淋');
-  } else {
-    console.log('停止喷淋');
-  }
+const handleSpary = () => {
+  openGateControlModal();
 };
 };
+function handleOK(passWord, handlerState, value?) {
+  console.log('handleOK', passWord, handlerState, value);
+  if (!passWord && !globalConfig?.simulatedPassword) {
+    message.warning('请输入密码');
+    return;
+  }
+  let data = {
+    deviceid: selectedSids.value.join(','),
+    devicetype: selectType.value,
+    paramcode: handlerState,
+    password: passWord || globalConfig?.simulatedPassword,
+    value: value ? value : null,
+  };
+  deviceControlApi(data)
+    .then((res) => {
+      if (res.success) {
+        message.success('指令已下发成功!');
+      } else {
+        message.error(res.message);
+      }
+    })
+    .finally(() => {
+      handleCancel();
+    });
+}
+function handleCancel() {
+  modalIsShow.value = false;
+  modalTitle.value = '';
+  modalType.value = '';
+}
+
 function toggleSwitch() {
 function toggleSwitch() {
   isOn.value = !isOn.value;
   isOn.value = !isOn.value;
 }
 }

+ 15 - 4
src/views/vent/home/configurable/components/belt/WarningResultList.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div class="warning-result-panel">
   <div class="warning-result-panel">
     <div class="table-container">
     <div class="table-container">
-      <table v-if="!!data" class="warning-table">
+      <table class="warning-table">
         <thead class="table-header">
         <thead class="table-header">
           <tr>
           <tr>
             <th v-for="col in config.columns" :key="col.prop" :style="{ width: col.width }">
             <th v-for="col in config.columns" :key="col.prop" :style="{ width: col.width }">
@@ -11,7 +11,7 @@
         </thead>
         </thead>
 
 
         <tbody class="table-body">
         <tbody class="table-body">
-          <tr v-for="(row, index) in data[config.tableReadFrom]" :key="index" class="table-row">
+          <tr v-for="(row, index) in tableList" :key="row.warnId || row.id || index" class="table-row">
             <td
             <td
               v-for="col in config.columns"
               v-for="col in config.columns"
               :key="col.prop"
               :key="col.prop"
@@ -51,7 +51,7 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { onMounted, ref } from 'vue';
+import { ref, watch } from 'vue';
 import ExecutePlan from './ExecutePlan.vue';
 import ExecutePlan from './ExecutePlan.vue';
 import ExecuteAdvice from './ExecuteAdvice.vue';
 import ExecuteAdvice from './ExecuteAdvice.vue';
 const props = defineProps<{
 const props = defineProps<{
@@ -72,9 +72,21 @@ const props = defineProps<{
     [key: string]: any;
     [key: string]: any;
   };
   };
 }>();
 }>();
+
 const visible = ref(false);
 const visible = ref(false);
 const visible1 = ref(false);
 const visible1 = ref(false);
 const planData = ref([]);
 const planData = ref([]);
+const tableList = ref<any[]>([]);
+
+watch(
+  () => props.data?.[props.config.tableReadFrom],
+  (newArr) => {
+    if (!newArr) return;
+    // 只更新内容,不重建表格
+    tableList.value = newArr;
+  },
+  { deep: true, immediate: true }
+);
 function getStatusText(status) {
 function getStatusText(status) {
   const map = {
   const map = {
     '102': '黄色预警',
     '102': '黄色预警',
@@ -103,7 +115,6 @@ function openModel1(row) {
   planData.value = row.alarmRecords['1'];
   planData.value = row.alarmRecords['1'];
   visible1.value = true;
   visible1.value = true;
 }
 }
-onMounted(() => {});
 </script>
 </script>
 
 
 <style scoped lang="less">
 <style scoped lang="less">

+ 7 - 7
src/views/vent/home/configurable/configurable.data.ts

@@ -181,7 +181,7 @@ export const testConfigVentSsl: Config[] = [
       complex_list: [],
       complex_list: [],
       gallery_list: [],
       gallery_list: [],
       preset: [],
       preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:420px;height:280px;',
       size: 'width:420px;height:280px;',
@@ -291,7 +291,7 @@ export const testConfigVentSsl: Config[] = [
       complex_list: [],
       complex_list: [],
       gallery_list: [],
       gallery_list: [],
       preset: [],
       preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:420px;height:280px;',
       size: 'width:420px;height:280px;',
@@ -636,7 +636,7 @@ export const testConfigVent: Config[] = [
   //         readFrom: 'device',
   //         readFrom: 'device',
   //       },
   //       },
   //     ],
   //     ],
-  //     to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+  //     to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
   //   },
   //   },
   //   showStyle: {
   //   showStyle: {
   //     size: 'width:390px;height:260px;',
   //     size: 'width:390px;height:260px;',
@@ -2886,7 +2886,7 @@ export const testConfigVentRealtime: Config[] = [
           readFrom: 'device',
           readFrom: 'device',
         },
         },
       ],
       ],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:470px;height:280px;',
       size: 'width:470px;height:280px;',
@@ -4008,7 +4008,7 @@ export const testConfigVentNew: Config[] = [
         //  },
         //  },
         //},
         //},
       },
       },
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:440px;height:280px;',
       size: 'width:440px;height:280px;',
@@ -5039,7 +5039,7 @@ export const testConfigWarnMonitor: Config[] = [
   },
   },
 ];
 ];
 
 
-export let menuList: any[] = [
+export const menuList: any[] = [
   { name: '灾害预警', MenuItemList: [] },
   { name: '灾害预警', MenuItemList: [] },
   { name: '通风预警', MenuItemList: [] },
   { name: '通风预警', MenuItemList: [] },
   { name: '火灾预警', MenuItemList: [] },
   { name: '火灾预警', MenuItemList: [] },
@@ -6508,7 +6508,7 @@ export const testConfigVent182: Config[] = [
       complex_list: [],
       complex_list: [],
       gallery_list: [],
       gallery_list: [],
       preset: [],
       preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:420px;height:280px;',
       size: 'width:420px;height:280px;',

+ 1 - 1
src/views/vent/home/configurable/configurable.data.wz.ts

@@ -830,7 +830,7 @@ export const testConfigSY: Config[] = [
       complex_list: [],
       complex_list: [],
       gallery_list: [],
       gallery_list: [],
       preset: [],
       preset: [],
-      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate_xinJianFuXieJin',
+      to: '/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=gate',
     },
     },
     showStyle: {
     showStyle: {
       size: 'width:450px;height:280px;',
       size: 'width:450px;height:280px;',

+ 47 - 20
src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts

@@ -503,29 +503,56 @@ export const vehicleFormConfig = {
     span: 4,
     span: 4,
   },
   },
 };
 };
+
 const { sysOrgCode } = useGlobSetting();
 const { sysOrgCode } = useGlobSetting();
 export const noDetailArr = ['nitrogen', 'forcFan']; // 前端详情的,
 export const noDetailArr = ['nitrogen', 'forcFan']; // 前端详情的,
 // 棋盘井球阀监测数据只有温度
 // 棋盘井球阀监测数据只有温度
-export const haveDetailArr = [
-  'windrect',
-  'window',
-  'gate',
-  'fanlocal',
-  'fanmain',
-  'fiber',
-  'bundletube',
-  'gaspatrol',
-  // 'dusting', // 保德要求去掉
-  // 'ballvalve',
-  'pump',
-  'safetymonitor',
-  'nitrogen',
-  'atomizing',
-  'firemon',
-  'forcFan',
-  'pulping',
-  'door',
-];
+export const haveDetailArr = () => {
+  if (sysOrgCode == 'hhnyhql') {
+    return [
+      'windrect',
+      'window',
+      'gate',
+      'fanlocal',
+      'fanmain',
+      // 'fiber', // 光纤不显示详情
+      'bundletube',
+      'gaspatrol',
+      // 'dusting', // 保德要求去掉
+      // 'ballvalve',
+      'pump',
+      'safetymonitor',
+      // 'nitrogen', // 注氮不显示详情
+      'atomizing',
+      'firemon',
+      'forcFan',
+      'pulping',
+      'door',
+    ];
+  } else {
+    return [
+      'windrect',
+      'window',
+      'gate',
+      'fanlocal',
+      'fanmain',
+      'fiber',
+      'bundletube',
+      'gaspatrol',
+      // 'dusting', // 保德要求去掉
+      // 'ballvalve',
+      'pump',
+      'safetymonitor',
+      'nitrogen',
+      'atomizing',
+      'firemon',
+      'forcFan',
+      'pulping',
+      'door',
+    ];
+  }
+};
+
 // 有操作记录的设备类型
 // 有操作记录的设备类型
 export const haveHandlerArr = [
 export const haveHandlerArr = [
   'windrect',
   'windrect',

+ 3 - 3
src/views/vent/monitorManager/deviceMonitor/components/device/index.vue

@@ -194,7 +194,7 @@
                 <template #action="{ record }">
                 <template #action="{ record }">
                   <TableAction
                   <TableAction
                     :actions="
                     :actions="
-                      haveDetailArr.find((item) => deviceType.startsWith(item))
+                      haveDetailArr().find((item) => deviceType.startsWith(item))
                         ? [
                         ? [
                             {
                             {
                               label: '详情',
                               label: '详情',
@@ -235,7 +235,7 @@
                 <template #action="{ record }">
                 <template #action="{ record }">
                   <TableAction
                   <TableAction
                     :actions="
                     :actions="
-                      haveDetailArr.find((item) => deviceType.startsWith(item))
+                      haveDetailArr().find((item) => deviceType.startsWith(item))
                         ? [
                         ? [
                             {
                             {
                               label: '详情',
                               label: '详情',
@@ -416,7 +416,7 @@
                 <template #action="{ record }">
                 <template #action="{ record }">
                   <TableAction
                   <TableAction
                     :actions="
                     :actions="
-                      haveDetailArr.find((item) => deviceType.startsWith(item))
+                      haveDetailArr().find((item) => deviceType.startsWith(item))
                         ? [
                         ? [
                             {
                             {
                               label: '详情',
                               label: '详情',

+ 103 - 103
src/views/vent/monitorManager/gateMonitor/components/CarDamageTable.vue

@@ -6,8 +6,7 @@
           <div class="area-item">
           <div class="area-item">
             <div class="item-text">风门状态:</div>
             <div class="item-text">风门状态:</div>
             <a-select ref="select" v-model:value="type" style="width: 240px" placeholder="请选择风门状态">
             <a-select ref="select" v-model:value="type" style="width: 240px" placeholder="请选择风门状态">
-              <a-select-option v-for="(item, index) in typeList" :key="item.value" :value="item.value">{{
-                item.label }}</a-select-option>
+              <a-select-option v-for="(item, index) in typeList" :key="item.value" :value="item.value">{{ item.label }}</a-select-option>
             </a-select>
             </a-select>
           </div>
           </div>
         </a-col>
         </a-col>
@@ -18,148 +17,149 @@
               <a-select-option v-for="(item, index) in typeList" :key="item.value" :value="item.value">{{
               <a-select-option v-for="(item, index) in typeList" :key="item.value" :value="item.value">{{
                 item.label }}</a-select-option>
                 item.label }}</a-select-option>
             </a-select> -->
             </a-select> -->
-            <a-date-picker v-model:value="startTime" style="width:240px" show-time
-              valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" />
+            <a-date-picker v-model:value="startTime" style="width: 240px" show-time valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择开始时间" />
           </div>
           </div>
         </a-col>
         </a-col>
-          <a-col :span="5">
+        <a-col :span="5">
           <div class="area-item">
           <div class="area-item">
             <div class="item-text">结束时间:</div>
             <div class="item-text">结束时间:</div>
-            <a-date-picker v-model:value="endTime" style="width:240px" show-time
-                            valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" />
+            <a-date-picker v-model:value="endTime" style="width: 240px" show-time valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束时间" />
           </div>
           </div>
         </a-col>
         </a-col>
         <a-col :span="5">
         <a-col :span="5">
-          <a-button type="primary" preIcon="ant-design:search-outlined" style="margin-left: 10px"
-            @click="getSearch">查询</a-button>
+          <a-button type="primary" preIcon="ant-design:search-outlined" style="margin-left: 10px" @click="getSearch">查询</a-button>
           <a-button preIcon="ant-design:sync-outlined" style="margin: 0px 15px" @click="getReset">重置</a-button>
           <a-button preIcon="ant-design:sync-outlined" style="margin: 0px 15px" @click="getReset">重置</a-button>
         </a-col>
         </a-col>
       </a-row>
       </a-row>
     </div>
     </div>
     <div class="content-area">
     <div class="content-area">
-      <a-table size="small" :dataSource="dataSource" :columns="carColumns" :pagination="pagination"
-        :scroll="{ y: 200, }" @change="pageChange">
+      <a-table size="small" :dataSource="dataSource" :columns="carColumns" :pagination="pagination" :scroll="{ y: 200 }" @change="pageChange">
         <template #bodyCell="{ column, text }">
         <template #bodyCell="{ column, text }">
           <template
           <template
-            v-if="column.dataIndex == 'carNo' || column.dataIndex == 'distance' || column.dataIndex == 'photo' || column.dataIndex == 'captureTime'">
+            v-if="column.dataIndex == 'carNo' || column.dataIndex == 'distance' || column.dataIndex == 'photo' || column.dataIndex == 'captureTime'"
+          >
             <div>{{ text ? text : '-' }}</div>
             <div>{{ text ? text : '-' }}</div>
           </template>
           </template>
           <template v-if="column.dataIndex == 'type'">
           <template v-if="column.dataIndex == 'type'">
-            <div>{{ text == '0' ? '正常开闭' : text == '1' ? '风门常开' : text == '2' ? '风门关闭不严' : text == '3' ? '疑似车辆撞击' : '--' }}
-            </div>
+            <div>{{ text == '0' ? '正常开闭' : text == '1' ? '风门常开' : text == '2' ? '风门关闭不严' : text == '3' ? '疑似车辆撞击' : '--' }} </div>
           </template>
           </template>
           <template v-if="column.dataIndex == 'photoC'">
           <template v-if="column.dataIndex == 'photoC'">
-            <img :src="text" alt="" class="photo_zp" @click="preViewImg(text)">
+            <img :src="text" alt="" class="photo_zp" @click="preViewImg(text)" />
           </template>
           </template>
         </template>
         </template>
       </a-table>
       </a-table>
     </div>
     </div>
     <!-- 预览抓拍图像 -->
     <!-- 预览抓拍图像 -->
     <a-modal v-model:visible="visiblePhoto" width="850px" :title="titlePhoto" :footer="null" centered destroyOnClose>
     <a-modal v-model:visible="visiblePhoto" width="850px" :title="titlePhoto" :footer="null" centered destroyOnClose>
-      <img :src="imgSrc" alt="">
+      <img :src="imgSrc" alt="" />
     </a-modal>
     </a-modal>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref, reactive, onMounted } from 'vue'
-import { carColumns, typeList } from '../gate.data'
-
-let props = defineProps({
-  deviceListApi: {
-    type: Function,
-    required: true,
-  },
-  gateId: {
-    type: String,
-    default: ''
-  }
-})
-
-let type = ref('0')
-let startTime=ref('')
-let endTime=ref('')
-let dataSource = ref<any[]>([])
-//分页参数配置
-let pagination = reactive({
-  current: 1, // 当前页码
-  pageSize: 10, // 每页显示条数
-  total: 0, // 总条目数,后端返回
-  // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
-  showSizeChanger: true, // 是否可改变每页显示条数
-  pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
-});
-let visiblePhoto = ref(false)
-let titlePhoto = ref('抓拍图像预览')
-let imgSrc = ref('')//抓拍图像路径
+  import { ref, reactive, onMounted } from 'vue';
+  import { carColumns, typeList } from '../gate.data';
 
 
+  let props = defineProps({
+    deviceListApi: {
+      type: Function,
+      required: true,
+    },
+    gateId: {
+      type: String,
+      default: '',
+    },
+  });
 
 
+  let type = ref('0');
+  let startTime = ref('');
+  let endTime = ref('');
+  let dataSource = ref<any[]>([]);
+  //分页参数配置
+  let pagination = reactive({
+    current: 1, // 当前页码
+    pageSize: 10, // 每页显示条数
+    total: 0, // 总条目数,后端返回
+    // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
+    showSizeChanger: true, // 是否可改变每页显示条数
+    pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
+  });
+  let visiblePhoto = ref(false);
+  let titlePhoto = ref('抓拍图像预览');
+  let imgSrc = ref(''); //抓拍图像路径
 
 
-//查询列表
-async function getCarList() {
-  let res = await props.deviceListApi({ gateIds: props.gateId, type: type.value,startTime:startTime.value,endTime:endTime.value,  pageNo: pagination.current, pageSize: pagination.pageSize })
-  const remoteUrl = import.meta.env.DEV ? 'http://182.92.126.35' : 'http://' + window.location.hostname;
-  dataSource.value = res.records.map(el => {
-    return {
-      photoC: `${remoteUrl}:9999/sys/common/static/${el.photo.substring(el.photo.indexOf('/gate_monitor'))}`,
-      ...el
-    }
-  })
-  pagination.total = res.total
-}
-function pageChange(val) {
-  pagination.current = val.current;
-  pagination.pageSize = val.pageSize;
-  getCarList()
-}
-//查询
-function getSearch() {
-  pagination.current = 1
-  getCarList()
-}
-//重置
-function getReset() {
-  type.value = '0'
-  startTime.value=''
-  endTime.value=''
-  pagination.current = 1
-  getCarList()
-}
-//预览抓拍图像
-function preViewImg(img) {
-  visiblePhoto.value = true
-  imgSrc.value = img
-}
-onMounted(() => {
-  getCarList()
-})
+  //查询列表
+  async function getCarList() {
+    let res = await props.deviceListApi({
+      gateIds: props.gateId,
+      type: type.value,
+      startTime: startTime.value,
+      endTime: endTime.value,
+      pageNo: pagination.current,
+      pageSize: pagination.pageSize,
+    });
+    const remoteUrl = import.meta.env.DEV ? 'http://182.92.126.35' : 'http://' + window.location.hostname;
+    dataSource.value = res.records.map((el) => {
+      return {
+        photoC: `${remoteUrl}:9999/sys/common/static/${el.photo.substring(el.photo.indexOf('/gate_monitor'))}`,
+        ...el,
+      };
+    });
+    pagination.total = res.total;
+  }
+  function pageChange(val) {
+    pagination.current = val.current;
+    pagination.pageSize = val.pageSize;
+    getCarList();
+  }
+  //查询
+  function getSearch() {
+    pagination.current = 1;
+    getCarList();
+  }
+  //重置
+  function getReset() {
+    type.value = '0';
+    startTime.value = '';
+    endTime.value = '';
+    pagination.current = 1;
+    getCarList();
+  }
+  //预览抓拍图像
+  function preViewImg(img) {
+    visiblePhoto.value = true;
+    imgSrc.value = img;
+  }
+  onMounted(() => {
+    getCarList();
+  });
 </script>
 </script>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>
-.car-damage {
-  .search-area {
-    margin: 15px;
+  .car-damage {
+    .search-area {
+      margin: 15px;
 
 
-    .area-item {
-      display: flex;
-      align-items: center;
+      .area-item {
+        display: flex;
+        align-items: center;
 
 
-      .item-text {
-        color: #fff;
+        .item-text {
+          color: #fff;
+        }
       }
       }
     }
     }
-  }
 
 
-  .zxm-picker,
-  .zxm-input {
-    border: 1px solid #3ad8ff77;
-    background-color: #ffffff00;
-    color: #fff;
-  }
+    .zxm-picker,
+    .zxm-input {
+      border: 1px solid #3ad8ff77;
+      background-color: #ffffff00;
+      color: #fff;
+    }
 
 
-  .photo_zp {
-    width: 120px;
-    cursor: pointer;
+    .photo_zp {
+      width: 120px;
+      cursor: pointer;
+    }
   }
   }
-}
 </style>
 </style>

+ 9 - 9
src/views/vent/monitorManager/gateMonitor/gate.threejs.ts

@@ -844,7 +844,7 @@ const loadModel = (code): Promise<any> => {
   return import('./gate.threejs.yy').then((r) => r.default);
   return import('./gate.threejs.yy').then((r) => r.default);
 };
 };
 
 
-export const mountedThree = (playerDom) => {
+export const mountedThree = () => {
   // const { sysOrgCode } = useGlobSetting();
   // const { sysOrgCode } = useGlobSetting();
   // const sysOrgCode = 'gsgszdek';
   // const sysOrgCode = 'gsgszdek';
   return new Promise(async (resolve) => {
   return new Promise(async (resolve) => {
@@ -860,12 +860,12 @@ export const mountedThree = (playerDom) => {
           case 'fmXr':
           case 'fmXr':
             const FmXR = await loadModel('FmXR');
             const FmXR = await loadModel('FmXR');
             fmXr = new FmXR(model);
             fmXr = new FmXR(model);
-            fmXr.mountedThree(playerDom);
+            fmXr.mountedThree();
             break;
             break;
           case 'fmYy':
           case 'fmYy':
             const Fm1 = await loadModel('Fm1');
             const Fm1 = await loadModel('Fm1');
             fm1 = new Fm1(model);
             fm1 = new Fm1(model);
-            fm1.mountedThree(playerDom);
+            fm1.mountedThree();
             break;
             break;
           case 'gate_qd':
           case 'gate_qd':
             const Fm3 = await loadModel('Fm3');
             const Fm3 = await loadModel('Fm3');
@@ -943,24 +943,24 @@ export const mountedThree = (playerDom) => {
     } else {
     } else {
       const Fm3 = await loadModel('Fm3');
       const Fm3 = await loadModel('Fm3');
       fm3 = new Fm3(model);
       fm3 = new Fm3(model);
-      fm3.mountedThree(playerDom);
+      fm3.mountedThree();
       const FmTwoSs = await loadModel('FmTwoSs');
       const FmTwoSs = await loadModel('FmTwoSs');
       fmTwoSs = new FmTwoSs(model);
       fmTwoSs = new FmTwoSs(model);
-      fmTwoSs.mountedThree(playerDom);
+      fmTwoSs.mountedThree();
       const Fm2 = await loadModel('Fm2');
       const Fm2 = await loadModel('Fm2');
       fm2 = new Fm2(model);
       fm2 = new Fm2(model);
-      fm2.mountedThree(playerDom);
+      fm2.mountedThree();
       // 三道门
       // 三道门
       const FmThreeTl = await loadModel('FmThreeTl');
       const FmThreeTl = await loadModel('FmThreeTl');
       fmThreeTl = new FmThreeTl(model);
       fmThreeTl = new FmThreeTl(model);
-      if (fmThreeTl) fmThreeTl.mountedThree(playerDom);
+      if (fmThreeTl) fmThreeTl.mountedThree();
       const FmXR = await loadModel('FmXR');
       const FmXR = await loadModel('FmXR');
       fmXr = new FmXR(model);
       fmXr = new FmXR(model);
-      fmXr.mountedThree(playerDom);
+      fmXr.mountedThree();
       // 液压风门
       // 液压风门
       const Fm1 = await loadModel('Fm1');
       const Fm1 = await loadModel('Fm1');
       fm1 = new Fm1(model);
       fm1 = new Fm1(model);
-      fm1.mountedThree(playerDom);
+      fm1.mountedThree();
       resolve(null);
       resolve(null);
     }
     }
 
 

+ 3 - 3
src/views/vent/monitorManager/gateMonitor/gate.threejs.xr.ts

@@ -74,8 +74,8 @@ class FmXR {
     const screenDownText = VENT_PARAM['modalText']
     const screenDownText = VENT_PARAM['modalText']
       ? VENT_PARAM['modalText']
       ? VENT_PARAM['modalText']
       : History_Type['type'] == 'remote'
       : History_Type['type'] == 'remote'
-      ? `国能神东煤炭集团监制`
-      : '煤科通安(北京)智控科技有限公司研制';
+        ? `国能神东煤炭集团监制`
+        : '煤科通安(北京)智控科技有限公司研制';
 
 
     const screenDownTextX = 80 - (screenDownText.length - 10) * 9;
     const screenDownTextX = 80 - (screenDownText.length - 10) * 9;
     const textArr = [
     const textArr = [
@@ -490,7 +490,7 @@ class FmXR {
     }
     }
   }
   }
 
 
-  mountedThree(playerDom) {
+  mountedThree() {
     this.group = new THREE.Object3D();
     this.group = new THREE.Object3D();
     this.group.name = this.modelName;
     this.group.name = this.modelName;
     return new Promise((resolve) => {
     return new Promise((resolve) => {

+ 3 - 3
src/views/vent/monitorManager/gateMonitor/gate.threejs.yy.ts

@@ -76,8 +76,8 @@ class Fm1 {
     const screenDownText = VENT_PARAM['modalText']
     const screenDownText = VENT_PARAM['modalText']
       ? VENT_PARAM['modalText']
       ? VENT_PARAM['modalText']
       : History_Type['type'] == 'remote'
       : History_Type['type'] == 'remote'
-      ? `国能神东煤炭集团监制`
-      : '煤科通安(北京)智控科技有限公司研制';
+        ? `国能神东煤炭集团监制`
+        : '煤科通安(北京)智控科技有限公司研制';
 
 
     const screenDownTextX = 80 - (screenDownText.length - 11) * 9;
     const screenDownTextX = 80 - (screenDownText.length - 11) * 9;
     const textArr = [
     const textArr = [
@@ -447,7 +447,7 @@ class Fm1 {
     }
     }
   }
   }
 
 
-  mountedThree(playerDom) {
+  mountedThree() {
     this.group = new THREE.Object3D();
     this.group = new THREE.Object3D();
     this.group.name = this.modelName;
     this.group.name = this.modelName;
     return new Promise((resolve) => {
     return new Promise((resolve) => {

+ 7 - 6
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -610,7 +610,7 @@
     if (!selectRow) return;
     if (!selectRow) return;
     loading.value = true;
     loading.value = true;
     selectRowIndex.value = index;
     selectRowIndex.value = index;
-    gateId.value=selectRow.deviceID
+    gateId.value = selectRow.deviceID;
     const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
     const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
     Object.assign(selectData, initData, selectRow, baseData);
     Object.assign(selectData, initData, selectRow, baseData);
     isFrontOpenRunning = false; //开关门动作是否在进行
     isFrontOpenRunning = false; //开关门动作是否在进行
@@ -738,7 +738,7 @@
       password: passWord || globalConfig?.simulatedPassword,
       password: passWord || globalConfig?.simulatedPassword,
       masterComputer: selectData.masterComputer,
       masterComputer: selectData.masterComputer,
     };
     };
-    let handler = () => { };
+    let handler = () => {};
 
 
     switch (handlerState) {
     switch (handlerState) {
       case '1': // 打开前门
       case '1': // 打开前门
@@ -983,9 +983,8 @@
       await getMonitor(true);
       await getMonitor(true);
     } else {
     } else {
       loading.value = true;
       loading.value = true;
-      const playerDom = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
-
-      mountedThree(playerDom)
+      // const playerDom = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
+      mountedThree()
         .then(async () => {
         .then(async () => {
           if (sysOrgCode != 'zmhjhzmy') {
           if (sysOrgCode != 'zmhjhzmy') {
             await getMonitor(true);
             await getMonitor(true);
@@ -999,7 +998,9 @@
             });
             });
           }
           }
         })
         })
-        .catch(() => { });
+        .catch((e) => {
+          console.log(e);
+        });
     }
     }
   });
   });