Pārlūkot izejas kodu

[Feat 0000]皮带巷代码迁移

bobo04052021@163.com 1 mēnesi atpakaļ
vecāks
revīzija
cde037bf6f

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

@@ -0,0 +1,377 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="border">
+      <customHeader>皮带巷三级防灭火系统</customHeader>
+      <div style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 0">
+        <SubApp />
+      </div>
+      <div class="box-container">
+        <ModuleCommon
+          v-for="cfg in configs"
+          :key="cfg.deviceType"
+          :show-style="cfg.showStyle"
+          :module-data="cfg.moduleData"
+          :module-name="cfg.moduleName"
+          :device-type="cfg.deviceType"
+          :data="readData"
+          :visible="true"
+        />
+      </div>
+      <!-- 巷道模型组件 -->
+    </div>
+  </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.Belt';
+import ModuleCommon from './components/ModuleCommonBelt.vue';
+import SubApp from '/@/components/vent/micro/createSubApp.vue';
+import { read } from 'fs';
+// import { BDFireMock } from './mock';
+const { configs, fetchConfigs } = useInitConfigs();
+const { updateEnhancedConfigs, updateData } = 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: '1#区域',
+          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: [
+    {
+      beltName: '测试1',
+      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: '在线',
+        },
+      ],
+    },
+    {
+      beltName: '测试2',
+      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();
+  });
+}
+// async function getDataSource() {
+//   const res = await list({ devicetype: 'belt', pagetype: 'normal' });
+//   let dataSource: any = [];
+//   dataSource = res.msgTxt[0] && res.msgTxt[0].datalist ? res.msgTxt[0].datalist[0] : {};
+//   if (dataSource) {
+//     readData.value = Object.assign(dataSource, dataSource.readData);
+//   }
+// }
+
+// 查询关联设备列表
+// async function getDeviceList() {
+//   const res = await systemList({ devicetype: 'sys', systemID: optionValue.value });
+//   const result = res.msgTxt;
+//   const deviceArr = <DeviceType[]>[];
+//   result.forEach((item) => {
+//     const data = item['datalist'].filter((data: any) => {
+//       const readData = data.readData;
+//       return Object.assign(data, readData);
+//     });
+//     if (item.type != 'sys') {
+//       deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data });
+//     }
+//   });
+//   deviceList.value = deviceArr;
+//   deviceActive.value = deviceArr[0].deviceType;
+//   deviceChange(0);
+// }
+
+function initInterval() {
+  setInterval(() => {
+    refresh();
+  }, 60000);
+}
+onMounted(() => {
+  refresh();
+  initInterval();
+});
+</script>
+
+<style lang="less" scoped>
+.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: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
+    margin-top: 50px;
+  }
+}
+</style>

+ 90 - 0
src/views/vent/home/configurable/belt/beltYjkf.vue

@@ -0,0 +1,90 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="border">
+      <customHeader>皮带巷智能管控</customHeader>
+      <div class="box-container">
+        <ModuleCommon
+          v-for="cfg in configs"
+          :key="cfg.deviceType"
+          :show-style="cfg.showStyle"
+          :module-data="cfg.moduleData"
+          :module-name="cfg.moduleName"
+          :device-type="cfg.deviceType"
+          :page-type="cfg.pageType"
+          :data="readData"
+          :visible="true"
+        />
+      </div>
+      <!-- 巷道模型组件 -->
+    </div>
+  </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 { testYjkf } from './configurable.data.Belt';
+import ModuleCommon from './components/ModuleCommonBelt.vue';
+
+import { read } from 'fs';
+// import { BDFireMock } from './mock';
+const { configs, fetchConfigs } = useInitConfigs();
+const { updateEnhancedConfigs, updateData } = useInitPage('皮带巷智能管控');
+// const readData = ref({});
+function refresh() {
+  fetchConfigs('belt').then(() => {
+    configs.value = testYjkf;
+    // Promise.resolve(readData).then(updateData);
+    // updateEnhancedConfigs(configs.value);
+    // getDataSource();
+  });
+}
+
+function initInterval() {
+  setInterval(() => {
+    refresh();
+  }, 60000);
+}
+onMounted(() => {
+  refresh();
+  initInterval();
+});
+</script>
+
+<style lang="less" scoped>
+.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: 94%;
+    background: url('/@/assets/images/beltFire/mainbj.png') no-repeat;
+    background-size: 100% 100%;
+    margin-top: 55px;
+  }
+}
+</style>

+ 108 - 0
src/views/vent/home/configurable/belt/components/ModuleCommonBelt.vue

@@ -0,0 +1,108 @@
+<template>
+  <!-- 常用模块 -->
+  <Transition
+    :enter-active-class="`animate__animated  animate__fadeIn${capitalizedPosition}`"
+    :leave-active-class="`animate__animated  animate__fadeOut${capitalizedPosition}`"
+  >
+    <ventBox1 v-if="visible" :class="getModuleClass(showStyle)" :style="style" :pageType="pageType">
+      <template v-if="moduleName" #title>
+        <div :class="{ 'cursor-pointer': !!moduleData.to }" style="font-weight: bold; font-style: italic" @click="redirectTo">{{ moduleName }}</div>
+      </template>
+      <template #container>
+        <slot>
+          <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="selectedData = $event" />
+          <Content
+            :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }"
+            :moduleData="moduleData"
+            :data="selectedData"
+            :chartData="chartData"
+          />
+        </slot>
+      </template>
+    </ventBox1>
+  </Transition>
+</template>
+<script lang="ts" setup>
+import Header from './headerBelt.vue';
+import Content from './contentBelt.vue';
+// import ModuleLeft from './original/moduleLeft.vue';
+// import ModuleBottom from './original/moduleBottom.vue';
+import { computed, ref } from 'vue';
+import ventBox1 from './ventBoxBelt.vue';
+import { openWindow } from '/@/utils';
+import { getFormattedText } from '../../hooks/helper';
+// 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 { header } = props.moduleData;
+const selectedData = ref();
+
+const style = computed(() => {
+  const size = props.showStyle.size;
+  const position = props.showStyle.position;
+  console.log(props.showStyle, '123123');
+  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';
+}
+
+function redirectTo() {
+  const { to } = props.moduleData;
+  if (!to) return;
+  openWindow(getFormattedText(selectedData.value, to));
+}
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.module-common .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-bottom) {
+    --image-box1-bottom: url('/@/assets/images/beltFire/1-2.png');
+    background-image: url('/@/assets/images/beltFire/1-2.png');
+  }
+}
+</style>

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

