2 次代碼提交 0e66fa7b39 ... 7c658d58d5

作者 SHA1 備註 提交日期
  bobo04052021@163.com 7c658d58d5 Merge branch 'master' of http://39.97.59.228:8013/hrx/mky-vent-base 3 周之前
  bobo04052021@163.com 9e9c619959 [Feat 0000]皮带巷三级防灭火喷淋接口对接 3 周之前
共有 21 個文件被更改,包括 1572 次插入1801 次删除
  1. 二進制
      src/assets/images/beltFire/activeBtn.png
  2. 二進制
      src/assets/images/beltFire/normalBtn.png
  3. 二進制
      src/assets/images/beltFire/yjkf/1-1.png
  4. 12 0
      src/views/vent/deviceManager/comment/DeviceModalLeather.vue
  5. 53 34
      src/views/vent/deviceManager/comment/warningTabel/BaseModal1Leather.vue
  6. 173 173
      src/views/vent/deviceManager/comment/warningTabel/index3.vue
  7. 1 0
      src/views/vent/deviceManager/comment/warningTabel/indexLeather.vue
  8. 18 28
      src/views/vent/deviceManager/comment/warningTabel/warning.data.ts
  9. 354 321
      src/views/vent/home/configurable/belt/belt-new.vue
  10. 317 284
      src/views/vent/home/configurable/belt/belt.vue
  11. 82 78
      src/views/vent/home/configurable/belt/components/BeltNav.vue
  12. 31 39
      src/views/vent/home/configurable/belt/components/Header.vue
  13. 105 97
      src/views/vent/home/configurable/belt/components/ModuleCommon.vue
  14. 0 401
      src/views/vent/home/configurable/belt/components/contentBelt.vue
  15. 1 3
      src/views/vent/home/configurable/belt/components/detail/gateBoard.vue
  16. 88 0
      src/views/vent/home/configurable/belt/configurable.api.ts
  17. 74 74
      src/views/vent/home/configurable/belt/configurable.data.ts
  18. 0 2
      src/views/vent/home/configurable/components/belt/CameraListTest.vue
  19. 1 1
      src/views/vent/home/configurable/components/belt/FireSensorAnalysis.vue
  20. 261 265
      src/views/vent/home/configurable/components/belt/SprayControl.vue
  21. 1 1
      src/views/vent/home/configurable/components/content.vue

二進制
src/assets/images/beltFire/activeBtn.png


二進制
src/assets/images/beltFire/normalBtn.png


二進制
src/assets/images/beltFire/yjkf/1-1.png


+ 12 - 0
src/views/vent/deviceManager/comment/DeviceModalLeather.vue

@@ -50,6 +50,18 @@
       <a-tab-pane v-if="deviceType == 'managesys'" key="4" tab="预警条目管理">
         <ManagerWarningDeviceTable v-if="activeKey == '4'" :deviceId="deviceData.id" />
       </a-tab-pane>
+      <a-tab-pane key="5" :tab="deviceType !== 'managesys' ? '点位(报警)配置' : '配置预警设备'">
+        <template v-if="activeKey == '5'">
+          <WarningTable v-if="deviceType !== 'managesys'" :deviceId="deviceData.id" :pointType="deviceData.strtype" />
+          <BackWindDeviceTable v-else :deviceId="deviceData.id" />
+        </template>
+      </a-tab-pane>
+      <a-tab-pane v-if="deviceType == 'managesys'" key="6" tab="配置控制设备">
+        <template v-if="activeKey == '6'">
+          <WarningTable v-if="deviceType !== 'managesys'" :deviceId="deviceData.id" :pointType="deviceData.strtype" />
+          <ManagerWarningTable v-else :deviceId="deviceData.id" />
+        </template>
+      </a-tab-pane>
       <a-tab-pane v-if="deviceType == 'managesys'" key="14" tab="配置预警解除后控制设备">
         <template v-if="activeKey == '14'">
           <ManagerWarningTable :deviceId="deviceData.id" :monitor-type="3" />

+ 53 - 34
src/views/vent/deviceManager/comment/warningTabel/BaseModal1Leather.vue

@@ -1,41 +1,54 @@
 <template>
   <BasicModal @register="register" :title="title" :width="1600" :min-height="500" v-bind="$attrs" @ok="onSubmit">
-    <!-- 顶部基础表单 -->
     <BasicForm @register="registerForm" />
-
-    <!-- 左右分栏:预警配置 + 控制配置 -->
     <div class="double-form__layout">
-      <!-- 左侧:配置预警设备 -->
+      <!-- 配置预警设备 -->
       <div class="setting-form__wrapper">
         <h3 class="panel-title">配置预警设备</h3>
         <div class="form-row" v-for="(item, idx) in warnList" :key="`warn-${idx}`">
-          <BasicForm :model="item" :schemas="deviceFormColumns" layout="inline" label-width="0" :show-action-button-group="false" />
+          <BasicForm
+            ref="warnFormRefs"
+            :model="item"
+            :schemas="deviceFormColumns"
+            layout="inline"
+            label-width="0"
+            :show-action-button-group="false"
+          />
           <a-button type="link" normal @click="delWarnRow(idx)" :disabled="warnList.length <= 1">删除</a-button>
         </div>
         <a-button type="dashed" block @click="addWarnRow" class="setting-form__button">新增预警配置</a-button>
       </div>
-
-      <!-- 右侧:配置控制设备 -->
+      <!-- 配置控制设备 -->
       <div class="setting-form__wrapper">
         <h3 class="panel-title">配置控制设备</h3>
         <div class="form-row" v-for="(item, idx) in controlList" :key="`control-${idx}`">
-          <BasicForm :model="item" :schemas="deviceControlColumns" layout="inline" label-width="0" :show-action-button-group="false" />
-          <a-button type="link" normal @click="delControlRow(idx)" :disabled="controlList.length <= 1">删除</a-button>
+          <BasicForm
+            ref="controlFormRefs"
+            :model="item"
+            :schemas="deviceControlColumns"
+            layout="inline"
+            label-width="0"
+            :show-action-button-group="false"
+          />
+          <a-button type="link" normal @click="delControlRow(idx, item)" :disabled="controlList.length <= 1">删除</a-button>
         </div>
         <a-button type="dashed" block @click="addControlRow" class="setting-form__button">新增控制配置</a-button>
       </div>
     </div>
   </BasicModal>
 </template>
-
 <script lang="ts" setup>
-import { ref, unref } from 'vue';
+import { ref, unref, toRaw } from 'vue';
 import { BasicForm, useForm } from '/@/components/Form';
 import { BasicModal, useModalInner } from '/@/components/Modal';
 import { message } from 'ant-design-vue';
 import { deviceFormColumns, deviceControlColumns } from './warning.data';
+import { workFaceWarningDelete } from './warning.api';
+
 import type { FormSchema } from '/@/components/Form/src/types/form';
+import type { FormActionType } from '/@/components/Form'; // 引入类型定义
 
+// ... props 和 emits 定义保持不变 ...
 const props = defineProps({
   formSchemas: {
     type: Array as PropType<FormSchema[]>,
@@ -49,9 +62,9 @@ const emit = defineEmits(['add', 'update']);
 const title = ref('');
 const isUpdate = ref(false);
 
-// ==========================================
-//  左侧:预警配置列表(独立)
-// ==========================================
+const warnFormRefs = ref<FormActionType[]>([]);
+const controlFormRefs = ref<FormActionType[]>([]);
+
 const warnList = ref([getEmptyWarnRow()]);
 function getEmptyWarnRow() {
   return {
@@ -62,6 +75,7 @@ function getEmptyWarnRow() {
     cxTime: null,
     dataTrend: '',
     trendCxTime: null,
+    monitorType: '2',
   };
 }
 function addWarnRow() {
@@ -72,9 +86,6 @@ function delWarnRow(idx) {
   warnList.value.splice(idx, 1);
 }
 
-// ==========================================
-//  右侧:控制配置列表(独立)
-// ==========================================
 const controlList = ref([getEmptyControlRow()]);
 function getEmptyControlRow() {
   return {
@@ -83,19 +94,19 @@ function getEmptyControlRow() {
     value: '',
     orderNum: null,
     remark: '',
+    monitorType: '1',
   };
 }
 function addControlRow() {
   controlList.value.push(getEmptyControlRow());
 }
-function delControlRow(idx) {
+async function delControlRow(idx, record) {
   if (controlList.value.length <= 1) return message.warning('至少保留一行');
   controlList.value.splice(idx, 1);
+  console.log(record, '111111');
+  // await workFaceWarningDelete({ id: record.id });
 }
 
-// ==========================================
-//  主表单 & 弹窗
-// ==========================================
 const [registerForm, { resetFields, setFieldsValue, validate, getFieldsValue }] = useForm({
   schemas: props.formSchemas,
   showActionButtonGroup: false,
@@ -103,41 +114,49 @@ const [registerForm, { resetFields, setFieldsValue, validate, getFieldsValue }]
 
 const [register, { setModalProps, closeModal }] = useModalInner(async (data) => {
   isUpdate.value = unref(data.isUpdate);
-  title.value = data.isUpdate ? '编辑预警' : '新增预警';
+  title.value = data.isUpdate ? '编辑' : '新增';
   await resetFields();
-
+  warnFormRefs.value = [];
+  controlFormRefs.value = [];
   if (data.isUpdate && data.record) {
     await setFieldsValue(data.record);
-    // 编辑回显 两组数据
-    warnList.value = data.record.warnList || [getEmptyWarnRow()];
-    controlList.value = data.record.controlList || [getEmptyControlRow()];
+    const allAlarms = data.record.alarmList || [];
+    // 预警设备 monitorType 2
+    const warnings = allAlarms.filter((item: any) => String(item.monitorType) === '1');
+    // 控制设备 monitorType 1
+    const controls = allAlarms.filter((item: any) => String(item.monitorType) === '2');
+    warnList.value = warnings.length ? warnings : [getEmptyWarnRow()];
+    controlList.value = controls.length ? controls : [getEmptyControlRow()];
   } else {
-    // 新增重置
     warnList.value = [getEmptyWarnRow()];
     controlList.value = [getEmptyControlRow()];
   }
 });
-
 async function onSubmit() {
   try {
     const baseForm = await getFieldsValue();
     await validate();
     setModalProps({ confirmLoading: true });
-
+    const warnValues = await Promise.all(unref(warnFormRefs).map((formRef) => formRef.getFieldsValue()));
+    const controlValues = await Promise.all(unref(controlFormRefs).map((formRef) => formRef.getFieldsValue()));
     const submitData = {
       ...baseForm,
-      warnList: warnList.value, // 预警配置数组
-      controlList: controlList.value, // 控制配置数组
+      // 合并数据
+      alarmList: [...warnValues, ...controlValues],
     };
-
-    emit(isUpdate.value ? 'update' : 'add', isUpdate.value ? 'update' : 'add', submitData);
+    if (!isUpdate.value) {
+      emit('add', 'add', submitData);
+    } else {
+      emit('update', 'update', submitData);
+    }
     closeModal();
+  } catch (error) {
+    console.error('表单验证失败:', error);
   } finally {
     setModalProps({ confirmLoading: false });
   }
 }
 </script>
-
 <style lang="less" scoped>
 @import '/@/design/theme.less';
 @import '/@/design/theme.less';

+ 173 - 173
src/views/vent/deviceManager/comment/warningTabel/index3.vue

@@ -25,207 +25,207 @@
 </template>
 
 <script lang="ts" setup>
-  import { ref, onMounted } from 'vue';
-  import { rowOrColSpanMap, MonitorColumns, monitorWarningFormSchemas } from './warning.data';
-  import { warningLogList, workFaceWarningList, workFaceWarningAdd, workFaceWarningEdit, workFaceWarningDelete } from './warning.api';
-  import BaseModal from './BaseModal.vue';
-  import { useModal } from '/@/components/Modal';
-  import { message } from 'ant-design-vue';
-
-  const emit = defineEmits(['register']);
-
-  const props = defineProps({
-    deviceId: { type: String },
-  });
-
-  const show = ref(false);
-  const formSchemas = monitorWarningFormSchemas({ id: props.deviceId });
-  const activeID = ref('');
-  const warningList = ref<{ id: string; alarmName: string }[]>([]);
-  const dataSource = ref<any[]>([]);
-
-  function selectWarning(id) {
-    activeID.value = id;
-    // 查询该条目的下预警设备列表
-    getDataSource();
-  }
-
-  async function getWarningList() {
-    const result = await warningLogList({ sysId: props.deviceId, pageSize: 100000 }); //id: props.deviceId
-    warningList.value = result.records;
-    activeID.value = warningList.value[0]['id'];
-  }
-
-  async function getDataSource() {
-    show.value = false;
-    rowOrColSpanMap.clear();
-    const result = await workFaceWarningList({ sysId: props.deviceId, monitorType: 2, alarmId: activeID.value, pageSize: 100000 });
-    let flag = 0;
-    let groupNum = 0;
-    let resultDataSource: any[] = [];
-    const value1 = [
-      {
-        code: 'key',
-        rowSpan: 0,
-        colSpan: 1,
-      },
-      {
-        code: 'alarmName',
-        rowSpan: 0,
-        colSpan: 1,
-      },
-      {
-        code: 'operation1',
-        rowSpan: 0,
-        colSpan: 1,
-      },
-    ];
-    // 根据relId 排序
-
-    for (let i = 0; i < result.records.length; i++) {
-      const item = result.records[i];
-      if (!item.relId) {
-        groupNum++;
-        resultDataSource.push(item);
-        let itemChildArr: any[] = [];
-        for (let j = 0; j < result.records.length; j++) {
-          const itemChild = result.records[j];
-          if (itemChild.relId == item.id) {
-            resultDataSource.push(itemChild);
-            itemChildArr.push(itemChild);
-          }
-        }
-        const value0 = [
-          {
-            code: 'key',
-            rowSpan: itemChildArr.length + 1,
-            colSpan: 1,
-          },
-          {
-            code: 'alarmName',
-            rowSpan: itemChildArr.length + 1,
-            colSpan: 1,
-          },
-          {
-            code: 'operation1',
-            rowSpan: itemChildArr.length + 1,
-            colSpan: 1,
-          },
-        ];
-        rowOrColSpanMap.set(item['id'], value0);
-        item['key'] = `${groupNum}`;
-        for (let m = 0; m < itemChildArr.length; m++) {
-          rowOrColSpanMap.set(itemChildArr[m]['id'], value1);
+import { ref, onMounted } from 'vue';
+import { rowOrColSpanMap, MonitorColumns, monitorWarningFormSchemas } from './warning.data';
+import { warningLogList, workFaceWarningList, workFaceWarningAdd, workFaceWarningEdit, workFaceWarningDelete } from './warning.api';
+import BaseModal from './BaseModal.vue';
+import { useModal } from '/@/components/Modal';
+import { message } from 'ant-design-vue';
+
+const emit = defineEmits(['register']);
+
+const props = defineProps({
+  deviceId: { type: String },
+});
+
+const show = ref(false);
+const formSchemas = monitorWarningFormSchemas({ id: props.deviceId });
+const activeID = ref('');
+const warningList = ref<{ id: string; alarmName: string }[]>([]);
+const dataSource = ref<any[]>([]);
+
+function selectWarning(id) {
+  activeID.value = id;
+  // 查询该条目的下预警设备列表
+  getDataSource();
+}
+
+async function getWarningList() {
+  const result = await warningLogList({ sysId: props.deviceId, pageSize: 100000 }); //id: props.deviceId
+  warningList.value = result.records;
+  activeID.value = warningList.value[0]['id'];
+}
+
+async function getDataSource() {
+  show.value = false;
+  rowOrColSpanMap.clear();
+  const result = await workFaceWarningList({ sysId: props.deviceId, monitorType: 2, alarmId: activeID.value, pageSize: 100000 });
+  let flag = 0;
+  let groupNum = 0;
+  let resultDataSource: any[] = [];
+  const value1 = [
+    {
+      code: 'key',
+      rowSpan: 0,
+      colSpan: 1,
+    },
+    {
+      code: 'alarmName',
+      rowSpan: 0,
+      colSpan: 1,
+    },
+    {
+      code: 'operation1',
+      rowSpan: 0,
+      colSpan: 1,
+    },
+  ];
+  // 根据relId 排序
+
+  for (let i = 0; i < result.records.length; i++) {
+    const item = result.records[i];
+    if (!item.relId) {
+      groupNum++;
+      resultDataSource.push(item);
+      let itemChildArr: any[] = [];
+      for (let j = 0; j < result.records.length; j++) {
+        const itemChild = result.records[j];
+        if (itemChild.relId == item.id) {
+          resultDataSource.push(itemChild);
+          itemChildArr.push(itemChild);
         }
       }
+      const value0 = [
+        {
+          code: 'key',
+          rowSpan: itemChildArr.length + 1,
+          colSpan: 1,
+        },
+        {
+          code: 'alarmName',
+          rowSpan: itemChildArr.length + 1,
+          colSpan: 1,
+        },
+        {
+          code: 'operation1',
+          rowSpan: itemChildArr.length + 1,
+          colSpan: 1,
+        },
+      ];
+      rowOrColSpanMap.set(item['id'], value0);
+      item['key'] = `${groupNum}`;
+      for (let m = 0; m < itemChildArr.length; m++) {
+        rowOrColSpanMap.set(itemChildArr[m]['id'], value1);
+      }
     }
-    show.value = true;
-    dataSource.value = resultDataSource;
   }
+  show.value = true;
+  dataSource.value = resultDataSource;
+}
 
-  async function handleDelete(record) {
-    await workFaceWarningDelete({ id: record.id });
-    getDataSource();
-  }
+async function handleDelete(record) {
+  await workFaceWarningDelete({ id: record.id });
+  getDataSource();
+}
 
-  const [register, { openModal, closeModal }] = useModal();
-
-  function handleOpen(flag?, record?) {
-    if (record) {
-      if (flag == 'update') {
-        openModal(true, {
-          isUpdate: true,
-          record,
-        });
-      } else {
-        if (!activeID.value) {
-          message.warning('请先选择预警条目!');
-          return;
-        }
-        // 新增并关系数据
-        openModal(true, {
-          isUpdate: false,
-          record,
-        });
-      }
+const [register, { openModal, closeModal }] = useModal();
+
+function handleOpen(flag?, record?) {
+  if (record) {
+    if (flag == 'update') {
+      openModal(true, {
+        isUpdate: true,
+        record,
+      });
     } else {
       if (!activeID.value) {
         message.warning('请先选择预警条目!');
         return;
       }
+      // 新增并关系数据
       openModal(true, {
         isUpdate: false,
+        record,
       });
     }
+  } else {
+    if (!activeID.value) {
+      message.warning('请先选择预警条目!');
+      return;
+    }
+    openModal(true, {
+      isUpdate: false,
+    });
   }
+}
 
-  async function onSubmit(flag, values) {
-    if (activeID.value) {
-      // 提交数据弹窗
-      if (flag == 'update') {
-        await workFaceWarningEdit({ ...values });
-      } else {
-        await workFaceWarningAdd({ ...values, monitorType: 2, sysId: props.deviceId, alarmId: activeID.value });
-      }
-      getDataSource();
+async function onSubmit(flag, values) {
+  if (activeID.value) {
+    // 提交数据弹窗
+    if (flag == 'update') {
+      await workFaceWarningEdit({ ...values });
+    } else {
+      await workFaceWarningAdd({ ...values, monitorType: 2, sysId: props.deviceId, alarmId: activeID.value });
     }
-    closeModal();
+    getDataSource();
   }
+  closeModal();
+}
 
-  onMounted(async () => {
-    await getWarningList();
-    await getDataSource();
-  });
+onMounted(async () => {
+  await getWarningList();
+  await getDataSource();
+});
 </script>
 
 <style lang="less" scoped>
-  @ventSpace: zxm;
-
-  .warning-device-box {
-    width: 100%;
-    height: 600px;
+@ventSpace: zxm;
+
+.warning-device-box {
+  width: 100%;
+  height: 600px;
+  overflow-y: auto;
+  display: flex;
+  .warning-box {
+    width: 200px;
+    height: 100%;
     overflow-y: auto;
-    display: flex;
-    .warning-box {
-      width: 200px;
-      height: 100%;
-      overflow-y: auto;
-      background: #ffffff11;
-      padding: 5px;
-      border-radius: 5px;
-
-      .link-item {
-        position: relative;
-        cursor: pointer;
-        line-height: 30px;
-        padding-left: 30px;
-        color: #fff;
-        span:hover {
-          color: #89ffff;
-        }
-        &::after {
-          content: '';
-          position: absolute;
-          display: block;
-          width: 8px;
-          height: 8px;
-          top: 12px;
-          left: 10px;
-          transform: rotateZ(45deg) skew(10deg, 10deg);
-          background: #45d3fd;
-        }
+    background: #ffffff11;
+    padding: 5px;
+    border-radius: 5px;
+
+    .link-item {
+      position: relative;
+      cursor: pointer;
+      line-height: 30px;
+      padding-left: 30px;
+      color: #fff;
+      span:hover {
+        color: #89ffff;
       }
-      .active-device-title {
-        color: aqua;
+      &::after {
+        content: '';
+        position: absolute;
+        display: block;
+        width: 8px;
+        height: 8px;
+        top: 12px;
+        left: 10px;
+        transform: rotateZ(45deg) skew(10deg, 10deg);
+        background: #45d3fd;
       }
     }
-    .device-box {
-      flex: 1;
-      margin-left: 10px;
+    .active-device-title {
+      color: aqua;
     }
+  }
+  .device-box {
+    flex: 1;
+    margin-left: 10px;
+  }
 
-    .action-link {
-      color: #00e7ff;
-    }
+  .action-link {
+    color: #00e7ff;
   }
+}
 </style>

+ 1 - 0
src/views/vent/deviceManager/comment/warningTabel/indexLeather.vue

@@ -82,6 +82,7 @@ async function handleDelete(record) {
 }
 
 async function onSubmit(flag, values) {
+  console.log(values, '1111');
   // 提交数据弹窗
   if (flag == 'update') {
     await warningLogEdit(values);

+ 18 - 28
src/views/vent/deviceManager/comment/warningTabel/warning.data.ts

@@ -324,18 +324,6 @@ export const workFaceWarningFormSchemasLeather: FormSchema[] = [
     componentProps: { dictCode: 'leveltype', stringToNumber: true },
     required: true,
   },
-  {
-    label: '配置预警设备',
-    field: 'warnDevices',
-    component: 'Input',
-    slot: 'monitor',
-  },
-  {
-    label: '配置控制设备',
-    field: 'controlDevices',
-    component: 'Select',
-    slot: 'controlDevices',
-  },
   {
     label: '分区数',
     field: 'partNum',
@@ -358,29 +346,29 @@ export const deviceFormColumns: FormSchema[] = [
   {
     label: '设备类型',
     field: 'deviceType',
-    component: 'Select',
-  },
-  {
-    label: '点位',
-    field: 'monitorId',
-    component: 'Select',
-    slot: 'monitor',
-    required: true,
+    component: 'MTreeSelect',
+    componentProps: {
+      isSearch: false,
+    },
+    colProps: { span: 12 },
   },
   {
     label: '报警上限值',
     field: 'fmax',
     component: 'InputNumber',
+    colProps: { span: 12 },
   },
   {
     label: '报警下限值',
     field: 'fmin',
     component: 'InputNumber',
+    colProps: { span: 12 },
   },
   {
     label: '报警持续时间(s)',
     field: 'cxTime',
     component: 'InputNumber',
+    colProps: { span: 12 },
   },
   {
     label: '数据趋势',
@@ -390,40 +378,42 @@ export const deviceFormColumns: FormSchema[] = [
       dictCode: 'dataTrend',
       placeholder: '请选择数据趋势',
     },
+    colProps: { span: 12 },
   },
   {
     label: '数据趋势持续时间(h)',
     field: 'trendCxTime',
     component: 'InputNumber',
+    colProps: { span: 12 },
   },
 ];
 export const deviceControlColumns: FormSchema[] = [
   {
     label: '设备类型',
     field: 'deviceType',
-    component: 'Select',
-  },
-  {
-    label: '点位',
-    field: 'monitorId',
-    component: 'Select',
-    slot: 'monitor',
-    required: true,
+    component: 'MTreeSelect',
+    componentProps: {
+      isSearch: false,
+    },
+    colProps: { span: 12 },
   },
   {
     label: '值',
     field: 'value',
     component: 'Input',
+    colProps: { span: 12 },
   },
   {
     label: '执行顺序',
     field: 'orderNum',
     component: 'InputNumber',
+    colProps: { span: 12 },
   },
   {
     label: '操作描述',
     field: 'remark',
     component: 'Input',
+    colProps: { span: 12 },
   },
 ];
 export const manageWarningPointColumns: BasicColumn[] = [

+ 354 - 321
src/views/vent/home/configurable/belt/belt-new.vue

@@ -2,8 +2,8 @@
 <template>
   <div class="company-home">
     <!-- 顶部标题栏 + 下拉选择 -->
-    <customHeader> 皮带巷预警管控详情 </customHeader>
-    <div class="modal-box" id="modalBox">
+    <customHeader> 皮带巷智能管控 </customHeader>
+    <div class="modal-box" id="modalBox" v-if="pageType !== 'history'">
       <Three3D ref="three3D" :modalName="'pidai'" class="modal-3d" @success="initModalAnimate" />
       <div class="modal-css3d" id="css3dContainer"> </div>
     </div>
@@ -52,384 +52,417 @@
           :visible="true"
         />
       </template>
+      <template v-if="pageType == 'history'">
+        <History />
+      </template>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-  import { onMounted, ref, watch, computed } 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 Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
-  import BeltNav from './components/BeltNav.vue';
-  import { useRouter, useRoute } from 'vue-router';
-  import { getSystem } from './configurable.api';
-  import { modalAnimate } from './threejs/belt.threejs';
-
-  // 初始化配置
-  const { configs, fetchConfigs } = useInitConfigs();
-  const { updateEnhancedConfigs, updateData, data } = useInitPage('皮带巷智能管控');
-  // const pageType = computed(() => {
-  //   const currentType = route.params.type as string;
-  //   return currentType;
-  // });
-  const pageType = ref('fireMonitor');
-
-  // 下拉框选项
-  const beltOptions = [
-    { id: '1', beltName: '主运巷皮带 1' },
-    { id: '2', beltName: '主运巷皮带 2' },
-  ];
+import { onMounted, ref, watch, computed } 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 Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
+import BeltNav from './components/BeltNav.vue';
+import { useRouter, useRoute } from 'vue-router';
+import { getSystem, getDevice } from './configurable.api';
+import { modalAnimate } from './threejs/belt.threejs';
+import History from './components/detail/history.vue';
+// 初始化配置
+const { configs, fetchConfigs } = useInitConfigs();
+const { updateEnhancedConfigs, updateData, data } = useInitPage('皮带巷三级防灭火系统');
+// const pageType = computed(() => {
+//   const currentType = route.params.type as string;
+//   return currentType;
+// });
+const pageType = ref('');
+const route = useRoute();
+// 下拉框选项
+const beltOptions = [
+  { id: '1', beltName: '主运巷皮带 1' },
+  { id: '2', beltName: '主运巷皮带 2' },
+];
 
-  const selectedBeltId = ref('1');
+const selectedBeltId = ref('1');
 
-  // 模拟数据
-  const readData = {
-    fmhjcInfo: [
-      {
-        beltName: '主运巷皮带1',
-        wz: { strtype: 'wz', avg: '111', max: '222', min: '333', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
-        hcl: { strtype: 'HCl', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
-        gx: { strtype: 'gx', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
-        co: { strtype: 'CO', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: true, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
-        wd: { strtype: 'wd', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
-      },
-    ],
-    pdhzfxInfo: [
-      {
-        beltName: '主运巷皮带1',
-        warningLevel: '一般风险',
-        sysList: [
-          {
-            time: '2026-03-21 13:23:34',
-            area: '3#皮带区域',
-            type: 'CO浓度异常',
-            status: '三级预警',
-            advice: '立即检查该区域设备,启动应急预案',
-            action: '启动喷淋',
-          },
-          {
-            time: '2026-03-21 13:23:34',
-            area: '3#皮带区域',
-            type: 'CO浓度异常',
-            status: '三级预警',
-            advice: '立即检查该区域设备,启动应急预案',
-            action: '启动喷淋',
-          },
-          {
-            time: '2026-03-21 13:23:34',
-            area: '3#皮带区域',
-            type: 'CO浓度异常',
-            status: '三级预警',
-            advice: '立即检查该区域设备,启动应急预案',
-            action: '启动喷淋',
-          },
-          {
-            time: '2026-03-21 13:23:34',
-            area: '3#皮带区域',
-            type: 'CO浓度异常',
-            status: '三级预警',
-            advice: '立即检查该区域设备,启动应急预案',
-            action: '启动喷淋',
-          },
-        ],
-      },
-    ],
-    sensorAnalysis: {
-      hy: { name: '火焰传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
-      wd: { name: '温度传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
-      yw: { name: '烟雾传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
+// 模拟数据
+const readData = {
+  fmhjcInfo: [
+    {
+      beltName: '主运巷皮带1',
+      wz: { strtype: 'wz', avg: '111', max: '222', min: '333', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
+      hcl: { strtype: 'HCl', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
+      gx: { strtype: 'gx', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
+      co: { strtype: 'CO', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: true, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
+      wd: { strtype: 'wd', avg: 'XXX', max: 'XXX', min: 'XXX', alarm: false, pos: 'AAAA', maxTime: '2013-05-24 15:52:42' },
     },
-    vehicleCOAnalysis: {
-      isRisk: true,
-      activityList: [
+  ],
+  pdhzfxInfo: [
+    {
+      beltName: '主运巷皮带1',
+      warningLevel: '一般风险',
+      sysList: [
         {
-          pos: '1#皮带区域',
-          vehicle: '车辆23425',
-          status: '0',
-          // vehicle2: '车辆53456',
-          // vehicle3: '未通过车辆',
-          // coReason1: 'CO浓度异常升高,已确认为车辆干扰',
-          // coReason3: 'CO浓度异常升高,已确认非车辆干扰',
-          // possibleCause: '皮带摩擦过热或电器设备故障',
-          // recommendation: '立即检查3#皮带区域设备',
+          time: '2026-03-21 13:23:34',
+          area: '3#皮带区域',
+          type: 'CO浓度异常',
+          status: '三级预警',
+          advice: '立即检查该区域设备,启动应急预案',
+          action: '启动喷淋',
         },
         {
-          pos: '2#皮带区域',
-          vehicle: '车辆53456',
-          status: '1',
+          time: '2026-03-21 13:23:34',
+          area: '3#皮带区域',
+          type: 'CO浓度异常',
+          status: '三级预警',
+          advice: '立即检查该区域设备,启动应急预案',
+          action: '启动喷淋',
         },
         {
-          pos: '3#皮带区域',
-          vehicle: '未通过车辆',
-          status: '0',
+          time: '2026-03-21 13:23:34',
+          area: '3#皮带区域',
+          type: 'CO浓度异常',
+          status: '三级预警',
+          advice: '立即检查该区域设备,启动应急预案',
+          action: '启动喷淋',
         },
-      ],
-      analysisList: [
         {
-          pos: '1#皮带区域',
-          analysisText: 'CO浓度异常升高,已确认为车辆干扰',
-        },
-        {
-          pos: '1#皮带区域',
-          analysisText: 'CO浓度异常升高,已确认为车辆干扰',
+          time: '2026-03-21 13:23:34',
+          area: '3#皮带区域',
+          type: 'CO浓度异常',
+          status: '三级预警',
+          advice: '立即检查该区域设备,启动应急预案',
+          action: '启动喷淋',
         },
       ],
-      possibleCause: '皮带摩擦过热或电器设备故障',
-      recommendation: '立即检查3#皮带区域设备',
     },
-    sprayData: [
+  ],
+  sensorAnalysis: {
+    hy: { name: '火焰传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
+    wd: { name: '温度传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
+    yw: { name: '烟雾传感器', alarm: false, maxTime: '2013-05-24 15:52:42', pos: '' },
+  },
+  vehicleCOAnalysis: {
+    isRisk: true,
+    activityList: [
       {
-        beltArea: '1#皮带区域',
-        devicePosition: '1#皮带-50m处',
-        netStatus: '0', // 网络状态:0=断开,1=连接
-        runStatus: '1', // 运行状态:0=异常,1=正常
-        waterVolume: 86,
-        waterPressure: 1.4,
+        pos: '1#皮带区域',
+        vehicle: '车辆23425',
+        status: '0',
+        // vehicle2: '车辆53456',
+        // vehicle3: '未通过车辆',
+        // coReason1: 'CO浓度异常升高,已确认为车辆干扰',
+        // coReason3: 'CO浓度异常升高,已确认非车辆干扰',
+        // possibleCause: '皮带摩擦过热或电器设备故障',
+        // recommendation: '立即检查3#皮带区域设备',
       },
       {
-        beltArea: '2#皮带区域',
-        devicePosition: '2#皮带-120m处',
-        netStatus: '1',
-        runStatus: '1',
-        waterVolume: 72,
-        waterPressure: 0.8,
+        pos: '2#皮带区域',
+        vehicle: '车辆53456',
+        status: '1',
       },
       {
-        beltArea: '3#皮带区域',
-        devicePosition: '3#皮带-200m处',
-        netStatus: '1',
-        runStatus: '0',
-        waterVolume: 45,
-        waterPressure: 1.6,
+        pos: '3#皮带区域',
+        vehicle: '未通过车辆',
+        status: '0',
       },
     ],
-  };
+    analysisList: [
+      {
+        pos: '1#皮带区域',
+        analysisText: 'CO浓度异常升高,已确认为车辆干扰',
+      },
+      {
+        pos: '1#皮带区域',
+        analysisText: 'CO浓度异常升高,已确认为车辆干扰',
+      },
+    ],
+    possibleCause: '皮带摩擦过热或电器设备故障',
+    recommendation: '立即检查3#皮带区域设备',
+  },
+  sprayData: [
+    {
+      beltArea: '1#皮带区域',
+      devicePosition: '1#皮带-50m处',
+      netStatus: '0', // 网络状态:0=断开,1=连接
+      runStatus: '1', // 运行状态:0=异常,1=正常
+      waterVolume: 86,
+      waterPressure: 1.4,
+    },
+    {
+      beltArea: '2#皮带区域',
+      devicePosition: '2#皮带-120m处',
+      netStatus: '1',
+      runStatus: '1',
+      waterVolume: 72,
+      waterPressure: 0.8,
+    },
+    {
+      beltArea: '3#皮带区域',
+      devicePosition: '3#皮带-200m处',
+      netStatus: '1',
+      runStatus: '0',
+      waterVolume: 45,
+      waterPressure: 1.6,
+    },
+  ],
+};
 
-  // 下拉框切换处理
-  function handleBeltChange(id: string) {
-    selectedBeltId.value = id;
-    refresh();
-  }
+// 下拉框切换处理
+function handleBeltChange(id: string) {
+  selectedBeltId.value = id;
+  refresh();
+}
 
-  // 风险等级样式映射
-  function getLevelClass(level: string) {
-    switch (level) {
-      case '重大风险':
-        return 'level-critical';
-      case '高风险':
-        return 'level-high';
-      case '一般风险':
-        return 'level-normal';
-      default:
-        return '';
-    }
+// 风险等级样式映射
+function getLevelClass(level: string) {
+  switch (level) {
+    case '重大风险':
+      return 'level-critical';
+    case '高风险':
+      return 'level-high';
+    case '一般风险':
+      return 'level-normal';
+    default:
+      return '';
   }
+}
+// 刷新数据
+function refresh() {
+  fetchConfigs('belt').then(() => {
+    if (pageType.value == 'fireMonitor') {
+      configs.value = testBeltNew;
+      Promise.resolve(readData).then(updateData);
+    } else if (pageType.value == 'emergencyControl') {
+      const params = {
+        devicetype: 'sys',
+        systemID: '1637983899775242242',
+        type: 'ventS',
+      };
+      Promise.resolve(getSystem(params)).then(updateData);
+      configs.value = testYjkf;
+    } else if (pageType.value == 'sprayControl') {
+      configs.value = testSpary;
+      const params = {
+        devicetype: 'sys',
+        systemID: '2028657172566073346',
+      };
+      Promise.resolve(getDevice(params)).then((originalData) => {
+        updateData(originalData);
+        const sprayData: any[] = [];
+        if (data.value?.msgTxt) {
+          data.value.msgTxt.forEach((item) => {
+            const hasSprayAuto = item.type && item.type.toLowerCase().includes('spray_auto');
+            if (hasSprayAuto) {
+              sprayData.push({
+                ...item,
+                ...item.readData,
+              });
+            }
+          });
+        }
+        data.value.sprayData = sprayData;
+        updateData(data.value);
+      });
+    } else {
+      configs.value = testBeltNew;
+    }
+    updateEnhancedConfigs(configs.value);
+  });
+}
 
-  // 刷新数据
-  function refresh() {
-    fetchConfigs('belt').then(() => {
-      if (pageType.value == 'fireMonitor') {
-        configs.value = testBeltNew;
-        Promise.resolve(readData).then(updateData);
-      } else if (pageType.value == 'emergencyControl') {
-        const params = {
-          devicetype: 'sys',
-          systemID: '1637983899775242242',
-          type: 'ventS',
-        };
-        Promise.resolve(getSystem(params)).then(updateData);
-        configs.value = testYjkf;
-      } else if (pageType.value == 'sprayControl') {
-        configs.value = testSpary;
-        Promise.resolve(readData).then(updateData);
-      } else {
-        configs.value = testBeltNew;
-      }
-      updateEnhancedConfigs(configs.value);
-    });
-  }
+// // 定时刷新
+// function initInterval() {
+//   setInterval(() => {
+//     refresh();
+//   }, 60000);
+// }
 
-  // // 定时刷新
-  // function initInterval() {
-  //   setInterval(() => {
-  //     refresh();
-  //   }, 60000);
-  // }
+async function changePage(pageTypeStr: string) {
+  const finalPageType = pageTypeStr || (route.query.pageType as string) || '';
+  pageType.value = finalPageType;
+  await refresh();
+}
 
-  function changePage(pageTypeStr: string) {
-    pageType.value = pageTypeStr;
-    refresh();
-  }
+// watch(
+//   // 监听动态路由参数 :type
+//   () => route.params.type,
+//   (newVal) => {
+//     if (newVal) {
+//       console.log('切换页面类型:', newVal);
+//       refresh(); // 切换路由自动刷新
+//     }
+//   }
+// );
 
-  // watch(
-  //   // 监听动态路由参数 :type
-  //   () => route.params.type,
-  //   (newVal) => {
-  //     if (newVal) {
-  //       console.log('切换页面类型:', newVal);
-  //       refresh(); // 切换路由自动刷新
-  //     }
-  //   }
-  // );
+function initModalAnimate(modal) {
+  console.log('初始化模型', modal);
+  modal.isRender = true;
 
-  function initModalAnimate(modal) {
-    console.log('初始化模型', modal);
-    modal.isRender = true;
+  modalAnimate(modal);
+}
 
-    modalAnimate(modal);
-  }
+watch(
+  () => route.query.pageType,
+  (newQueryType) => {
+    if (newQueryType) {
+      changePage(newQueryType as string);
+    }
+  },
+  { immediate: true } // 初始化立刻执行
+);
 
-  onMounted(() => {
-    refresh();
-    // initInterval();
-  });
+onMounted(() => {
+  refresh();
+  // initInterval();
+});
 </script>
 
 <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%;
+    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: 100%;
-    color: @white;
+    height: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
     position: relative;
-    font-family: 'Microsoft YaHei', sans-serif;
-    .top-bg {
+    overflow: hidden;
+    margin-top: 50px;
+    .box-container {
+      position: relative;
       width: 100%;
-      height: 56px;
-      position: absolute;
-      margin-top: 10px;
-      z-index: 1;
-    }
-    .header-container {
-      position: absolute;
-      top: 20px;
-      left: 20px;
-      z-index: 10;
+      height: 100%;
     }
+  }
 
-    .border {
-      width: 100%;
-      height: 94%;
-      background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
-      background-size: 100% 100%;
-      position: relative;
-      overflow: hidden;
+  // 中间预警结果区
+  .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;
 
-      .box-container {
-        position: relative;
-        width: 100%;
-        height: 100%;
-      }
+    .warning-header {
+      font-size: 18px;
+      font-weight: bold;
+      margin-bottom: 10px;
+      color: #ff6b6b;
     }
 
-    // 中间预警结果区
-    .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-list {
+      width: 100%;
+      height: 100%;
+      overflow-y: auto;
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+    }
 
-      .warning-header {
-        font-size: 18px;
-        font-weight: bold;
-        margin-bottom: 10px;
-        color: #ff6b6b;
-      }
+    .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-list {
-        width: 100%;
-        height: 100%;
-        overflow-y: auto;
-        display: flex;
-        flex-direction: column;
-        gap: 8px;
+      .warning-time {
+        font-size: 14px;
+        color: #ccc;
       }
 
-      .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;
+      .warning-level {
+        font-size: 14px;
+        font-weight: bold;
+        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>

+ 317 - 284
src/views/vent/home/configurable/belt/belt.vue

@@ -24,296 +24,329 @@
   </div>
 </template>
 <script setup lang="ts">
-  import { onMounted, ref } 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 { BDFireMock } from './mock';
-  const { configs, fetchConfigs } = useInitConfigs();
-  const { updateEnhancedConfigs, updateData, data } = useInitPage('皮带巷三级防灭火系统');
-  const readData = {
-    pdhzfxInfo: [
-      {
-        beltName: '测试1',
-        sysList: [
-          {
-            beltName: '东翼胶带运输大巷皮带',
-            warnlevel: '重大风险',
-          },
-          {
-            beltName: '1102主运顺槽皮带',
-            warnlevel: '报警',
-          },
-          {
-            beltName: '1101主运顺槽皮带',
-            warnlevel: '低分险',
-          },
-          {
-            beltName: '东翼胶带运输大巷皮带',
-            warnlevel: '一般风险',
-          },
-          {
-            beltName: '东翼胶带运输大巷皮带',
-            warnlevel: '较大风险',
-          },
-        ],
-      },
-    ],
-    plmhInfo: [
-      {
-        beltName: '测试1',
-        sysList: [
-          {
-            netstatus: '1',
-            yxzt: '1',
-            plsy: '1#区域 1.4MPa',
-            kzms: '手动',
-          },
-        ],
-      },
-      {
-        beltName: '测试2',
-        sysList: [
-          {
-            netstatus: '1',
-            yxzt: '1',
-            plqy: '2#区域',
-            plsy: '1.6MPa',
-            kzms: '自动',
-          },
-        ],
-      },
-    ],
-    fmhjcInfo: [
-      {
-        beltName: '测试1',
-        sysList: [
-          {
-            warnLevel: '一般风险',
-            deviceType: '微震测声传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '光纤测温传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'HCI传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '烟雾传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'CO传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '火焰传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '温度传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '多参数传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'AI视频火焰分析',
-          },
-        ],
-      },
-      {
-        beltName: '测试2',
-        sysList: [
-          {
-            warnLevel: '一般风险',
-            deviceType: '微震测声传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '光纤测温传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'HCI传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '烟雾传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'CO传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '火焰传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '温度传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: '多参数传感器',
-          },
-          {
-            warnLevel: '一般风险',
-            deviceType: 'AI视频火焰分析',
-          },
-        ],
-      },
-    ],
-    yjkfArray: [
-      {
-        aqjkData: [
-          {
-            deviceName: '风门1',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门2',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门3',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门4',
-            frontDoorStatus: '开启',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门5',
-            frontDoorStatus: '开启',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门6',
-            frontDoorStatus: '开启',
-            backDoorStatus: '开启',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门7',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '关闭',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门8',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '关闭',
-            netStatus: '在线',
-          },
-          {
-            deviceName: '风门9',
-            frontDoorStatus: '关闭',
-            backDoorStatus: '关闭',
-            netStatus: '在线',
-          },
-        ],
-      },
-    ],
-    aqjkData: [
-      {
-        deviceName: '风门1',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门2',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门3',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门4',
-        frontDoorStatus: '开启',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门5',
-        frontDoorStatus: '开启',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门6',
-        frontDoorStatus: '开启',
-        backDoorStatus: '开启',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门7',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '关闭',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门8',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '关闭',
-        netStatus: '在线',
-      },
-      {
-        deviceName: '风门9',
-        frontDoorStatus: '关闭',
-        backDoorStatus: '关闭',
-        netStatus: '在线',
-      },
-    ],
-  };
-  // const readData = ref({});
-  function refresh() {
-    fetchConfigs('belt').then(() => {
-      configs.value = testBeltLaneFire;
-      Promise.resolve(readData).then(updateData);
-      // updateEnhancedConfigs(configs.value);
-      // getDataSource();
-    });
-  }
+import { onMounted, ref } 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 { BDFireMock } from './mock';
+import { getDevice } from './configurable.api';
+const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
+const { updateEnhancedConfigs, updateData, data } = useInitPage('皮带巷三级防灭火系统');
+const readData = {
+  pdhzfxInfo: [
+    {
+      beltName: '测试1',
+      sysList: [
+        {
+          beltName: '东翼胶带运输大巷皮带',
+          warnlevel: '重大风险',
+        },
+        {
+          beltName: '1102主运顺槽皮带',
+          warnlevel: '报警',
+        },
+        {
+          beltName: '1101主运顺槽皮带',
+          warnlevel: '低分险',
+        },
+        {
+          beltName: '东翼胶带运输大巷皮带',
+          warnlevel: '一般风险',
+        },
+        {
+          beltName: '东翼胶带运输大巷皮带',
+          warnlevel: '较大风险',
+        },
+      ],
+    },
+  ],
+  plmhInfo: [
+    {
+      beltName: '测试1',
+      sysList: [
+        {
+          netstatus: '1',
+          yxzt: '1',
+          plsy: '1#区域 1.4MPa',
+          kzms: '手动',
+        },
+      ],
+    },
+    {
+      beltName: '测试2',
+      sysList: [
+        {
+          netstatus: '1',
+          yxzt: '1',
+          plqy: '2#区域',
+          plsy: '1.6MPa',
+          kzms: '自动',
+        },
+      ],
+    },
+  ],
+  fmhjcInfo: [
+    {
+      beltName: '测试1',
+      sysList: [
+        {
+          warnLevel: '一般风险',
+          deviceType: '微震测声传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '光纤测温传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'HCI传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '烟雾传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'CO传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '火焰传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '温度传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '多参数传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'AI视频火焰分析',
+        },
+      ],
+    },
+    {
+      beltName: '测试2',
+      sysList: [
+        {
+          warnLevel: '一般风险',
+          deviceType: '微震测声传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '光纤测温传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'HCI传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '烟雾传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'CO传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '火焰传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '温度传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: '多参数传感器',
+        },
+        {
+          warnLevel: '一般风险',
+          deviceType: 'AI视频火焰分析',
+        },
+      ],
+    },
+  ],
+  yjkfArray: [
+    {
+      aqjkData: [
+        {
+          deviceName: '风门1',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门2',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门3',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门4',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门5',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门6',
+          frontDoorStatus: '开启',
+          backDoorStatus: '开启',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门7',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '关闭',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门8',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '关闭',
+          netStatus: '在线',
+        },
+        {
+          deviceName: '风门9',
+          frontDoorStatus: '关闭',
+          backDoorStatus: '关闭',
+          netStatus: '在线',
+        },
+      ],
+    },
+  ],
+  aqjkData: [
+    {
+      deviceName: '风门1',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门2',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门3',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门4',
+      frontDoorStatus: '开启',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门5',
+      frontDoorStatus: '开启',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门6',
+      frontDoorStatus: '开启',
+      backDoorStatus: '开启',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门7',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '关闭',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门8',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '关闭',
+      netStatus: '在线',
+    },
+    {
+      deviceName: '风门9',
+      frontDoorStatus: '关闭',
+      backDoorStatus: '关闭',
+      netStatus: '在线',
+    },
+  ],
+};
+// const readData = ref({});
+function refresh() {
+  fetchConfigs('belt').then(() => {
+    configs.value = testBeltLaneFire;
+    // const params = {
+    //   devicetype: 'sys',
+    //   systemID: '2028657172566073346',
+    // };
+    // Promise.resolve(getDevice(params)).then(updateData);
+    Promise.resolve(readData).then(updateData);
+    // updateEnhancedConfigs(configs.value);
+    // getDataSource();
+  });
+}
 
-  function initInterval() {
-    setInterval(() => {
-      refresh();
-    }, 60000);
-  }
-  onMounted(() => {
+function initInterval() {
+  setInterval(() => {
     refresh();
-    initInterval();
-  });
+  }, 60000);
+}
+onMounted(() => {
+  refresh();
+  initInterval();
+});
 </script>
 
 <style lang="less" scoped>
-  .spray-wrapper {
+.spray-wrapper {
+  width: 100%;
+  height: 100%;
+  background-image: url('/@/assets/images/beltFire/baseMap.png');
+  background-size: cover;
+}
+
+#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;
+  width: 100%;
+  height: 100%;
+  color: @white;
+  position: relative;
+  .border {
     width: 100%;
-    height: 100%;
-    background-image: url('/@/assets/images/beltFire/baseMap.png');
-    background-size: cover;
+    height: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
+    margin-top: 50px;
   }
 
   #spray3D {

+ 82 - 78
src/views/vent/home/configurable/belt/components/BeltNav.vue

@@ -3,7 +3,7 @@
     <!-- 左侧圆形图标 -->
     <div class="icon-left">
       <div class="icon-circle">
-        <div class="icon"></div>
+        <div class="icon">3D</div>
       </div>
     </div>
     <!-- 中间按钮组 -->
@@ -21,7 +21,7 @@
     <!-- 右侧圆形图标 -->
     <div class="icon-right">
       <div class="icon-circle">
-        <div class="icon"></div>
+        <span class="icon">应急控制</span>
       </div>
     </div>
   </div>
@@ -85,86 +85,90 @@
 </script>
 
 <style scoped lang="less">
-  .tech-nav-container {
+.tech-nav-container {
+  width: 100%;
+  max-width: 900px;
+  margin: 0 auto;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 60px;
+  position: relative;
+  box-sizing: border-box;
+  height: 50px;
+}
+
+/* 左侧图标容器 */
+.icon-left,
+.icon-right {
+  width: 100px;
+  height: 40px;
+  z-index: 2; /* 关键:设置为最高层级,确保浮在背景图之上 */
+  flex-shrink: 0; /* 防止被压缩 */
+  background: url('/@/assets/images/beltFire/normalBtn.png') center / 100% 100% no-repeat;
+  margin-top: 12px;
+  .icon-circle {
     width: 100%;
-    max-width: 800px;
-    margin: 0 auto;
+    height: 100%;
     display: flex;
     align-items: center;
-    justify-content: space-between;
-    padding: 12px 60px;
-    position: relative;
-    box-sizing: border-box;
-    height: 50px;
-  }
-
-  /* 左侧图标容器 */
-  .icon-left,
-  .icon-right {
-    width: 50px;
-    height: 50px;
-    position: relative;
-    z-index: 2; /* 关键:设置为最高层级,确保浮在背景图之上 */
-    flex-shrink: 0; /* 防止被压缩 */
-    margin-top: 12px;
-    .icon-circle {
-      width: 100%;
-      height: 100%;
-      background: url('/@/assets/images/beltFire/yjkf/1-3.png') center / 100% 100% no-repeat;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-
-      .icon {
-        margin-top: 2px;
-        width: 18px;
-        height: 18px;
-        background-size: contain;
-        background-repeat: no-repeat;
-      }
-    }
-  }
-
-  .icon-left .icon {
-    background-image: url('/@/assets/images/beltFire/yjkf/3D.svg');
-  }
-  .icon-right .icon {
-    background-image: url('/@/assets/images/beltFire/yjkf/yjkz.svg');
-  }
+    justify-content: center;
+  }
+}
+.icon-left {
+  margin-left: -60px;
+}
+.icon-right {
+  margin-right: -60px;
+}
+.icon-left:hover,
+.icon-right:hover {
+  background: url('/@/assets/images/beltFire/activeBtn.png') center / 100% 100% no-repeat;
+}
+.icon-left .icon {
+  font-size: 14px;
+  font-weight: bold;
+}
+.icon-right .icon {
+  font-size: 14px;
+  font-weight: bold;
+}
 
-  /* 中间按钮组容器 - 核心修改区 */
-  .nav-buttons {
-    display: flex;
-    margin-left: 50px;
-    align-items: center;
-    gap: 5px;
-    position: relative;
-    z-index: 1;
-    flex: 1;
-    padding: 0 20px;
-    box-sizing: border-box;
-  }
-  .top-img {
-    width: 100%;
-    height: 100px;
-    background: url('/@/assets/images/beltFire/yjkf/1-2.png') no-repeat center;
-    position: absolute;
-    top: 0;
-    left: 0;
-    z-index: -1; /* 确保背景图在按钮下方 */
-  }
-  /* 按钮基础样式 */
-  .nav-menu-item,
-  .nav-menu-active {
-    height: 80%;
-    line-height: 35px;
-    padding: 0 20px;
-    font-size: 15px;
-    text-align: center;
-    white-space: nowrap;
-    cursor: pointer;
-    transition: all 0.2s ease;
-  }
+/* 中间按钮组容器 - 核心修改区 */
+.nav-buttons {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  position: relative;
+  z-index: 1;
+  flex: 1;
+  padding: 0 20px;
+  margin-top: 15px;
+  margin-left: 60px;
+  box-sizing: border-box;
+}
+.top-img {
+  width: 100%;
+  height: 100px;
+  background: url(/src/assets/images/beltFire/yjkf/1-2.png) no-repeat center;
+  background-size: 84% 62%;
+  position: absolute;
+  top: 9px;
+  left: 0;
+  z-index: -1;
+}
+/* 按钮基础样式 */
+.nav-menu-item,
+.nav-menu-active {
+  height: 80%;
+  line-height: 35px;
+  padding: 0 20px;
+  font-size: 15px;
+  text-align: center;
+  white-space: nowrap;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
 
   .nav-menu-item {
     color: #59acc7;

+ 31 - 39
src/views/vent/home/configurable/belt/components/Header.vue

@@ -80,43 +80,35 @@
 <style scoped>
   @import '/@/design/theme.less';
 
-  .costume-header {
-    height: 30px;
-    background: url('@/assets/images/beltFire/4-1.png');
-    background-size: 100% 100%;
-  }
-  .costume-headerToggleIcon {
-    height: 30px;
-    background: url('@/assets/images/beltFire/4-1.png');
-    background-size: 100% 100%;
-  }
-  .costume-header_left {
-    border-left: 3px solid;
-    border-right: 3px solid;
-    border-image-source: linear-gradient(to top, #00000033, var(--vent-base-light-bg), #00000033);
-    border-image-slice: 1;
-  }
-  .costume-header_right {
-    border-right: 3px solid;
-    border-image-source: linear-gradient(to top, #00000033, var(--vent-base-light-bg), #00000033);
-    border-image-slice: 1;
-  }
-  img {
-    width: 16px;
-    height: 16px;
-    margin-left: 8px;
-  }
-  ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
-    /* background-color: transparent; */
-    color: #fff;
-  }
-  ::v-deep .zxm-select-arrow {
-    color: #fff;
-  }
-  ::v-deep .zxm-select-selection-item {
-    color: #fff !important;
-  }
-  ::v-deep .zxm-select-selection-placeholder {
-    color: #fff !important;
-  }
+.costume-header {
+  height: 30px;
+  background: url('@/assets/images/beltFire/yjkf/1-1.png') no-repeat;
+  background-size: 100% 100%;
+}
+.costume-headerToggleIcon {
+  height: 30px;
+}
+.costume-header_left {
+}
+.costume-header_right {
+  padding-right: 5px;
+}
+img {
+  width: 16px;
+  height: 16px;
+  margin-left: 8px;
+}
+::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
+  /* background-color: transparent; */
+  color: #fff;
+}
+::v-deep .zxm-select-arrow {
+  color: #fff;
+}
+::v-deep .zxm-select-selection-item {
+  color: #fff !important;
+}
+::v-deep .zxm-select-selection-placeholder {
+  color: #fff !important;
+}
 </style>

+ 105 - 97
src/views/vent/home/configurable/belt/components/ModuleCommon.vue

@@ -12,132 +12,140 @@
         <slot>
           <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="handleSelect" />
           <Content
+            v-if="pageType == 'belt'"
             :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }"
             :moduleData="moduleData"
             :data="selectedDevice"
             :chartData="chartData"
           />
+          <Content
+            v-else
+            :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }"
+            :moduleData="moduleData"
+            :data="data"
+            :chartData="chartData"
+          />
         </slot>
       </template>
     </ventBox1>
   </Transition>
 </template>
 <script lang="ts" setup>
-  import Header from './header.vue';
-  import Content from '../../components/content.vue';
-  // import ModuleLeft from './original/moduleLeft.vue';
-  // import ModuleBottom from './original/moduleBottom.vue';
-  import { computed, ref, watch } from 'vue';
-  import ventBox1 from './ventBoxBelt.vue';
-  import { openWindow } from '/@/utils';
-  import { getFormattedText } from '../../hooks/helper';
-  import { useInitModule } from '../../hooks/useInit';
-  // import { ModuleProps } from '../types';
+import Header from './header.vue';
+import Content from '../../components/content.vue';
+// import ModuleLeft from './original/moduleLeft.vue';
+// import ModuleBottom from './original/moduleBottom.vue';
+import { computed, ref, watch } from 'vue';
+import ventBox1 from './ventBoxBelt.vue';
+import { openWindow } from '/@/utils';
+import { getFormattedText } from '../../hooks/helper';
+import { useInitModule } from '../../hooks/useInit';
+// import { ModuleProps } from '../types';
 
-  const props = defineProps<{
-    pageType: string;
-    /** 配置的详细模块信息 */
-    moduleData: any;
-    /** 配置的详细样式信息 */
-    showStyle: any;
-    /** 该模块配置中的设备标识符 */
-    deviceType: string;
-    /** api返回的数据 */
-    data: any;
-    moduleName: string;
-    visible: boolean;
-    chartData?: any;
-  }>();
-  defineEmits(['close', 'click']);
+const props = defineProps<{
+  pageType: string;
+  /** 配置的详细模块信息 */
+  moduleData: any;
+  /** 配置的详细样式信息 */
+  showStyle: any;
+  /** 该模块配置中的设备标识符 */
+  deviceType: string;
+  /** api返回的数据 */
+  data: any;
+  moduleName: string;
+  visible: boolean;
+  chartData?: any;
+}>();
+defineEmits(['close', 'click']);
 
-  const { header } = props.moduleData;
+const { header } = props.moduleData;
 
-  const { selectedDeviceID, selectedDevice, options, init } = useInitModule(props.deviceType, props.moduleData);
+const { selectedDeviceID, selectedDevice, options, init } = useInitModule(props.deviceType, props.moduleData);
 
-  const selectedData = ref();
+const selectedData = ref();
 
-  const style = computed(() => {
-    const size = props.showStyle.size;
-    const position = props.showStyle.position;
-    return size + position + 'position: absolute; pointer-events: auto; z-index: 1';
-  });
-  const pageType = computed(() => {
-    return props.pageType || '';
-  });
-  const capitalizedPosition = computed(() => {
-    return props.showStyle.position.includes('left') ? 'Left' : 'Right';
-  });
+const style = computed(() => {
+  const size = props.showStyle.size;
+  const position = props.showStyle.position;
+  return size + position + 'position: absolute; pointer-events: auto; z-index: 1';
+});
+const pageType = computed(() => {
+  return props.pageType || '';
+});
+const capitalizedPosition = computed(() => {
+  return props.showStyle.position.includes('left') ? 'Left' : 'Right';
+});
 
-  // 根据配置里的定位判断应该使用哪个class
-  function getModuleClass({ size, position }) {
-    const [_, width] = size.match(/width:([0-9]+)px/) || [];
-    if (position.includes('bottom') || parseInt(width) > 800) {
-      return 'module-common module-common-longer';
-    }
-    return 'module-common';
+// 根据配置里的定位判断应该使用哪个class
+function getModuleClass({ size, position }) {
+  const [_, width] = size.match(/width:([0-9]+)px/) || [];
+  if (position.includes('bottom') || parseInt(width) > 800) {
+    return 'module-common module-common-longer';
   }
+  return 'module-common';
+}
 
-  function redirectTo() {
-    const { to } = props.moduleData;
-    if (!to) return;
-    openWindow(getFormattedText(props.data, to));
-  }
+function redirectTo() {
+  const { to } = props.moduleData;
+  if (!to) return;
+  openWindow(getFormattedText(props.data, to));
+}
 
-  /**
-   * 模块选择切换事件
-   * @param selectedItem
-   */
-  function handleSelect(selectedItem: any) {
-    selectedData.value = selectedItem;
-    if (!selectedItem) return;
+/**
+ * 模块选择切换事件
+ * @param selectedItem
+ */
+function handleSelect(selectedItem: any) {
+  selectedData.value = selectedItem;
+  if (!selectedItem) return;
 
-    selectedDeviceID.value = options.value[0]?.value;
-    if (selectedItem.id !== undefined && selectedItem.id !== null) {
-      // 确保这个 ID 在当前的 options 里存在
-      const isValid = options.value.some((opt) => opt.value === selectedItem.id);
-      if (isValid) {
-        selectedDeviceID.value = selectedItem.id;
-      }
+  selectedDeviceID.value = options.value[0]?.value;
+  if (selectedItem.id !== undefined && selectedItem.id !== null) {
+    // 确保这个 ID 在当前的 options 里存在
+    const isValid = options.value.some((opt) => opt.value === selectedItem.id);
+    if (isValid) {
+      selectedDeviceID.value = selectedItem.id;
     }
   }
-  watch(
-    () => props.data,
-    (d) => {
-      init(d);
-      if (!selectedDeviceID.value) {
-        console.log(selectedDeviceID.value, '------');
+}
+watch(
+  () => props.data,
+  (d) => {
+    init(d);
+    if (!selectedDeviceID.value) {
+      console.log(selectedDeviceID.value, '------');
 
-        selectedDeviceID.value = options.value[0]?.value;
-      }
-    },
-    {
-      immediate: true,
+      selectedDeviceID.value = options.value[0]?.value;
     }
-  );
+  },
+  {
+    immediate: true,
+  }
+);
 </script>
 <style lang="less" scoped>
-  @import '/@/design/theme.less';
+@import '/@/design/theme.less';
 
-  .module-common .box1-center {
-    height: calc(100% - 48px);
-  }
+.module-common .box1-center {
+  height: calc(100% - 48px);
+}
 
-  :deep(.box1-center) {
-    height: calc(100% - 48px);
+:deep(.box1-center) {
+  height: calc(100% - 48px);
+}
+:deep(.box1-center > .box-container) {
+  height: 100%;
+  padding: 0 !important;
+  width: 100% !important;
+}
+.module-common-longer {
+  :deep(.box1-top) {
+    --image-box1-top: url('/@/assets/images/beltFire/1-1.png');
+    background-image: url('/@/assets/images/beltFire/1-1.png');
   }
-  :deep(.box1-center > .box-container) {
-    height: 100%;
-    padding: 0 !important;
-    width: 100% !important;
-  }
-  .module-common-longer {
-    :deep(.box1-top) {
-      --image-box1-top: url('/@/assets/images/beltFire/1-1.png');
-      background-image: url('/@/assets/images/beltFire/1-1.png');
-    }
-    :deep(.box1-bottom) {
-      --image-box1-bottom: url('/@/assets/images/beltFire/1-2.png');
-      background-image: url('/@/assets/images/beltFire/1-2.png');
-    }
+  :deep(.box1-bottom) {
+    --image-box1-bottom: url('/@/assets/images/beltFire/1-2.png');
+    background-image: url('/@/assets/images/beltFire/1-2.png');
   }
+}
 </style>

+ 0 - 401
src/views/vent/home/configurable/belt/components/contentBelt.vue

@@ -1,401 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<template>
-  <!-- 主体内容部分 -->
-  <div class="content">
-    <!-- 背景 -->
-    <img v-if="background.show && background.type === 'image'" class="content__background" :src="background.link" />
-    <video
-      v-if="background.show && background.type === 'video' && background.isBoard"
-      class="content__background"
-      width="100%"
-      autoplay
-      loop
-      muted
-      disablepictureinpicture
-      playsinline
-    >
-      <source :src="background.link" />
-      Not Supportted Link Or Browser
-    </video>
-    <video
-      v-if="background.show && background.type === 'video' && !background.isBoard"
-      class="content__background_1"
-      width="100%"
-      autoplay
-      loop
-      muted
-      disablepictureinpicture
-      playsinline
-    >
-      <source :src="background.link" />
-      Not Supportted Link Or Browser
-    </video>
-    <div class="flex w-full h-full" :style="{ flexDirection: layout.direction }">
-      <div v-for="config in layoutConfig" :key="config.name" :style="{ flexBasis: config.basis, overflow: config.overflow ? 'auto' : 'none' }">
-        <template v-if="config.name === 'board'">
-          <div class="content__module content__module1 flex flex-justify-around flex-items-center flex-wrap">
-            <MiniBoard
-              v-for="item in config.items"
-              :key="item.prop"
-              :label="item.label"
-              :value="item.value"
-              :type="config.type"
-              :layout="config.layout"
-            />
-          </div>
-        </template>
-        <!-- 通常列表部分 -->
-        <template v-if="config.name === 'list'">
-          <CustomListBelt class="content__module" :type="config.type" :data="config.data" :list-config="config.items" />
-        </template>
-        <!-- 复杂列表部分 -->
-        <template v-if="config.name === 'complex_list'">
-          <ComplexListBelt class="content__module" :type="config.type" :data="config.data" :list-config="config.items" />
-        </template>
-        <template v-if="config.name === 'complex_list1'">
-          <ComplexList1Belt class="content__module" :type="config.type" :data="config.data" :list-config="config.items" />
-        </template>
-        <!-- 表格部分,这部分通常是占一整个模块的 -->
-        <template v-if="config.name === 'table'">
-          <CustomTableBelt
-            class="content__module text-center overflow-auto"
-            :type="config.type"
-            :columns="config.columns"
-            :auto-scroll="config.autoScroll"
-            :config="config"
-          />
-        </template>
-        <template v-if="config.name === 'gateBoard'">
-          <GateBoard class="content__module text-center overflow-auto" :data="config.data" />
-        </template>
-      </div>
-    </div>
-  </div>
-</template>
-<script lang="ts" setup>
-  import { computed } from 'vue';
-  import { CommonItem, Config } from '../../../../deviceManager/configurationTable/types';
-  import CustomListBelt from './detail/CustomListBelt.vue';
-  import ComplexListBelt from './detail/ComplexListBelt.vue';
-  import ComplexList1Belt from './detail/ComplexList-Belt1.vue';
-  import CustomTableBelt from './detail/CustomTableBelt.vue';
-  import GateBoard from './detail/gateBoard.vue';
-
-  import { clone } from 'lodash-es';
-  import { getData, getFormattedText } from '../../hooks/helper';
-
-  const props = defineProps<{
-    data: any;
-    moduleData: Config['moduleData'];
-    chartData: any;
-  }>();
-
-  const { background, layout } = props.moduleData;
-
-  // 获取当原始配置带 items 项时的最终 items 配置
-  function getItems(raw, items: CommonItem[]) {
-    return items.map((i) => {
-      return {
-        ...i,
-        label: getFormattedText(raw, i.label, i.trans),
-        value: getFormattedText(raw, i.value, i.trans),
-      };
-    });
-  }
-
-  // 获取当 List 组件配置带 items 项时的最终 items 配置
-  function getListItems(raw: any, items: CommonItem[], mapFromData?: boolean) {
-    if (mapFromData && Array.isArray(raw)) {
-      return raw.map((data) => {
-        const item = items[0];
-        return {
-          ...item,
-          label: getFormattedText(data, item.label, item.trans),
-          value: getFormattedText(data, item.value, item.trans),
-        };
-      });
-    }
-    return getItems(raw, items);
-  }
-
-  /** 根据配置里的layout将配置格式化为带 key 的具体配置,例如:[{ key: 'list', value: any, ...ModuleDataList }] */
-  const layoutConfig = computed(() => {
-    const refData = props.data;
-    const list = clone(props.moduleData.list) || [];
-    const complex_list = clone(props.moduleData.complex_list) || [];
-    const complex_list1 = clone(props.moduleData.complex_list1) || [];
-    const table = clone(props.moduleData.table) || [];
-    const board = clone(props.moduleData.board) || [];
-    const gallery = clone(props.moduleData.gallery) || [];
-    const gallery_list = clone(props.moduleData.gallery_list) || [];
-    const preset = clone(props.moduleData.preset) || [];
-    return layout.items.reduce((arr: any[], item) => {
-      switch (item.name) {
-        case 'board': {
-          const cfg = board.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            items: getItems(data, cfg.items),
-          });
-          break;
-        }
-        case 'gallery': {
-          const cfg = gallery.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            items: getItems(data, cfg.items),
-          });
-          break;
-        }
-        case 'list': {
-          const cfg = list.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            items: getListItems(data, cfg.items, cfg.mapFromData),
-          });
-          break;
-        }
-        case 'complex_list': {
-          const cfg = complex_list.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          if (cfg.mapFromData) {
-            const firstListItem = cfg.items[0];
-            arr.push({
-              overflow: true,
-              ...item,
-              ...cfg,
-              items: (data || []).map((d) => {
-                return {
-                  title: getFormattedText(d, firstListItem.title, firstListItem.trans),
-                  contents: firstListItem.contents.map((e) => {
-                    return {
-                      ...e,
-                      label: getFormattedText(d, e.label, e.trans),
-                      value: getFormattedText(d, e.value, e.trans),
-                    };
-                  }),
-                };
-              }),
-            });
-          } else {
-            arr.push({
-              overflow: true,
-              ...item,
-              ...cfg,
-              items: cfg.items.map((i) => {
-                return {
-                  title: getFormattedText(data, i.title, i.trans),
-                  contents: i.contents.map((e) => {
-                    return {
-                      ...e,
-                      label: getFormattedText(data, e.label, e.trans),
-                      value: getFormattedText(data, e.value, e.trans),
-                    };
-                  }),
-                };
-              }),
-            });
-          }
-          break;
-        }
-        case 'gallery_list': {
-          const cfg = gallery_list.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            items: getItems(data, cfg.items),
-            galleryItems: getItems(data, cfg.galleryItems),
-          });
-          break;
-        }
-        case 'complex_list1': {
-          const cfg = complex_list1.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            items: cfg.items.map((i) => {
-              return {
-                title: getFormattedText(data, i.title, i.trans),
-                contents: i.contents.map((e) => {
-                  return {
-                    ...e,
-                    label: getFormattedText(data, e.label, e.trans),
-                    value: getFormattedText(data, e.value, e.trans),
-                  };
-                }),
-              };
-            }),
-          });
-          console.log(refData, 'refData');
-
-          break;
-        }
-        case 'table': {
-          const cfg = table.shift();
-          console.log(cfg, '111');
-          if (!cfg) break;
-          arr.push({
-            overflow: true,
-            ...item,
-            ...cfg,
-            columns: cfg.columns,
-            data: refData,
-          });
-          break;
-        }
-        default: {
-          const cfg = preset.shift();
-          if (!cfg) break;
-          const data = getData(refData, cfg.readFrom, cfg.parser);
-
-          arr.push({
-            ...item,
-            data,
-            config: cfg,
-          });
-          break;
-        }
-      }
-      return arr;
-    }, []);
-  });
-</script>
-<style lang="less" scoped>
-  @import '@/design/theme.less';
-
-  .content {
-    position: relative;
-    // z-index: -2;
-    display: flex;
-    flex-direction: column;
-    overflow-y: auto; // 这里会导致样式无故添加滚动条
-    overflow-x: hidden;
-  }
-
-  .content__background {
-    width: 100%;
-    // height: 100%;
-    height: calc(100% - 65px);
-    position: absolute;
-    top: 65px;
-    left: 0;
-    z-index: 0;
-    object-fit: fill;
-    padding: 5px;
-    box-sizing: border-box;
-  }
-  .content__background_1 {
-    width: 100%;
-    height: 100%;
-    position: absolute;
-    top: 0px;
-    left: 0;
-    z-index: 0;
-    object-fit: fill;
-  }
-
-  .image__background {
-    width: 35%;
-    height: 61%;
-    left: 30%;
-  }
-
-  .content__module {
-    // margin-top: 5px;
-    // margin-bottom: 5px;
-    width: 100%;
-    height: 100%;
-  }
-
-  .content__module1 {
-    background: url('@/assets/images/beltFire/yjkf/2-1.png');
-    background-repeat: no-repeat;
-    background-size: 100% 100%;
-    height: 30%;
-    margin-top: 20%;
-  }
-
-  .content__moduleFire {
-    width: 100%;
-    height: 100%;
-    margin-left: -24% !important;
-  }
-
-  .content__module_dust {
-    background: url('@/assets/images/vent/homeNew/bottomBg.png');
-    background-repeat: no-repeat;
-    background-size: 100% 100%;
-    width: 100%;
-    height: 100%;
-  }
-
-  // .content__module:first-of-type {
-  //   margin-top: 0;
-  // }
-  // .content__module:last-of-type {
-  //   margin-bottom: 0;
-  // }
-  ::-webkit-scrollbar {
-    width: 5px !important;
-  }
-
-  ::-webkit-scrollbar-thumb {
-    width: 5px !important;
-  }
-
-  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-    /* background-color: transparent; */
-    color: #fff;
-  }
-
-  :deep(.zxm-select-arrow) {
-    color: #fff;
-  }
-
-  :deep(.zxm-select-selection-item) {
-    color: #fff !important;
-  }
-
-  :deep(.zxm-select-selection-placeholder) {
-    color: #fff !important;
-  }
-
-  :deep(.dialog-overlay) {
-    width: 100%;
-    height: 100%;
-    position: unset;
-    box-shadow: unset;
-  }
-
-  ::-webkit-scrollbar {
-    width: 5px !important;
-  }
-
-  ::-webkit-scrollbar-thumb {
-    width: 5px !important;
-  }
-</style>

+ 1 - 3
src/views/vent/home/configurable/belt/components/detail/gateBoard.vue

@@ -54,6 +54,7 @@ import { ref, onMounted, defineProps, watch } from 'vue';
 import { getFormattedText } from '../../../hooks/helper';
 // import gateSVG from '../gateSVG.vue';
 import gateSVG from '../../../../../monitorManager/gateMonitor/components/gateDualSVG.vue';
+import { nextTick } from 'process';
 const props = defineProps<{
   config: {
     config: {
@@ -90,13 +91,11 @@ function monitorAnimation(selectData, index) {
 
 function oneKeyOpen(index) {
   if (childRefs.value[index]) {
-    // 直接强制两个都打开!
     childRefs.value[index].animate(true, true, true);
   }
 }
 function oneKeyClose(index) {
   if (childRefs.value[index]) {
-    // 直接强制两个都打开!
     childRefs.value[index].animate(false, false, false);
   }
 }
@@ -105,7 +104,6 @@ watch(
   () => props.data,
   (newData) => {
     if (!newData || !newData.length) return;
-    // 遍历每一项,执行动画(初始化 + 数据更新都生效)
     newData.forEach((item, index) => {
       monitorAnimation(item, index);
     });

+ 88 - 0
src/views/vent/home/configurable/belt/configurable.api.ts

@@ -8,6 +8,7 @@ import _ from 'lodash';
 enum Api {
   getSystem = '/modelreq/monitor/system',
   getDevice = '/modelreq/monitor/device',
+  getDisHome = '/monitor/disaster/getDisHome',
 }
 
 export const getSystem = (params) => defHttp.post({ url: Api.getSystem, params });
@@ -16,3 +17,90 @@ export const getDevice = (params) => defHttp.post({ url: Api.getDevice, params }
 // 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
 // 这会导致相同的请求被同时发送多次。
 const cache = new Map<string, Promise<any>>();
+export const getDisHome = (params) => {
+  // 生成缓存key,基于接口地址和参数
+  const key = `${Api.getDisHome}?${JSON.stringify(params)}`;
+
+  // 缓存不存在时发起请求
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getDisHome, params }).finally(() => {
+        // 请求完成后删除缓存,保证下次请求能获取最新数据
+        cache.delete(key);
+      })
+    );
+  }
+
+  // 返回缓存中的Promise并处理响应数据
+  return (cache.get(key) as Promise<any>).then((res) => {
+    // 1. 处理 pdArray 中的光纤温度数据(解析JSON字符串)
+    if (res.pdArray && Array.isArray(res.pdArray)) {
+      res.pdArray.forEach((e) => {
+        // 先校验 arrayFiber 是数组,避免forEach报错
+        if (e.arrayFiber && Array.isArray(e.arrayFiber)) {
+          e.arrayFiber.forEach((j) => {
+            // 安全解析 JSON,避免 undefined/无效JSON 导致报错
+            j.fibreTemperatureArr = safeJsonParse(j.fibreTemperature, []);
+          });
+        }
+      });
+    }
+
+    // 2. 处理 sgGxObj 下的设备数据
+    if (res.sgGxObj) {
+      // 2.1 解析 devGxcw 中的光纤温度
+      if (res.sgGxObj.devGxcw && Array.isArray(res.sgGxObj.devGxcw)) {
+        res.sgGxObj.devGxcw.forEach((e) => {
+          e.fibreTemperatureArr = safeJsonParse(e.fibreTemperature, []);
+        });
+      }
+
+      // 2.2 为 devSgjc 中的气体字段设置默认值
+      if (res.sgGxObj.devSgjc && Array.isArray(res.sgGxObj.devSgjc)) {
+        res.sgGxObj.devSgjc.forEach((e) => {
+          e.o2val = e.o2Val || 0;
+          e.coval = e.coVal || 0;
+          e.gasval = e.gasVal || 0;
+          e.ch2val = e.ch2Val || 0;
+          e.chval = e.chVal || 0;
+        });
+      }
+    }
+
+    // 3. 重组 obfObj 为按气体类型分类的结构
+    if (res.obfObj && Array.isArray(res.obfObj.arrayDev)) {
+      res.obfObj.obfObjModded = [
+        { objType: '氧气', arrayDev: mapObfDev(res.obfObj.arrayDev, 'o2Val') },
+        { objType: '甲烷', arrayDev: mapObfDev(res.obfObj.arrayDev, 'ch4Val') },
+        { objType: '一氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'coVal') },
+        { objType: '乙炔', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h2Val') },
+        { objType: '二氧化碳', arrayDev: mapObfDev(res.obfObj.arrayDev, 'co2Val') },
+        { objType: '乙烯', arrayDev: mapObfDev(res.obfObj.arrayDev, 'c2h4Val') },
+        { objType: '压差', arrayDev: mapObfDev(res.obfObj.arrayDev, 'dpVal') },
+        { objType: '温度', arrayDev: mapObfDev(res.obfObj.arrayDev, 'tempVal') },
+      ];
+    }
+
+    return res;
+  });
+};
+/**
+ * 安全解析 JSON 字符串的工具函数
+ * @param {string} jsonStr - 要解析的JSON字符串
+ * @param {any} defaultValue - 解析失败/值无效时的默认值
+ * @returns {any} 解析结果或默认值
+ */
+function safeJsonParse(jsonStr, defaultValue = null) {
+  // 先校验值是否为有效字符串
+  if (!jsonStr || typeof jsonStr !== 'string') {
+    return defaultValue;
+  }
+  // 捕获解析异常
+  try {
+    return JSON.parse(jsonStr);
+  } catch (err) {
+    console.warn('JSON解析失败', jsonStr, err);
+    return defaultValue;
+  }
+}

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

@@ -2,7 +2,7 @@ import { Config } from '../../../deviceManager/configurationTable/types';
 // 皮带巷三级防灭火首页
 export const testBeltLaneFire: Config[] = [
   {
-    deviceType: '',
+    deviceType: 'pdhzfxpj',
     moduleName: '皮带火灾风险状态整体评价',
     pageType: 'belt',
     moduleData: {
@@ -134,7 +134,7 @@ export const testBeltLaneFire: Config[] = [
     },
   },
   {
-    deviceType: 'plmhInfo',
+    deviceType: 'spray_auto',
     moduleName: '喷淋灭火系统',
     pageType: 'belt',
     moduleData: {
@@ -187,7 +187,7 @@ export const testBeltLaneFire: Config[] = [
             },
             {
               label: '运行状态',
-              value: '${[0].yxzt}',
+              value: '${[0].deviceStatus}',
               trans: {
                 '0': '未喷淋',
                 '1': '正在喷淋',
@@ -197,7 +197,7 @@ export const testBeltLaneFire: Config[] = [
             },
             {
               label: '喷淋水压状态',
-              value: '${[0].plsy}',
+              value: '${[0].MPa}',
               color: 'blue',
               info: '',
             },
@@ -996,7 +996,7 @@ export const testBeltNew: Config[] = [
 ];
 export const testSpary: Config[] = [
   {
-    deviceType: 'plmhInfo', //
+    deviceType: 'sprayData', //
     moduleName: '',
     pageType: 'beltYjkf1',
     moduleData: {
@@ -1005,7 +1005,7 @@ export const testSpary: Config[] = [
         readFrom: '',
         selector: {
           show: true,
-          value: '${beltName}',
+          value: '${typeName}',
         },
         slot: {
           show: false,
@@ -1036,7 +1036,7 @@ export const testSpary: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'plmhInfo',
+          readFrom: 'sprayData[0].datalist',
           type: 'C',
           config: [
             {
@@ -1044,17 +1044,17 @@ export const testSpary: Config[] = [
               contentTop: [
                 {
                   label: '皮带区域',
-                  code: 'beltArea',
+                  code: '${strname}',
                 },
                 {
                   label: '设备位置',
-                  code: 'devicePosition',
+                  code: '${strinstallpos}',
                 },
               ],
               contents: [
                 {
                   label: '网络状态',
-                  code: 'netStatus',
+                  code: '${netStatus}',
                   trans: {
                     0: '断开',
                     1: '正常',
@@ -1062,7 +1062,7 @@ export const testSpary: Config[] = [
                 },
                 {
                   label: '运行状态',
-                  code: 'runStatus',
+                  code: '${readData.deviceStatus}',
                   trans: {
                     0: '断开',
                     1: '正常',
@@ -1070,78 +1070,78 @@ export const testSpary: Config[] = [
                 },
                 {
                   label: '水量',
-                  code: 'waterVolume',
+                  code: '${readData.volume}',
                 },
                 {
                   label: '水压',
-                  code: 'waterPressure',
+                  code: '${readData.MPa}',
                 },
               ],
             },
           ],
         },
       ],
-      mock: {
-        plmhInfo: [
-          {
-            id: '1',
-            beltName: '1#皮带区域',
-            beltData: [
-              {
-                sid: '1',
-                beltArea: '1#皮带区域',
-                devicePosition: '1#皮带-50m处',
-                netStatus: '1',
-                runStatus: '1',
-                waterVolume: '0.0',
-                waterPressure: '0.0 Mpa',
-              },
-              {
-                sid: '2',
-                beltArea: '1#皮带区域',
-                devicePosition: '1#皮带-100m处',
-                netStatus: '1',
-                runStatus: '1',
-                waterVolume: '0.0',
-                waterPressure: '0.0 Mpa',
-              },
-              {
-                sid: '3',
-                beltArea: '1#皮带区域',
-                devicePosition: '1#皮带-150m处',
-                netStatus: '1',
-                runStatus: '1',
-                waterVolume: '0.0',
-                waterPressure: '0.0 Mpa',
-              },
-            ],
-          },
-          {
-            id: '2',
-            beltName: '2#皮带区域',
-            beltData: [
-              {
-                sid: '4',
-                beltArea: '2#皮带区域',
-                devicePosition: '2#皮带-50m处',
-                netStatus: '1',
-                runStatus: '1',
-                waterVolume: '0.0',
-                waterPressure: '0.0 Mpa',
-              },
-              {
-                sid: '5',
-                beltArea: '2#皮带区域',
-                devicePosition: '2#皮带-100m处',
-                netStatus: '1',
-                runStatus: '1',
-                waterVolume: '0.0',
-                waterPressure: '0.0 Mpa',
-              },
-            ],
-          },
-        ],
-      },
+      // mock: {
+      //   plmhInfo: [
+      //     {
+      //       id: '1',
+      //       beltName: '1#皮带区域',
+      //       beltData: [
+      //         {
+      //           sid: '1',
+      //           beltArea: '1#皮带区域',
+      //           devicePosition: '1#皮带-50m处',
+      //           netStatus: '1',
+      //           runStatus: '1',
+      //           waterVolume: '0.0',
+      //           waterPressure: '0.0 Mpa',
+      //         },
+      //         {
+      //           sid: '2',
+      //           beltArea: '1#皮带区域',
+      //           devicePosition: '1#皮带-100m处',
+      //           netStatus: '1',
+      //           runStatus: '1',
+      //           waterVolume: '0.0',
+      //           waterPressure: '0.0 Mpa',
+      //         },
+      //         {
+      //           sid: '3',
+      //           beltArea: '1#皮带区域',
+      //           devicePosition: '1#皮带-150m处',
+      //           netStatus: '1',
+      //           runStatus: '1',
+      //           waterVolume: '0.0',
+      //           waterPressure: '0.0 Mpa',
+      //         },
+      //       ],
+      //     },
+      //     {
+      //       id: '2',
+      //       beltName: '2#皮带区域',
+      //       beltData: [
+      //         {
+      //           sid: '4',
+      //           beltArea: '2#皮带区域',
+      //           devicePosition: '2#皮带-50m处',
+      //           netStatus: '1',
+      //           runStatus: '1',
+      //           waterVolume: '0.0',
+      //           waterPressure: '0.0 Mpa',
+      //         },
+      //         {
+      //           sid: '5',
+      //           beltArea: '2#皮带区域',
+      //           devicePosition: '2#皮带-100m处',
+      //           netStatus: '1',
+      //           runStatus: '1',
+      //           waterVolume: '0.0',
+      //           waterPressure: '0.0 Mpa',
+      //         },
+      //       ],
+      //     },
+      //   ],
+      // },
     },
     showStyle: {
       size: 'width:440px;height:820px;',

+ 0 - 2
src/views/vent/home/configurable/components/belt/CameraListTest.vue

@@ -59,8 +59,6 @@ const videoList = ref([
   display: flex;
   flex-direction: column;
   align-items: center;
-  background: url('/@/assets/images/vent/camera_bg.png');
-  background-size: 100% 100%;
   .live-video {
     width: 90%;
     height: 86%;

+ 1 - 1
src/views/vent/home/configurable/components/belt/FireSensorAnalysis.vue

@@ -165,7 +165,7 @@ const parseStatus = (statusStr: string) => {
 
   &.status-danger {
     background-color: #ff4d4d;
-    box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
+    box-shadow: 0 0 6px 2px rgb(255, 0, 0);
     animation: flash 1s infinite;
   }
 }

+ 261 - 265
src/views/vent/home/configurable/components/belt/SprayControl.vue

@@ -10,8 +10,7 @@
         <a-button class="control-btn">自动控制</a-button>
       </div>
       <!-- 循环渲染分组 -->
-      <div v-for="(beltData, index) in data.beltData" :key="index" class="block-item">
-        <!-- {{ beltData }} -->
+      <div v-for="(beltData, index) in data" :key="index" class="block-item">
         <!-- 这里应该由data渲染,因为data数量是动态不固定的,config.config是静态的 -->
         <div v-for="(group, index) in config.config" :key="index" class="sensor-group">
           <!-- 组标题 -->
@@ -29,7 +28,7 @@
             <div class="item-icon" :class="getBgClass(itemIndex)"></div>
             <div class="item-status">
               <div class="item-label">{{ item.label }}</div>
-              <div class="item-code">{{ getItemText(beltData, item) }}</div>
+              <div class="item-code">{{ getFormattedText(beltData, item.code) }}</div>
             </div>
           </div>
           <div class="container">
@@ -37,8 +36,13 @@
               <div class="item-status">
                 <div class="item-label">{{ item.label }}</div>
                 <div class="item-code">
-                  <span class="status-dot" v-if="item.trans" :class="getStatusClass(beltData, item)"> </span>
-                  {{ getItemText(beltData, item) }}
+                  <span
+                    class="status-dot"
+                    v-if="item.trans"
+                    :class="[getFormattedText(beltData, item.code, item.trans) === '正常' ? 'status-normal' : 'status-danger', 'status-dot']"
+                  >
+                  </span>
+                  {{ getFormattedText(beltData, item.code, item.trans) }}
                 </div>
               </div>
             </div>
@@ -50,298 +54,290 @@
 </template>
 
 <script setup lang="ts">
-  import { computed, onMounted, ref } from 'vue';
-  import { getFormattedText } from '../../hooks/helper';
+import { computed, onMounted, ref } from 'vue';
+import { getFormattedText } from '../../hooks/helper';
 
-  const props = defineProps<{
-    config: Array<{
-      readFrom: string;
-      contentTop: Array<{
-        label: string;
-        code: string;
-        status?: string;
-        info?: string;
-      }>;
-      contents: Array<{
-        label: string;
-        code: string;
-        trans?: any;
-      }>;
+const props = defineProps<{
+  config: Array<{
+    readFrom: string;
+    contentTop: Array<{
+      label: string;
+      code: string;
+      status?: string;
+      info?: string;
     }>;
-    data: {
-      [key: string]: any;
-    };
-  }>();
+    contents: Array<{
+      label: string;
+      code: string;
+      trans?: any;
+    }>;
+  }>;
+  data: {
+    [key: string]: any;
+  };
+}>();
 
-  // --- 存储选中的 sid ---
-  const selectedSids = ref<string[]>([]);
+// --- 存储选中的 sid ---
+const selectedSids = ref<string[]>([]);
 
-  // --- 处理勾选变化 ---
-  const handleCheckChange = (checked: boolean, sid: string) => {
-    if (checked) {
-      // 勾选:如果不存在则加入数组
-      if (!selectedSids.value.includes(sid)) {
-        selectedSids.value.push(sid);
-      }
-    } else {
-      // 取消勾选:从数组中移除
-      const index = selectedSids.value.indexOf(sid);
-      if (index > -1) {
-        selectedSids.value.splice(index, 1);
-      }
+// --- 处理勾选变化 ---
+const handleCheckChange = (checked: boolean, sid: string) => {
+  if (checked) {
+    // 勾选:如果不存在则加入数组
+    if (!selectedSids.value.includes(sid)) {
+      selectedSids.value.push(sid);
     }
-    console.log('当前选中的 SID 列表:', selectedSids.value);
-  };
-  const getBgClass = (index) => {
-    return index % 2 === 0 ? 'bg-1' : 'bg-2';
-  };
-  /**
-   * 根据配置项从当前皮带数据中获取对应的值
-   * @param currentItem 当前循环到的单条皮带数据 (beltData)
-   * @param configItem 配置项 (包含 code 和 trans)
-   */
-  const getItemText = (currentItem: any, configItem: { code: string; trans?: any }) => {
-    // 1. 获取原始值: 通过 code 字段从 currentItem 中取值
-    const rawValue = currentItem[configItem.code];
-
-    // 2. 如果有翻译映射 (trans),则进行翻译
-    if (configItem.trans && configItem.trans[rawValue] !== undefined) {
-      return configItem.trans[rawValue];
+  } else {
+    // 取消勾选:从数组中移除
+    const index = selectedSids.value.indexOf(sid);
+    if (index > -1) {
+      selectedSids.value.splice(index, 1);
     }
+  }
+  console.log('当前选中的 SID 列表:', selectedSids.value);
+};
+const getBgClass = (index) => {
+  return index % 2 === 0 ? 'bg-1' : 'bg-2';
+};
+/**
+ * 根据配置项从当前皮带数据中获取对应的值
+ * @param currentItem 当前循环到的单条皮带数据 (beltData)
+ * @param configItem 配置项 (包含 code 和 trans)
+ */
+const getItemText = (currentItem: any, configItem: { code: string; trans?: any }) => {
+  // 1. 获取原始值: 通过 code 字段从 currentItem 中取值
+  const rawValue = currentItem[configItem.code];
 
-    // 3. 没有翻译则直接返回原始值
-    return rawValue;
-  };
-  const handleSpary = (state: boolean) => {
-    if (state) {
-      console.log('启动喷淋');
-    } else {
-      console.log('停止喷淋');
-    }
-  };
-  const getStatusClass = (beltData: any, item: any) => {
-    const val = getItemText(beltData, item);
-    // 根据翻译后的值判断颜色(连接=绿,断开=红)
-    if (val === '正常') return 'status-normal';
-    if (val === '断开') return 'status-danger';
-    return '';
-  };
-  onMounted(() => {
-    console.log(props.config, '123');
-    console.log(props.data, 'data');
-  });
+  // 2. 如果有翻译映射 (trans),则进行翻译
+  if (configItem.trans && configItem.trans[rawValue] !== undefined) {
+    return configItem.trans[rawValue];
+  }
+
+  // 3. 没有翻译则直接返回原始值
+  return rawValue;
+};
+const handleSpary = (state: boolean) => {
+  if (state) {
+    console.log('启动喷淋');
+  } else {
+    console.log('停止喷淋');
+  }
+};
+onMounted(() => {
+  console.log(props.config, '123');
+  console.log(props.data, 'data');
+});
 </script>
 
 <style scoped lang="less">
-  /* 全局面板样式 */
-  .fire-safety-panel {
-    border-radius: 8px;
-    padding: 3px;
-    color: #fff;
-    font-family: 'Microsoft YaHei', sans-serif;
-    padding-top: 10px;
-  }
-  /* 列表容器 */
-  .sensor-list {
-    display: flex;
-    flex-direction: column;
-    gap: 15px; /* 组间距 */
-  }
-  /** 按钮 **/
-  .control-bar {
-    background: url('@/assets/images/beltFire/yjkf/1-2title.png');
-    background-size: 100% 100%;
-    display: flex;
-    justify-content: space-around;
-    height: 50px;
-  }
-  .control-btn {
-    background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
-    border: 1px solid #40c4ff;
-    color: #fff;
-    font-size: 12px;
-    padding: 2px 8px;
-    height: 24px;
-    margin: auto;
-    box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
-  }
+/* 全局面板样式 */
+.fire-safety-panel {
+  border-radius: 8px;
+  padding: 3px;
+  color: #fff;
+  font-family: 'Microsoft YaHei', sans-serif;
+  padding-top: 10px;
+}
+/* 列表容器 */
+.sensor-list {
+  display: flex;
+  flex-direction: column;
+  gap: 15px; /* 组间距 */
+}
+/** 按钮 **/
+.control-bar {
+  background: url('@/assets/images/beltFire/yjkf/1-2title.png');
+  background-size: 100% 100%;
+  display: flex;
+  justify-content: space-around;
+  height: 50px;
+}
+.control-btn {
+  background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
+  border: 1px solid #40c4ff;
+  color: #fff;
+  font-size: 12px;
+  padding: 2px 8px;
+  height: 24px;
+  margin: auto;
+  box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+}
 
-  /* 分组卡片 */
-  .sensor-group {
-    background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
-    background-size: 100% 100%;
-    padding: 10px;
-  }
+/* 分组卡片 */
+.sensor-group {
+  background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
+  background-size: 100% 100%;
+  padding: 10px;
+}
 
-  /* 组标题 */
-  .group-title {
-    background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
-    background-size: 35% 100%;
+/* 组标题 */
+.group-title {
+  background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
+  background-size: 35% 100%;
+  color: #fff;
+  font-size: 12px;
+  font-weight: bold;
+  font-style: italic;
+  margin-bottom: 8px;
+  padding-bottom: 5px;
+  padding-left: 10px;
+  .check-btn {
     color: #fff;
     font-size: 12px;
-    font-weight: bold;
-    font-style: italic;
-    margin-bottom: 8px;
-    padding-bottom: 5px;
-    padding-left: 10px;
-    .check-btn {
-      color: #fff;
-      font-size: 12px;
-    }
   }
+}
+
+/* 列表项 */
+.sensor-item {
+  height: 30px;
+  background-size: 100% 100%;
+  display: flex;
+  align-items: center;
+  margin-bottom: 5px;
+  font-size: 13px;
+  color: #c0d0e0;
+  overflow-y: auto;
+  background-repeat: no-repeat;
+}
+.sensor-item.bg-1 {
+  background-image: url('@/assets/images/beltFire/yjkf/1-5.png');
+}
+.sensor-item.bg-2 {
+  background-image: url('@/assets/images/beltFire/yjkf/1-6.png');
+}
+.item-icon {
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  margin-left: 10px;
+}
+.item-icon.bg-1 {
+  background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
+}
+
+.item-icon.bg-2 {
+  background: url('@/assets/images/beltFire/yjkf/1-4wz.svg') no-repeat;
+}
+.container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+.dataInfo-item {
+  display: flex;
+  justify-content: space-around;
+  margin-bottom: 5px;
+  font-size: 13px;
+  width: calc(50% - 5px);
+  color: #c0d0e0;
+}
+
+.dataInfo-item:nth-child(1),
+.dataInfo-item:nth-child(4) {
+  background: url('@/assets/images/beltFire/yjkf/1-7.png') no-repeat;
+  background-size: 100% 100%;
+}
+
+.dataInfo-item:nth-child(2),
+.dataInfo-item:nth-child(3) {
+  background: url('@/assets/images/beltFire/yjkf/1-8.png') no-repeat;
+  background-size: 100% 100%;
+}
 
-  /* 列表项 */
-  .sensor-item {
+.item-status {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin: 0 15px 0 20px;
+  .item-label {
+    color: #fff;
     height: 30px;
-    background-size: 100% 100%;
-    display: flex;
-    align-items: center;
-    margin-bottom: 5px;
-    font-size: 13px;
-    color: #c0d0e0;
-    overflow-y: auto;
-    background-repeat: no-repeat;
-  }
-  .sensor-item.bg-1 {
-    background-image: url('@/assets/images/beltFire/yjkf/1-5.png');
-  }
-  .sensor-item.bg-2 {
-    background-image: url('@/assets/images/beltFire/yjkf/1-6.png');
-  }
-  .item-icon {
-    background-size: 100% 100%;
-    width: 20px;
-    height: 20px;
-    margin-left: 10px;
+    line-height: 30px;
   }
-  .item-icon.bg-1 {
-    background: url('@/assets/images/beltFire/yjkf/1-3area.svg') no-repeat;
+  .item-code {
+    height: 30px;
+    line-height: 30px;
+    text-align: right;
+    color: #91faff;
+    font-size: 12px;
+    font-family: 'douyuFont';
   }
+}
 
-  .item-icon.bg-2 {
-    background: url('@/assets/images/beltFire/yjkf/1-4wz.svg') no-repeat;
-  }
-  .container {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 10px;
-  }
-  .dataInfo-item {
-    display: flex;
-    justify-content: space-around;
-    margin-bottom: 5px;
-    font-size: 13px;
-    width: calc(50% - 5px);
-    color: #c0d0e0;
+.item-content {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  .label {
+    color: #fff;
   }
+}
 
-  .dataInfo-item:nth-child(1),
-  .dataInfo-item:nth-child(4) {
-    background: url('@/assets/images/beltFire/yjkf/1-7.png') no-repeat;
-    background-size: 100% 100%;
-  }
+.item-value {
+  margin-right: 10px;
+  font-size: 12px;
+  color: #36dae7;
+}
+.item-info {
+  color: #ffff;
+  font-size: 11px;
+}
 
-  .dataInfo-item:nth-child(2),
-  .dataInfo-item:nth-child(3) {
-    background: url('@/assets/images/beltFire/yjkf/1-8.png') no-repeat;
-    background-size: 100% 100%;
+/* 状态指示灯 */
+.status-dot {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  margin-left: 5px;
+  margin-top: 10px;
+  animation: pulse 2s infinite;
+  background: #3a3a3a;
+  // position: absolute;
+  // left: 0;
+  // top: 50%;
+  transform: translateY(-50%);
+  box-shadow: 0 0 6px 2px rgba(90, 90, 90, 0.6);
+  &.status-normal {
+    background-color: #00ff00;
+    box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
   }
 
-  .item-status {
-    width: 100%;
-    display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    margin: 0 15px 0 20px;
-    .item-label {
-      color: #fff;
-      height: 30px;
-      line-height: 30px;
-    }
-    .item-code {
-      height: 30px;
-      line-height: 30px;
-      text-align: right;
-      color: #91faff;
-      font-size: 12px;
-      font-family: 'douyuFont';
-    }
+  &.status-danger {
+    background-color: #ff4d4d;
+    box-shadow: 0 0 6px 2px rgb(255, 0, 0);
   }
+}
 
-  .item-content {
-    flex: 1;
-    display: flex;
-    align-items: center;
-    .label {
-      color: #fff;
-    }
+/* 动画效果 */
+@keyframes pulse {
+  0% {
+    transform: scale(1);
+    opacity: 1;
   }
-
-  .item-value {
-    margin-right: 10px;
-    font-size: 12px;
-    color: #36dae7;
+  50% {
+    transform: scale(1.2);
+    opacity: 0.8;
   }
-  .item-info {
-    color: #ffff;
-    font-size: 11px;
+  100% {
+    transform: scale(1);
+    opacity: 1;
   }
+}
 
-  /* 状态指示灯 */
-  .status-dot {
-    display: inline-block;
-    width: 10px;
-    height: 10px;
-    border-radius: 50%;
-    margin-left: 5px;
-    margin-top: 10px;
-    animation: pulse 2s infinite;
-    background: #3a3a3a;
-    // position: absolute;
-    // left: 0;
-    // top: 50%;
-    transform: translateY(-50%);
-    box-shadow: 0 0 6px 2px rgba(90, 90, 90, 0.6);
-    &.status-normal {
-      background-color: #00ff00;
-      box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
-    }
-
-    &.status-danger {
-      background-color: #ff4d4d;
-      box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
-      animation: flash 1s infinite;
-    }
+@keyframes flash {
+  0% {
+    opacity: 1;
   }
-
-  /* 动画效果 */
-  @keyframes pulse {
-    0% {
-      transform: scale(1);
-      opacity: 1;
-    }
-    50% {
-      transform: scale(1.2);
-      opacity: 0.8;
-    }
-    100% {
-      transform: scale(1);
-      opacity: 1;
-    }
+  50% {
+    opacity: 0.5;
   }
-
-  @keyframes flash {
-    0% {
-      opacity: 1;
-    }
-    50% {
-      opacity: 0.5;
-    }
-    100% {
-      opacity: 1;
-    }
+  100% {
+    opacity: 1;
   }
+}
 </style>

+ 1 - 1
src/views/vent/home/configurable/components/content.vue

@@ -199,7 +199,7 @@
         </template>
         <!-- 3. 火灾监测设备分析 -->
         <template v-if="config.name === 'sprayCtrl'">
-          <SprayControl class="content__module" :config="config.config" :data="data" />
+          <SprayControl class="content__module" :config="config.config" :data="config.data" />
         </template>
         <template v-if="config.name === 'cameraList'">
           <CameraList class="content__module" :config="config.config" :data="config.data" />