@@ -0,0 +1,377 @@
+<!-- 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 === 'list'">
+          <CustomListBelt class="content__module" :type="config.type" :list-config="config.items" />
+        </template>
+        <!-- 复杂列表部分 -->
+        <template v-if="config.name === 'complex_list'">
+          <ComplexListBelt class="content__module" :type="config.type" :list-config="config.items" />
+        </template>
+        <template v-if="config.name === 'complex_list1'">
+          <ComplexList1Belt class="content__module" :type="config.type" :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"
+            :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 { 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 mockData = clone(props.chartData) || [];
+  return layout.items.reduce((arr: any[], item) => {
+    switch (item.name) {
+      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);
+
+        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 'table': {
+        const cfg = table.shift();
+        if (!cfg) break;
+        const data = getData(refData, cfg.readFrom, cfg.parser);
+
+        arr.push({
+          ...cfg,
+          ...item,
+          columns: cfg.columns,
+          data,
+        });
+        console.log(arr, '11111111111');
+        break;
+      }
+      default: {
+        const cfg = preset.shift();
+        if (!cfg) break;
+        const data = getData(refData, cfg.readFrom, cfg.parser);
+
+        arr.push({
+          ...item,
+          data,
+          config: cfg,
+        });
+        break;
+      }
+    }
+    // console.log(arr,'arr---')
+    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/vent/homeNew/databg/4.png');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  height: 129px;
+  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>

+ 95 - 0
src/views/vent/home/configurable/belt/components/customHeader-belt.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="vent-custom-header">
+    <div class="vent-home-header">
+      <div class="header-text"><slot></slot></div>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+import { defineComponent, computed } from 'vue';
+import { Decoration5 } from '@kjgl77/datav-vue3';
+export default defineComponent({
+  name: 'CustomHeader',
+  components: { Decoration5 },
+  props: {},
+  emits: ['change'],
+});
+</script>
+<style lang="less">
+@import '/@/design/vent/modal.less';
+
+.@{ventSpace}-select-dropdown.drop {
+  background-color: transparent !important;
+
+  .@{ventSpace}-select-item-option-selected,
+  .@{ventSpace}-select-item-option-active {
+    background-color: #ffffff33 !important;
+  }
+  .@{ventSpace}-select-item {
+    color: inherit;
+    &:hover {
+      background-color: #ffffff33 !important;
+    }
+  }
+  .@{ventSpace}-select-tree {
+    .@{ventSpace}-select-tree-treenode {
+      color: inherit;
+    }
+    .@{ventSpace}-select-tree-switcher-icon {
+      color: inherit;
+    }
+  }
+}
+</style>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@ventSpace: zxm;
+
+.vent-custom-header {
+  --image-vent-header1: url('/@/assets/images/beltFire/top.png');
+  width: 100%;
+  position: relative;
+  z-index: 9999;
+  pointer-events: none;
+  .vent-home-header {
+    width: 100%;
+    position: fixed;
+    top: 0;
+    // background: url('/@/assets/images/vent/new-home/header-bg.png') no-repeat;
+    // height: 100px;
+    background: var(--image-vent-header1) no-repeat;
+    height: 89px;
+    background-size: contain;
+    display: flex;
+    justify-content: center;
+    .header-icon {
+      margin-top: 45px;
+    }
+    .header-text {
+      position: fixed;
+      top: 5px;
+      color: #fff;
+      font-size: 32px;
+      font-family: 'ysbtFont';
+      background-image: linear-gradient(#ffffff 50%, @vent-base-light-bg);
+      -webkit-background-clip: text;
+      color: transparent;
+    }
+  }
+}
+:deep(.zxm-select) {
+  width: 300px;
+  .@{ventSpace}-select-selector {
+    background: transparent !important;
+    border: none !important;
+    box-shadow: none !important;
+    .zxm-select-selection-item {
+      color: #fff !important;
+      font-size: 20px;
+    }
+  }
+  .@{ventSpace}-select-arrow {
+    color: #fff !important;
+  }
+}
+</style>

+ 131 - 0
src/views/vent/home/configurable/belt/components/detail/ComplexList-Belt1.vue

@@ -0,0 +1,131 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="list flex items-center" :class="`list_${type}`">
+    <div class="flex-grow" :class="`list_wrapper_${type}`">
+      <!-- 遍历每一组传感器数据 -->
+      <div v-for="(item, i) in listConfig" :key="`customlist${i}`" class="list-item" :class="`list-item_${type}`">
+        <div v-for="(ctx, j) in item.contents" :key="`vvhccdclc${j}`" :class="`list-item__content_${type} ${getBgClass(ctx.value)}`">
+          <div class="list-item__label"> {{ ctx.label }}</div>
+          <div class="list-item__value" :class="`list-item__value_${type}`">
+            {{ ctx.value }}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+withDefaults(
+  defineProps<{
+    listConfig: {
+      title: string;
+      contents: {
+        value: string;
+        color: string;
+        label?: string;
+        info?: string;
+      }[];
+    }[];
+    type: string;
+  }>(),
+  {
+    listConfig: () => [],
+    type: 'C',
+  }
+);
+
+const getBgClass = (riskLevel: string) => {
+  switch (riskLevel) {
+    case '低风险':
+      return 'bg-lowRisk';
+    case '一般风险':
+      return 'bg-normalRisk';
+    case '较大风险':
+      return 'bg-greaterRisk ';
+    case '重大风险':
+      return 'bg-majorRisk';
+    case '报警':
+      return 'bg-warning';
+    default:
+      return 'bg-lowRisk';
+  }
+};
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.list {
+  padding-left: 20px;
+  background-repeat: no-repeat;
+  position: relative;
+  display: flex;
+  align-items: center;
+  list-style: none;
+}
+
+.list-item_A {
+  align-items: center;
+  text-align: center;
+  margin: 10px 10px 17px 10px;
+  display: flex;
+  flex-direction: column; /* 竖排 */
+  gap: 5px; /* 间距 */
+}
+.list-item__content_A {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 35px;
+  padding: 0 12px;
+  color: #ffffff;
+  font-size: 13px;
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+}
+.list-item__content_A > .list-item__label {
+  padding-left: 40px;
+}
+.list-item__content_A > .list-item__value {
+  padding-right: 30px;
+  font-weight: bold;
+  font-style: italic;
+}
+.bg-lowRisk {
+  background-image: url('/@/assets/images/beltFire/lowRisk.png');
+}
+.bg-normalRisk {
+  background-image: url('/@/assets/images/beltFire/normalRisk.png');
+}
+.bg-greaterRisk {
+  background-image: url('/@/assets/images/beltFire/greaterRisk.png');
+}
+.bg-warning {
+  background-image: url('/@/assets/images/beltFire/warning.png');
+}
+.bg-majorRisk {
+  background-image: url('/@/assets/images/beltFire/majorRisk.png');
+}
+
+.list-item__content_A.bg-lowRisk .list-item__value {
+  color: #32ddff;
+}
+
+.list-item__content_A.bg-normalRisk .list-item__value {
+  color: #ffff00;
+}
+
+.list-item__content_A.bg-greaterRisk .list-item__value {
+  color: #ff9d17;
+}
+
+.list-item__content_A.bg-warning .list-item__value {
+  color: #ff0000;
+}
+
+.list-item__content_A.bg-majorRisk .list-item__value {
+  color: #ff3823;
+}
+</style>

+ 142 - 0
src/views/vent/home/configurable/belt/components/detail/ComplexListBelt.vue

@@ -0,0 +1,142 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="list flex items-center" :class="`list_${type}`">
+    <div class="flex-grow" :class="`list_wrapper_${type}`">
+      <!-- 遍历每一组传感器数据 -->
+      <div v-for="(item, i) in listConfig" :key="`customlist${i}`" class="list-item" :class="`list-item_${type}`">
+        <div v-for="(ctx, j) in item.contents" :key="`vvhccdclc${j}`" :class="`list-item__content_${type}`">
+          <div class="item-top">
+            <div class="sensor-icon"></div>
+            <div class="risk-text">{{ ctx.value }}</div>
+          </div>
+          <div class="item-bottom">
+            {{ ctx.label }}
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+withDefaults(
+  defineProps<{
+    listConfig: {
+      title: string;
+      contents: {
+        value: string;
+        color: string;
+        label?: string;
+        info?: string;
+      }[];
+    }[];
+    type: string;
+  }>(),
+  {
+    listConfig: () => [],
+    type: 'C',
+  }
+);
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.list {
+  padding-left: 20px;
+  background-repeat: no-repeat;
+  position: relative;
+  display: flex;
+  align-items: center;
+  list-style: none;
+}
+.list_wrapper_C {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 5px;
+}
+.list-item_C {
+  width: 80%;
+  padding: 5px 0;
+}
+
+.list-item__content_C {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  background-position: center;
+}
+
+.item-top {
+  width: 100%;
+  height: 80px;
+
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+}
+/* 外层list-item奇数时的图标 */
+.list-item:nth-child(odd) .list-item__content_C {
+  background-image: url('@/assets/images/beltFire/2-4.png');
+}
+
+/* 外层list-item偶数时的图标 */
+.list-item:nth-child(even) .list-item__content_C {
+  background-image: url('@/assets/images/beltFire/2-1.png');
+}
+/* 传感器图标 */
+.sensor-icon {
+  width: 100%;
+  height: 100%;
+  background-repeat: no-repeat;
+  background-size: 55% 100%;
+  background-position: center;
+  margin-bottom: 4px;
+}
+/* 外层list-item奇数时的图标 */
+.list-item:nth-child(odd) .sensor-icon {
+  background-image: url('@/assets/images/beltFire/2-5.png');
+}
+
+/* 外层list-item偶数时的图标 */
+.list-item:nth-child(even) .sensor-icon {
+  background-image: url('@/assets/images/beltFire/2-2.png');
+}
+/* 风险文字 */
+.risk-text {
+  white-space: nowrap;
+  width: 100%;
+  text-align: center;
+  color: #87ecf3;
+  font-size: 14px;
+  padding: 4px;
+  font-style: italic;
+  font-weight: bold;
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  background-position: center;
+}
+/* 外层list-item奇数时的图标 */
+.list-item:nth-child(odd) .risk-text {
+  background-image: url('@/assets/images/beltFire/2-3.png');
+}
+
+/* 外层list-item偶数时的图标 */
+.list-item:nth-child(even) .risk-text {
+  background-image: url('@/assets/images/beltFire/2-6.png');
+}
+
+/* 底部:传感器名称 */
+.item-bottom {
+  margin-bottom: 5px;
+  text-align: center;
+  color: #fff;
+  font-size: 12px;
+  line-height: 1.2;
+  width: 100%;
+}
+</style>

+ 144 - 0
src/views/vent/home/configurable/belt/components/detail/CustomListBelt.vue

@@ -0,0 +1,144 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="list flex" :class="`list_${type}`">
+    <div class="flex-grow" :class="`list__wrapper_${type}`">
+      <div v-for="(item, i) in listConfig" :key="`customlist${i}`" class="list-item" :class="`list-item_${type}`">
+        <div class="list-item__content" :class="`list-item__content_${type} ${getBgClass(item.value)}`">
+          <div class="list-item__label"> {{ item.label }}</div>
+          <div class="list-item__value" :class="`list-item__value_${type}`" v-if="item.label != '控制模式'">
+            <span v-if="item.label === '系统状态' || item.label === '运行状态'" class="status_dot"></span>
+            {{ item.value }}
+          </div>
+          <div class="list-item__value" :class="`list-item__value_${type}`" v-else>
+            <!-- 单选按钮组 -->
+            <div class="radio-group">
+              <label class="radio-label">
+                <input
+                  type="radio"
+                  :name="`mode_${i}`"
+                  value="auto"
+                  :checked="item.value === '自动'"
+                  @change="$emit('mode-change', { index: i, mode: '自动' })"
+                />
+                <span>自动</span>
+              </label>
+              <label class="radio-label">
+                <input
+                  type="radio"
+                  :name="`mode_${i}`"
+                  value="manual"
+                  :checked="item.value === '手动'"
+                  @change="$emit('mode-change', { index: i, mode: '手动' })"
+                />
+                <span>手动</span>
+              </label>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+withDefaults(
+  defineProps<{
+    listConfig: {
+      label: string;
+      value: string; // 低风险 | 一般风险 | 较大风险 | 严重风险 | 报警
+      color?: string;
+      info?: string;
+    }[];
+    type: string;
+  }>(),
+  {
+    listConfig: () => [],
+    type: 'A',
+  }
+);
+const getBgClass = (riskLevel: string) => {
+  switch (riskLevel) {
+    case '低风险':
+      return 'bg-lowRisk';
+    case '一般风险':
+      return 'bg-normalRisk';
+    case '较大风险':
+      return 'bg-greaterRisk ';
+    case '重大风险':
+      return 'bg-majorRisk';
+    case '报警':
+      return 'bg-warning';
+    default:
+      return 'bg-lowRisk';
+  }
+};
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+
+.list {
+  background-repeat: no-repeat;
+  position: relative;
+}
+
+.list-item_B {
+  align-items: center;
+  text-align: center;
+  margin: 20px;
+  display: flex;
+}
+.list-item__content_B {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 42px;
+  padding: 0 30px;
+  color: #ffffff;
+  font-size: 13px;
+  background-image: url('/@/assets/images/beltFire/3-1.png');
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+}
+.list-item__content_B > .list-item__label {
+  padding-top: 10px;
+  font-size: 14px;
+}
+.list-item__content_B > .list-item__value {
+  padding-top: 10px;
+  font-size: 14px;
+  font-weight: bold;
+  color: #fff;
+}
+.radio-group {
+  display: flex;
+  gap: 10px;
+  justify-content: center;
+  align-items: center;
+}
+
+.radio-label {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  cursor: pointer;
+  font-size: 14px;
+}
+
+.radio-label input[type='radio'] {
+  width: 16px;
+  height: 16px;
+  margin: 0;
+  cursor: pointer;
+}
+
+.status_dot {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  margin-right: 4px;
+  background-color: #46ff9c;
+}
+</style>

+ 171 - 0
src/views/vent/home/configurable/belt/components/detail/CustomTableBelt.vue

@@ -0,0 +1,171 @@
+<template>
+  <div class="table__content">
+    <div class="table__content_label" :class="`table__content_label_${type}`">
+      <div class="label-t" v-for="(item, index) in columns" :key="`svvhbcth-${index}`" :style="{ flexBasis }">{{ item.name }}</div>
+    </div>
+    <div ref="scrollRef" class="table__content_list" :class="`table__content_list_${type}`">
+      <div class="table__content_list_row" v-for="(item, index) in data" :key="`svvhbct-${index}`">
+        <div v-for="(t, i) in columns" :key="`svvhbctr-${i}`" :style="{ flexBasis }" :class="`table__content__list_item_${type}`">
+          <slot :name="t.prop" :scope="item">
+            <span>
+              <span
+                v-if="t.prop === 'frontDoorStatus' || t.prop === 'backDoorStatus' || t.prop === 'netStatus'"
+                :class="`status-dot ${getStatusClass(get(item, t.prop))}`"
+              ></span>
+              {{ get(item, t.prop) }}
+            </span>
+          </slot>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { computed, defineProps, ref } from 'vue';
+import _ from 'lodash';
+import { useAutoScroll } from '/@/hooks/core/useAutoScroll';
+
+let props = withDefaults(
+  defineProps<{
+    /** B | C */
+    type: string;
+    autoScroll: boolean;
+    /** 列表表头配置,每个prop都有其对应的slot来提供定制化功能 */
+    columns: { prop: string; name: string }[];
+    data: any[];
+    defaultValue: string;
+  }>(),
+  {
+    type: 'B',
+    autoScroll: false,
+    columns: () => [],
+    data: () => [],
+    defaultValue: '-',
+  }
+);
+
+const scrollRef = ref(null);
+if (props.autoScroll) {
+  useAutoScroll(scrollRef);
+}
+const getStatusClass = (status) => {
+  switch (status) {
+    case '在线':
+      return 'online';
+    case '开启':
+      return 'open';
+    case '关闭':
+    case '离线':
+      return 'offline';
+    default:
+      return '';
+  }
+};
+const flexBasis = computed(() => {
+  return Math.fround(100 / props.columns.length) + '%';
+});
+
+function get(o, p) {
+  const d = _.get(o, p);
+  return _.isNil(d) ? props.defaultValue : d === '' ? props.defaultValue : d;
+}
+</script>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@import '@/design/theme.less';
+
+@font-face {
+  font-family: 'douyuFont';
+  src: url('/@/assets/font/douyuFont.otf');
+}
+.table__content {
+  --image-content-label: url('/@/assets/images/beltFire/4-1.png');
+  --image-content-text: url('/@/assets/images/beltFire/4-2.png');
+  --image-content-label-d: url(/@/assets/images/home-container/configurable/minehome/content-label.png);
+  --image-content-body-d: url('/@/assets/images/home-container/configurable/minehome/content-body.png');
+  height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 5px 0;
+
+  .table__content_label {
+    padding: 10px;
+    width: 400px;
+    height: 32px;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+    .label-t {
+      text-align: center;
+      font-size: 14px;
+    }
+  }
+  .table__content_label_C {
+    background-position: center 100%;
+    background-size: 100% 40px;
+    background-repeat: no-repeat;
+    background-image: var(--image-content-label);
+    height: 40px;
+    .label-t {
+      background-repeat: no-repeat;
+      background-size: 80% auto;
+      background-position: center;
+      background-image: var(--image-list-head);
+    }
+  }
+
+  .table__content_list {
+    height: calc(100% - 32px);
+    width: 400px;
+    display: flex;
+    flex-direction: column;
+    padding: 5px 0;
+    box-sizing: border-box;
+    overflow-y: auto;
+    .table__content_list_row {
+      width: 100%;
+      display: flex;
+      justify-content: space-around;
+      align-items: center;
+      color: #fff;
+      margin-bottom: 5px;
+      span {
+        display: inline-block;
+        text-align: center;
+      }
+    }
+  }
+  .table__content_list_C {
+    .table__content_list_row {
+      min-height: 50px;
+      background-size: 100% auto;
+      background-repeat: no-repeat;
+      background-position: center bottom;
+      background-image: var(--image-content-text);
+    }
+  }
+
+  .status-dot {
+    display: inline-block;
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    margin-right: 4px;
+  }
+
+  .status-dot.online {
+    background-color: #46ff9c;
+  }
+
+  .status-dot.open {
+    background-color: #2cb6ff;
+  }
+
+  .status-dot.offline,
+  .status-dot.closed {
+    background-color: gray;
+  }
+}
+</style>

+ 95 - 0
src/views/vent/home/configurable/belt/components/headerBelt.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="vent-custom-header">
+    <div class="vent-home-header">
+      <div class="header-text"><slot></slot></div>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+import { defineComponent, computed } from 'vue';
+import { Decoration5 } from '@kjgl77/datav-vue3';
+export default defineComponent({
+  name: 'CustomHeader',
+  components: { Decoration5 },
+  props: {},
+  emits: ['change'],
+});
+</script>
+<style lang="less">
+@import '/@/design/vent/modal.less';
+
+.@{ventSpace}-select-dropdown.drop {
+  background-color: transparent !important;
+
+  .@{ventSpace}-select-item-option-selected,
+  .@{ventSpace}-select-item-option-active {
+    background-color: #ffffff33 !important;
+  }
+  .@{ventSpace}-select-item {
+    color: inherit;
+    &:hover {
+      background-color: #ffffff33 !important;
+    }
+  }
+  .@{ventSpace}-select-tree {
+    .@{ventSpace}-select-tree-treenode {
+      color: inherit;
+    }
+    .@{ventSpace}-select-tree-switcher-icon {
+      color: inherit;
+    }
+  }
+}
+</style>
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+@ventSpace: zxm;
+
+.vent-custom-header {
+  --image-vent-header1: url('/@/assets/images/beltFire/top.png');
+  width: 100%;
+  position: relative;
+  z-index: 9999;
+  pointer-events: none;
+  .vent-home-header {
+    width: 100%;
+    position: fixed;
+    top: 0;
+    // background: url('/@/assets/images/vent/new-home/header-bg.png') no-repeat;
+    // height: 100px;
+    background: var(--image-vent-header1) no-repeat;
+    height: 89px;
+    background-size: contain;
+    display: flex;
+    justify-content: center;
+    .header-icon {
+      margin-top: 45px;
+    }
+    .header-text {
+      position: fixed;
+      top: 5px;
+      color: #fff;
+      font-size: 32px;
+      font-family: 'ysbtFont';
+      background-image: linear-gradient(#ffffff 50%, @vent-base-light-bg);
+      -webkit-background-clip: text;
+      color: transparent;
+    }
+  }
+}
+:deep(.zxm-select) {
+  width: 300px;
+  .@{ventSpace}-select-selector {
+    background: transparent !important;
+    border: none !important;
+    box-shadow: none !important;
+    .zxm-select-selection-item {
+      color: #fff !important;
+      font-size: 20px;
+    }
+  }
+  .@{ventSpace}-select-arrow {
+    color: #fff !important;
+  }
+}
+</style>

+ 102 - 0
src/views/vent/home/configurable/belt/components/ventBoxBelt.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="vent-box1-bg">
+    <div class="box1-top" v-if="pageType !== 'beltYjkf1'">
+      <div class="title">
+        <slot name="title"></slot>
+      </div>
+    </div>
+    <div class="box1-center" :class="`box1-center-${pageType}`">
+      <div class="box-container">
+        <slot name="container"></slot>
+      </div>
+    </div>
+    <div class="box1-bottom" :class="`box1-bottom-${pageType}`"></div>
+  </div>
+</template>
+<script>
+import { defineComponent } from 'vue';
+export default defineComponent({
+  name: 'VentBox1',
+  props: {
+    pageType: {
+      type: String,
+    },
+  },
+  setup() {},
+});
+</script>
+
+<style lang="less" scoped>
+@import '/@/design/theme.less';
+.vent-box1-bg {
+  --image-box1-top: url('/@/assets/images/beltFire/1-1.png');
+  --image-box1-bottom: url('/@/assets/images/beltFire/1-2.png');
+  --image-box1-bottom1: url('/@/assets/images/beltFire/1-3.png');
+  --container-color: #00213236;
+  --container-image: linear-gradient(#3df6ff00, #3df6ff, #3df6ff00);
+  width: 100%;
+  min-height: 80px;
+  .box1-top {
+    width: 65%;
+    height: 35px;
+    margin-left: 20px;
+    background: var(--image-box1-top) no-repeat;
+    background-size: 100% 100%;
+    z-index: 2;
+    position: relative;
+    .title {
+      width: 100%;
+      height: 35px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #fff;
+    }
+  }
+  .box1-center {
+    width: 93%;
+    margin-left: 15px;
+    position: relative;
+    .box-container {
+      position: relative;
+      min-height: 50px;
+      padding: 10px;
+      color: #fff;
+      background-color: var(--container-color);
+      backdrop-filter: blur(5px);
+    }
+  }
+  .box1-top-beltYjkf1 {
+    margin-top: 12px;
+  }
+  .box1-center-beltYjkf {
+    height: calc(100% - 50px);
+    margin-top: 10px;
+  }
+  .box1-center-beltYjkf1 {
+    height: calc(100% - 73px);
+    margin-top: 50px;
+  }
+  .box1-bottom {
+    width: 100%;
+    height: 97%;
+    position: absolute;
+    bottom: 0px;
+    pointer-events: none;
+    z-index: -1 !important;
+  }
+  // 默认样式
+  .box1-bottom {
+    background: var(--image-box1-bottom) no-repeat;
+    background-size: 100% 100%;
+  }
+  .box1-bottom-beltYjkf1 {
+    background: var(--image-box1-bottom1) no-repeat;
+    background-size: 100% 100%;
+  }
+  .box1-bottom-beltYjkf {
+    background: var(--image-box1-bottom1) no-repeat;
+    background-size: 100% 100%;
+  }
+}
+</style>

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

@@ -0,0 +1,635 @@
+import { floor, isArray, random, slice } from 'lodash-es';
+import { defHttp } from '/@/utils/http/axios';
+import { get } from '../billboard/utils';
+import { useGlobSetting } from '/@/hooks/setting';
+import { reactive } from 'vue';
+import _ from 'lodash';
+
+enum Api {
+  list = '/safety/ventanalyDevice/homedata2',
+  getHomeData = '/safety/ventanalyDevice/homedata',
+  getDisHome = '/monitor/disaster/getDisHome',
+  getBDDustData = '/monitor/disaster/getDisDustHome',
+  // getBDFireData = '/monitor/disaster/getDisFireHome',
+  getDeviceSys = '/ventanaly-device/monitor/getSysFireHomeInfo',
+  getAlarmRecord = '/ventanaly-device/safety/ventanalyAlarmLog/sysLinkDevAlarmLog',
+  getTotal = '/safety/ventanalyAlarmLog/total',
+  sysTypeWarnList = '/safety/ventanalyAlarmLog/sysTypeWarn',
+  getDisasterProportion = '/safety/ventanalyAlarmLog/getDisasterProportion',
+  system = '/ventanaly-device/monitor/device',
+}
+
+// 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
+// 这会导致相同的请求被同时发送多次。
+const cache = new Map<string, Promise<any>>();
+
+/**
+ * 列表接口,5.5专用,和6.0的getHomeData基本一致
+ * @param params
+ */
+export const list = (params) => {
+  const key = `${Api.list}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.list, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    if (res.fanmain) {
+      // 处理频率字段,为了兼容旧版保留,现配置项已支持一级动态字段
+      res.fanmain.forEach((e) => {
+        if (e.readData.Fan2StartStatus === '1') {
+          e.current = '二号';
+          e.readData.FanFreqHz = e.readData.Fan2FreqHz;
+        } else {
+          e.current = '一号';
+          e.readData.FanFreqHz = e.readData.Fan1FreqHz;
+        }
+      });
+    }
+    if (res.fanlocal) {
+      res.fanlocal.forEach((e) => {
+        e.chartData = [
+          {
+            x: '吸风量',
+            yRealtime: e.readData.windQuantity1,
+            yMock: floor(parseFloat(e.inletAirVolume_merge) * random(0.98, 1, false), 2),
+            y: e.inletAirVolume_merge,
+          },
+          {
+            x: '供风量',
+            yRealtime: e.readData.windQuantity2,
+            yMock: floor(parseFloat(e.ductOutletAirVolume_merge) * random(0.98, 1, false), 2),
+            y: e.ductOutletAirVolume_merge,
+          },
+        ];
+        if (e.readData.Fan2StartStatus === '1') {
+          e.current = '二号';
+          e.readData.FanfHz = e.readData.Fan2fHz;
+        } else {
+          e.current = '一号';
+          e.readData.FanfHz = e.readData.Fan1fHz;
+        }
+      });
+    }
+    if (res.sys_majorpath) {
+      res.sys_majorpath.forEach((e) => {
+        const { drag_1, drag_2, drag_3, drag_total } = e.majorpath;
+        const { fy_merge = { value: '1' } } = e.readData;
+        const drag_merge = parseInt(fy_merge.value);
+        // const m3_merge = parseInt(retM3_merge.value);
+
+        e.piechart = [
+          { val: drag_1, valMock: floor((drag_1 / drag_total) * drag_merge), label: '进风区' },
+          { val: drag_2, valMock: floor((drag_2 / drag_total) * drag_merge), label: '用风区' },
+          { val: drag_3, valMock: floor((drag_3 / drag_total) * drag_merge), label: '回风区' },
+        ];
+        e.readData.dengjikong_merge = get(res, 'midinfo[0].sysinfo.equalarea');
+        e.readData.fy_merge_int = drag_merge;
+        // e.dengjikong_merge = floor((1.19 * (m3_merge / 60)) / Math.sqrt(drag_merge), 2);
+      });
+    }
+    if (res.sys_surface_caimei) {
+      res.sys_surface_caimei.forEach((e) => {
+        if (isArray(e.history)) {
+          e.history = slice(e.history, e.history.length - 30, e.history.length);
+        }
+        if (isArray(e.history_report)) {
+          e.history_report = slice(e.history_report, e.history_report.length - 30, e.history_report.length);
+          console.log(e, '999000');
+        }
+      });
+    }
+    if (res.device_arr) {
+      res.device_arr = Object.values(res.device);
+    }
+    if (res.sys_wind) {
+      res.sys_wind.forEach((e) => {
+        if (e.readData.m3) {
+          e.readData.m3 = e.readData.m3.replace('-', '');
+        }
+        if (e.readData.va) {
+          e.readData.va = e.readData.va.replace('-', '');
+        }
+      });
+    }
+    if (res.windrect) {
+      res.windrect.forEach((e) => {
+        if (e.readData.m3) {
+          e.readData.m3 = e.readData.m3.replace('-', '');
+        }
+        if (e.readData.va) {
+          e.readData.va = e.readData.va.replace('-', '');
+        }
+      });
+    }
+    if (res.safetymonitor) {
+      const { sysOrgCode } = useGlobSetting();
+      // 沙坪
+      if (sysOrgCode === 'jsnyspmy') {
+        res.safetymonitor = _.sortBy(res.safetymonitor, (e) => {
+          const map = new Map([
+            ['1960160466651189249', 1],
+            ['1960160465543892994', 2],
+            ['1960160465376120833', 3],
+            ['1960160466168844289', 4],
+            ['1960160465736830977', 5],
+            ['1960160466026237954', 6],
+            ['1960160407146598402', 7],
+          ]);
+
+          const inx = map.get(e.deviceID) || 9999;
+
+          return inx;
+        });
+      }
+    }
+
+    return res;
+  });
+};
+
+export const getHomeData = (params) => {
+  const key = `${Api.getHomeData}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getHomeData, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    res.fanmain.forEach((e) => {
+      if (e.readData.Fan2StartStatus === '1') {
+        e.current = '二号';
+        e.readData.FanFreqHz = e.readData.Fan2FreqHz;
+      } else {
+        e.current = '一号';
+        e.readData.FanFreqHz = e.readData.Fan1FreqHz;
+      }
+    });
+    res.fanlocal.forEach((e) => {
+      e.chartData = [
+        {
+          x: '吸风量',
+          y: e.readData.windQuantity1,
+        },
+        {
+          x: '供风量',
+          y: e.readData.windQuantity2,
+        },
+      ];
+      if (e.readData.Fan2StartStatus === '1') {
+        e.current = '二号';
+        e.readData.FanfHz = e.readData.Fan2fHz;
+      } else {
+        e.current = '一号';
+        e.readData.FanfHz = e.readData.Fan1fHz;
+      }
+    });
+    res.sys_majorpath.forEach((e) => {
+      e.piechart = [
+        { val: e.majorpath.drag_1, label: '进风区' },
+        { val: e.majorpath.drag_2, label: '用风区' },
+        { val: e.majorpath.drag_3, label: '回风区' },
+      ];
+    });
+
+    return res;
+  });
+};
+
+export const getBDDustData = (params) => {
+  const key = `${Api.getBDDustData}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getBDDustData, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return cache.get(key) as Promise<any>;
+};
+
+// 塔山火灾预警页面获取数据接口
+export const getDeviceSys = (params) => {
+  const key = `${Api.getDeviceSys}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getDeviceSys, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    return res;
+  });
+};
+
+export const getAlarmRecord = (params) => {
+  const key = `${Api.getAlarmRecord}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getAlarmRecord, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    return res;
+  });
+};
+
+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;
+  }
+}
+
+/**
+ * 映射 obfObj.arrayDev 数据的工具函数,减少重复代码
+ * @param {Array} devArray - 设备数组
+ * @param {string} valKey - 要取值的字段名
+ * @returns {Array} 映射后的数组
+ */
+function mapObfDev(devArray, valKey) {
+  return devArray.map((e) => ({
+    strinstallpos: e.strinstallpos,
+    val: e[valKey] || 0,
+  }));
+}
+//获取通风监测预警图表数据
+export const sysTypeWarnList = (params) => {
+  const key = `${Api.sysTypeWarnList}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.sysTypeWarnList, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    return res;
+  });
+};
+//获取多灾融合预警-风险权重比例数据
+export const getDisasterProportion = (params) => {
+  const key = `${Api.getDisasterProportion}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getDisasterProportion, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    return res;
+  });
+};
+
+//多灾融合预警
+function getLevelNum() {
+  return new Promise(async (resolve) => {
+    const list: Record<string, any> = {};
+    const typeArr = ['fire', 'dust', 'vent', 'gas'];
+    for (let i = 0; i < typeArr.length; i++) {
+      const type = typeArr[i];
+      const result = await sysTypeWarnList({ type });
+      if (type == 'fire') {
+        list.fire = result.length || 0;
+      } else if (type == 'dust') {
+        list.dust = result.length || 0;
+      } else if (type == 'vent') {
+        list.vent = result.length || 0;
+      } else if (type == 'gas') {
+        list.gas = result.length || 0;
+      }
+    }
+    resolve(list);
+  });
+}
+export const getTotal = (params) => {
+  const { sysDataType } = useGlobSetting();
+
+  const key = `${Api.getTotal}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.get({ url: Api.getTotal, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then(async (res) => {
+    console.log(res, '多灾融合预警数据');
+
+    let dataVent = await getLevelNum();
+    const levelsList = [
+      {
+        name: '报警',
+        value: 0,
+      },
+      {
+        name: '重大风险',
+        value: 0,
+      },
+      {
+        name: '较大风险',
+        value: 0,
+      },
+      {
+        name: '一般风险',
+        value: 0,
+      },
+      {
+        name: '低风险',
+        value: dataVent.vent || 0,
+      },
+    ];
+    //通风监测预警数据
+    switch (sysDataType) {
+      case 'monitor':
+        res.ventWarn = {
+          ventJf: res.ventInfo.zongjinfeng,
+          ventXf: res.ventInfo.xufengliang,
+          ventHf: res.ventInfo.zonghuifeng,
+        };
+        res.ventData = [
+          {
+            name: '报警',
+            value: res.info.sysInfo.ventS.levels.alarm,
+          },
+          {
+            name: '重大风险',
+            value: res.info.sysInfo.ventS.levels.red,
+          },
+          {
+            name: '较大风险',
+            value: res.info.sysInfo.ventS.levels.orange,
+          },
+          {
+            name: '一般风险',
+            value: res.info.sysInfo.ventS.levels.yellow,
+          },
+          {
+            name: '低风险',
+            value: dataVent.vent ? dataVent.vent : res.info.sysInfo.ventS.levels.blue,
+          },
+        ];
+
+        break;
+      case 'report':
+        res.ventWarn = {
+          ventJf: res.ventInfo.totalIntM3,
+          ventXf: res.ventInfo.xufengliang,
+          ventHf: res.ventInfo.totalRetM3,
+        };
+        res.ventData = levelsList;
+        break;
+      default:
+        res.ventWarn = {
+          ventJf: res.ventInfo.totalIntM3,
+          ventXf: res.ventInfo.xufengliang,
+          ventHf: res.ventInfo.totalRetM3,
+        };
+        res.ventData = levelsList;
+    }
+    //设备监测预警数据
+    res.deviceWarn = reactive({});
+    Object.keys(res.info.devicekindInfo).forEach((el) => {
+      res.deviceWarn[`${el}_all`] = res.info.devicekindInfo[el].totalcount;
+      res.deviceWarn[`${el}_warn`] = res.info.devicekindInfo[el].count;
+      res.deviceWarn[`${el}_close`] = res.info.devicekindInfo[el].netstatus;
+    });
+    //瓦斯监测预警数据
+    res.gasData = reactive({});
+    res.gasData.safety_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.gasNumber, 0);
+    res.gasData.gas_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.pumpNumber, 0);
+    res.gasData.monitorData = res.info.sysInfo.gasS.devices.map((el) => {
+      return {
+        label: el.systemname,
+        value: el.gasNumber,
+        value1: el.pumpNumber,
+      };
+    });
+
+    //火灾监测预警数据
+    res.fireInfos = reactive({});
+    res.fireInfos.dataOn = [];
+
+    if (res.bundletubeInfo && res.bundletubeInfo.msgTxt.length != 0 && res.bundletubeInfo.msgTxt[0].datalist.length != 0) {
+      res.bundletubeInfo.msgTxt[0].datalist.forEach((el) => {
+        res.fireInfos.dataOn.push({
+          warnLevel: el.syswarnLevel_str,
+          smokeJd: el.syswarnLevel_des,
+          value1: el.strinstallpos,
+        });
+      });
+    } else {
+      res.fireInfos.dataOn = [];
+    }
+    res.fireInfos.tempVal = res.info.sysInfo.fireS.summaryInfo
+      ? res.info.sysInfo.fireS.summaryInfo.external.temperature && res.info.sysInfo.fireS.summaryInfo.external.temperature.maxlevel == '0'
+        ? '低风险'
+        : '低风险'
+      : '';
+    res.fireInfos.smokeVal = res.info.sysInfo.fireS.summaryInfo
+      ? res.info.sysInfo.fireS.summaryInfo.external.smokeval &&
+        res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel &&
+        res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel == '0'
+        ? '低风险'
+        : '低风险'
+      : '';
+
+    res.fireInfos.fireVal = res.info.sysInfo.fireS.summaryInfo
+      ? res.info.sysInfo.fireS.summaryInfo.external.fireval &&
+        res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel &&
+        res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel == '0'
+        ? '低风险'
+        : '低风险'
+      : '';
+
+    res.fireInfos.coVal = res.info.sysInfo.fireS.summaryInfo
+      ? res.info.sysInfo.fireS.summaryInfo.external.coval && res.info.sysInfo.fireS.summaryInfo.external.coval.value
+        ? res.info.sysInfo.fireS.summaryInfo.external.coval.value
+        : '-'
+      : '';
+    //粉尘监测预警数据
+    res.dustInfo = [
+      {
+        name: '报警',
+        value: res.info.sysInfo.dustS.levels.alarm,
+      },
+      {
+        name: '重大风险',
+        value: res.info.sysInfo.dustS.levels.red,
+      },
+      {
+        name: '较大风险',
+        value: res.info.sysInfo.dustS.levels.orange,
+      },
+      {
+        name: '一般风险',
+        value: res.info.sysInfo.dustS.levels.yellow,
+      },
+      {
+        name: '低风险',
+        value: dataVent.dust ? dataVent.dust : res.info.sysInfo.dustS.levels.blue,
+      },
+    ];
+
+    return res;
+  });
+};
+
+//机电硐室
+export const getElectroData = (params) => {
+  const key = `${Api.system}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.system, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then(async (res) => {
+    let data = res.msgTxt.find((el) => el.type == 'ballvalve_auto');
+    data.tempData = data?.datalist?.map((el, index) => {
+      return {
+        areaName: el.readData.areaName,
+        tempStart: el.readData.tempStart,
+        tempStop: el.readData.tempStop,
+        CORealtime: el.readData.CORealtime,
+      };
+    });
+    if (data?.datalist) {
+      data.datalist.forEach((el) => {
+        el.cardData = {
+          title: el.strinstallpos,
+          areaText: '区域',
+          areaVal: el.readData.areaName,
+          moduleText: '模式',
+          moduleVal: el.readData.smokePattern,
+          statusText: '烟雾传感器状态',
+          statusVal: el.readData.smokeSensorStatus == 'False' ? '正常-低电平' : '异常',
+          phoneText: '机号',
+          phoneVal: el.readData.deviceName,
+          tempNowText: '实时测温',
+          tempNowVal: el.readData.tempRealtime,
+          tempOpenText: '开启温度',
+          tempOpenVal: el.readData.tempStart,
+          timeText: '延时t1',
+          timeVal: 0,
+          tempMaxText: '最高温度',
+          tempMaxVal: el.readData.tempMax,
+          tempCloseText: '关闭温度',
+          tempCloseVal: el.readData.tempMin,
+          time3Text: '延时t3',
+          time3Val: 0,
+          deviceSTAT: el.readData.deviceSTAT == '1' ? true : false,
+        };
+      });
+      data.chartData = data.datalist.map((el) => {
+        return {
+          time: el.readData.areaName,
+          coRealTime: el.readData.CORealtime,
+          coWarn: el.readData.COWarn,
+        };
+      });
+    }
+    return data;
+  });
+};

+ 441 - 0
src/views/vent/home/configurable/belt/configurable.data.Belt.ts

@@ -0,0 +1,441 @@
+import { Config } from '../../deviceManager/configurationTable/types';
+
+// 皮带巷三级防灭火首页
+export const testBeltLaneFire: Config[] = [
+  {
+    deviceType: 'pdhzfxInfo',
+    moduleName: '皮带火灾风险状态整体评价',
+    pageType: 'belt',
+    moduleData: {
+      header: {
+        show: false,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'column',
+        items: [
+          {
+            name: 'complex_list1',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [],
+      complex_list: [],
+      complex_list1: [
+        {
+          type: 'A',
+          readFrom: 'pdhzfxInfo[0].sysList',
+          mapFromData: true,
+          items: [
+            {
+              title: '',
+              contents: [
+                {
+                  label: '${beltName}',
+                  value: '${warnlevel}',
+                  info: '',
+                },
+              ],
+            },
+          ],
+        },
+        // {
+        //   type: 'C',
+        //   readFrom: 'sysList',
+        //   mapFromData: true,
+        //   items: [
+        //     {
+        //       title: '',
+        //       contents: [
+        //         {
+        //           label: '${beltName}',
+        //           value: '${warnlevel}',
+        //           info: '',
+        //         },
+        //       ],
+        //     },
+        //   ],
+        // },
+      ],
+      preset: [],
+      to: '/micro-vent-3dModal/beltYjkf/index',
+    },
+    showStyle: {
+      size: 'width:430px;height:350px;',
+      version: '原版',
+      position: 'top:30px;left:25px;',
+    },
+  },
+  {
+    deviceType: 'fmhjcInfo',
+    moduleName: '防灭火检测与预警信息',
+    pageType: 'belt',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'column',
+        items: [
+          {
+            name: 'complex_list',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [],
+      complex_list: [
+        {
+          type: 'C',
+          readFrom: 'sysList',
+          mapFromData: true,
+          items: [
+            {
+              title: '',
+              contents: [
+                {
+                  label: '${deviceType}',
+                  value: '${warnLevel}',
+                  info: '',
+                },
+              ],
+            },
+          ],
+        },
+      ],
+      preset: [],
+      // mock: BDfireMock,
+    },
+    showStyle: {
+      size: 'width:430px;height:430px;',
+      version: '原版',
+      position: 'top:415px;left:25px;',
+    },
+  },
+  {
+    deviceType: 'plmhInfo',
+    moduleName: '喷淋灭火系统',
+    pageType: 'belt',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'column',
+        items: [
+          {
+            name: 'list',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [
+        {
+          type: 'B',
+          readFrom: 'sysList',
+          items: [
+            {
+              label: '系统状态',
+              value: '${[0].netstatus}',
+              trans: {
+                '0': '离线',
+                '1': '正常',
+              },
+              color: 'blue',
+              info: '',
+            },
+            {
+              label: '运行状态',
+              value: '${[0].yxzt}',
+              trans: {
+                '0': '未喷淋',
+                '1': '正在喷淋',
+              },
+              color: 'blue',
+              info: '',
+            },
+            {
+              label: '喷淋水压状态',
+              value: '${[0].plsy}',
+              color: 'blue',
+              info: '',
+            },
+            {
+              label: '控制模式',
+              value: '${[0].kzms}',
+              color: 'blue',
+              info: '',
+            },
+          ],
+        },
+      ],
+      complex_list: [],
+      preset: [
+        {
+          readFrom: '',
+        },
+      ],
+      // mock: BDfireMock,
+    },
+    showStyle: {
+      size: 'width:430px;height:350px;',
+      version: '原版',
+      position: 'top:30px;right:25px;',
+    },
+  },
+  {
+    deviceType: 'yjkfArray',
+    moduleName: '应急控风减灾',
+    pageType: 'belt',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'row',
+        items: [
+          {
+            name: 'table',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [
+        {
+          type: 'C',
+          readFrom: 'aqjkData',
+          columns: [
+            {
+              name: '设备位置',
+              prop: 'deviceName',
+            },
+            {
+              name: '前门状态',
+              prop: 'frontDoorStatus',
+            },
+            {
+              name: '后门状态',
+              prop: 'backDoorStatus',
+            },
+            {
+              name: '网络状态',
+              prop: 'netStatus',
+            },
+          ],
+        },
+      ],
+      list: [],
+      complex_list: [],
+      preset: [],
+    },
+    showStyle: {
+      size: 'width:430px;height:430px;',
+      version: '原版',
+      position: 'top:415px;right:25px;',
+    },
+  },
+];
+export const testYjkf: Config[] = [
+  {
+    deviceType: 'plmhInfo',
+    moduleName: '',
+    pageType: 'beltYjkf1',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'column',
+        items: [
+          {
+            name: 'list',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [
+        {
+          type: 'B',
+          readFrom: 'sysList',
+          items: [],
+        },
+      ],
+      complex_list: [],
+      preset: [
+        {
+          readFrom: '',
+        },
+      ],
+      // mock: BDfireMock,
+    },
+    showStyle: {
+      size: 'width:440px;height:830px;',
+      version: '原版',
+      position: 'top:10px;left:25px;',
+    },
+  },
+  {
+    deviceType: 'yjkfArray',
+    moduleName: '摄像头视频信号',
+    pageType: 'beltYjkf',
+    moduleData: {
+      header: {
+        show: true,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'row',
+        items: [
+          {
+            name: 'table',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [
+        {
+          type: 'C',
+          readFrom: 'aqjkData',
+          columns: [
+            {
+              name: '设备位置',
+              prop: 'deviceName',
+            },
+            {
+              name: '前门状态',
+              prop: 'frontDoorStatus',
+            },
+            {
+              name: '后门状态',
+              prop: 'backDoorStatus',
+            },
+            {
+              name: '网络状态',
+              prop: 'netStatus',
+            },
+          ],
+        },
+      ],
+      list: [],
+      complex_list: [],
+      preset: [],
+      // mock: BDfireMock,
+    },
+    showStyle: {
+      size: 'width:440px;height:820px;',
+      version: '原版',
+      position: 'top:20px;right:25px;',
+    },
+  },
+];

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

@@ -351,40 +351,7 @@ export const testYjkf: Config[] = [
         {
           type: 'B',
           readFrom: 'sysList',
-          items: [
-            {
-              label: '系统状态',
-              value: '${[0].netstatus}',
-              trans: {
-                '0': '离线',
-                '1': '正常',
-              },
-              color: 'blue',
-              info: '',
-            },
-            {
-              label: '运行状态',
-              value: '${[0].yxzt}',
-              trans: {
-                '0': '未喷淋',
-                '1': '正在喷淋',
-              },
-              color: 'blue',
-              info: '',
-            },
-            {
-              label: '喷淋水压状态',
-              value: '${[0].plsy}',
-              color: 'blue',
-              info: '',
-            },
-            {
-              label: '控制模式',
-              value: '${[0].kzms}',
-              color: 'blue',
-              info: '',
-            },
-          ],
+          items: [],
         },
       ],
       complex_list: [],