Explorar o código

[Feat 0000]三级防灭火子页面开发

bobo04052021@163.com hai 2 meses
pai
achega
6205df77c5
Modificáronse 25 ficheiros con 1372 adicións e 881 borrados
  1. BIN=BIN
      src/assets/images/beltFire/fireMonitor/2-1.png
  2. 9 0
      src/assets/images/beltFire/fireMonitor/2-10.svg
  3. BIN=BIN
      src/assets/images/beltFire/fireMonitor/2-11.png
  4. BIN=BIN
      src/assets/images/beltFire/fireMonitor/2-12.png
  5. BIN=BIN
      src/assets/images/beltFire/fireMonitor/2-2.png
  6. BIN=BIN
      src/assets/images/beltFire/fireMonitor/2-4.png
  7. 14 0
      src/assets/images/beltFire/fireMonitor/2-5.svg
  8. 11 0
      src/assets/images/beltFire/yjkf/1-3area.svg
  9. BIN=BIN
      src/assets/images/beltFire/yjkf/1-6.png
  10. BIN=BIN
      src/assets/images/beltFire/yjkf/1-7.png
  11. BIN=BIN
      src/assets/images/beltFire/yjkf/1-8.png
  12. 4 1
      src/views/vent/deviceManager/configurationTable/types.ts
  13. 51 27
      src/views/vent/home/configurable/belt/belt-new.vue
  14. 55 59
      src/views/vent/home/configurable/belt/belt.vue
  15. 0 1
      src/views/vent/home/configurable/belt/components/contentBelt.vue
  16. 31 40
      src/views/vent/home/configurable/belt/components/detail/gateBoard.vue
  17. 189 23
      src/views/vent/home/configurable/belt/configurable.data.ts
  18. 96 0
      src/views/vent/home/configurable/components/belt/CameraList.vue
  19. 156 147
      src/views/vent/home/configurable/components/belt/FireSensorAnalysis.vue
  20. 99 105
      src/views/vent/home/configurable/components/belt/SensorStatusPanel.vue
  21. 280 0
      src/views/vent/home/configurable/components/belt/SprayControl.vue
  22. 334 284
      src/views/vent/home/configurable/components/belt/VehicleCOAnalysis.vue
  23. 14 5
      src/views/vent/home/configurable/components/belt/WarningResultList.vue
  24. 29 18
      src/views/vent/home/configurable/components/content.vue
  25. 0 171
      src/views/vent/home/configurable/components/detail/CustomTableBelt.vue

BIN=BIN
src/assets/images/beltFire/fireMonitor/2-1.png


+ 9 - 0
src/assets/images/beltFire/fireMonitor/2-10.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15.061" height="13.303" viewBox="0 0 15.061 13.303">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.295" x2="0.946" y2="0.843" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#83e4ff"/>
+      <stop offset="1" stop-color="#fff"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_57939" data-name="路径 57939" d="M181.213,223v-.879h1.758V223h1.758v1.758H182.97v.879h-1.758v-.879H170.667V223Zm-4.394-4.394v-.879h1.758v.879h6.152v1.758h-6.152v.879h-1.758v-.879h-6.152v-1.758Zm-4.394-4.394v-.879h1.758v.879h10.546v1.758H174.182v.879h-1.758v-.879h-1.758v-1.758Z" transform="translate(-170.167 -212.833)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

BIN=BIN
src/assets/images/beltFire/fireMonitor/2-11.png


BIN=BIN
src/assets/images/beltFire/fireMonitor/2-12.png


BIN=BIN
src/assets/images/beltFire/fireMonitor/2-2.png


BIN=BIN
src/assets/images/beltFire/fireMonitor/2-4.png


+ 14 - 0
src/assets/images/beltFire/fireMonitor/2-5.svg

@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.365" height="27.914" viewBox="0 0 24.365 27.914">
+  <defs>
+    <filter id="多边形_5" x="0" y="0" width="24.365" height="27.914" filterUnits="userSpaceOnUse">
+      <feOffset input="SourceAlpha"/>
+      <feGaussianBlur stdDeviation="3" result="blur"/>
+      <feFlood flood-color="#3df6ff"/>
+      <feComposite operator="in" in2="blur"/>
+      <feComposite in="SourceGraphic"/>
+    </filter>
+  </defs>
+  <g transform="matrix(1, 0, 0, 1, 0, 0)" filter="url(#多边形_5)">
+    <path id="多边形_5-2" data-name="多边形 5" d="M4.957,0,9.914,6.365H0Z" transform="translate(15.37 9) rotate(90)" fill="#3df6ff"/>
+  </g>
+</svg>

+ 11 - 0
src/assets/images/beltFire/yjkf/1-3area.svg

@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20.602" height="16.199" viewBox="0 0 20.602 16.199">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" y1="1" x2="0.5" y2="0.083" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#abdcff"/>
+      <stop offset="1" stop-color="#fff"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13144" data-name="组 13144" transform="translate(0 0)">
+    <path id="路径_57953" data-name="路径 57953" d="M64.512,208.711v-14.74l5.886-1.46v14.716Zm7.346-1.483V192.512l5.91,1.46v14.74Zm7.37-13.256,5.886-1.46v14.716l-5.886,1.483Z" transform="translate(-64.512 -192.512)" fill="url(#linear-gradient)"/>
+  </g>
+</svg>

BIN=BIN
src/assets/images/beltFire/yjkf/1-6.png


BIN=BIN
src/assets/images/beltFire/yjkf/1-7.png


BIN=BIN
src/assets/images/beltFire/yjkf/1-8.png


+ 4 - 1
src/views/vent/deviceManager/configurationTable/types.ts

@@ -106,7 +106,9 @@ export interface ModuleData {
         | 'sensor_status'
         | 'fire_sensor_analysis'
         | 'warning_result'
-        | 'vehicle_co_analysis';
+        | 'vehicle_co_analysis'
+        | 'sprayCtrl'
+        | 'cameraList';
       /** 分区大小 */
       basis: string;
       overflow?: boolean;
@@ -364,6 +366,7 @@ export interface ModuleDataTable extends ReadFrom {
     /** 取值 prop,注意该项不支持 formatter 格式 */
     prop: string;
   }[];
+  pageType?: string;
 }
 
 export interface ModuleDataPreset extends ReadFrom {

+ 51 - 27
src/views/vent/home/configurable/belt/belt-new.vue

@@ -23,7 +23,20 @@
         />
       </template>
       <template v-if="pageType == 'emergencyControl'">
-        <ModuleCommon1
+        <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="data"
+          :visible="true"
+        />
+      </template>
+      <template v-if="pageType == 'sprayControl'">
+        <ModuleCommon
           v-for="cfg in configs"
           :key="cfg.deviceType"
           :show-style="cfg.showStyle"
@@ -43,10 +56,9 @@
 import { onMounted, ref, watch, computed } from 'vue';
 import customHeader from './components/customHeader-belt.vue';
 import { useInitConfigs, useInitPage } from '../hooks/useInit';
-import { testBeltNew, testYjkf } from './configurable.data';
+import { testBeltNew, testYjkf, testSpary } from './configurable.data';
 import ModuleCommon from './components/ModuleCommon.vue';
 import ModuleCommon1 from './components/ModuleCommonBelt.vue';
-import { is } from '/@/utils/is';
 import BeltNav from './components/BeltNav.vue';
 import { config } from 'process';
 import { useRouter, useRoute } from 'vue-router';
@@ -106,6 +118,14 @@ const readData = {
           advice: '立即检查该区域设备,启动应急预案',
           action: '启动喷淋',
         },
+        {
+          time: '2026-03-21 13:23:34',
+          area: '3#皮带区域',
+          type: 'CO浓度异常',
+          status: '三级预警',
+          advice: '立即检查该区域设备,启动应急预案',
+          action: '启动喷淋',
+        },
       ],
     },
   ],
@@ -152,33 +172,30 @@ const readData = {
     possibleCause: '皮带摩擦过热或电器设备故障',
     recommendation: '立即检查3#皮带区域设备',
   },
-  doorData: [
+  sprayData: [
     {
-      id: 1,
-      position: '16联巷短路风门',
-      frontStatus: '关闭',
-      backStatus: '关闭',
-      networkStatus: '在线',
-      modelImg: '',
-      open: true,
+      beltArea: '1#皮带区域',
+      devicePosition: '1#皮带-50m处',
+      netStatus: '0', // 网络状态:0=断开,1=连接
+      runStatus: '1', // 运行状态:0=异常,1=正常
+      waterVolume: 86,
+      waterPressure: 1.4,
     },
     {
-      id: 2,
-      position: '18联巷短路风门',
-      frontStatus: '打开',
-      backStatus: '打开',
-      networkStatus: '在线',
-      modelImg: '',
-      open: true,
+      beltArea: '2#皮带区域',
+      devicePosition: '2#皮带-120m处',
+      netStatus: '1',
+      runStatus: '1',
+      waterVolume: 72,
+      waterPressure: 0.8,
     },
     {
-      id: 3,
-      position: '23联巷短路风门',
-      frontStatus: '关闭',
-      backStatus: '关闭',
-      networkStatus: '在线',
-      modelImg: '',
-      open: false,
+      beltArea: '3#皮带区域',
+      devicePosition: '3#皮带-200m处',
+      netStatus: '1',
+      runStatus: '0',
+      waterVolume: 45,
+      waterPressure: 1.6,
     },
   ],
 };
@@ -208,14 +225,21 @@ function refresh() {
   fetchConfigs('belt').then(() => {
     if (route.query.pageType == 'fireMonitor') {
       configs.value = testBeltNew;
+      Promise.resolve(readData).then(updateData);
     } else if (route.query.pageType == 'emergencyControl') {
+      const params = {
+        devicetype: 'sys',
+        systemID: '1637983899775242242',
+        type: 'ventS',
+      };
+      Promise.resolve(getSystem(params)).then(updateData);
       configs.value = testYjkf;
     } else if (route.query.pageType == 'sprayControl') {
-      configs.value = testYjkf;
+      configs.value = testSpary;
+      Promise.resolve(readData).then(updateData);
     } else {
       configs.value = testBeltNew;
     }
-    Promise.resolve(readData).then(updateData);
     updateEnhancedConfigs(configs.value);
   });
 }

+ 55 - 59
src/views/vent/home/configurable/belt/belt.vue

@@ -15,7 +15,7 @@
           :module-name="cfg.moduleName"
           :device-type="cfg.deviceType"
           :page-type="cfg.pageType"
-          :data="readData"
+          :data="data"
           :visible="true"
         />
       </div>
@@ -172,7 +172,6 @@ const readData = {
   ],
   yjkfArray: [
     {
-      beltName: '测试1',
       aqjkData: [
         {
           deviceName: '风门1',
@@ -230,64 +229,61 @@ const readData = {
         },
       ],
     },
+  ],
+  aqjkData: [
     {
-      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: '在线',
-        },
-      ],
+      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: '在线',
     },
   ],
 };

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

@@ -129,7 +129,6 @@ const layoutConfig = computed(() => {
   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': {

+ 31 - 40
src/views/vent/home/configurable/belt/components/detail/gateBoard.vue

@@ -8,7 +8,7 @@
       <div class="left-panel">
         <!-- 风门数据列表 -->
         <div class="door-list">
-          <div class="door-card" v-for="item in gateData" :key="item.deviceID">
+          <div class="door-card" v-for="(item, index) in props.data" :key="index">
             <div class="door-position">
               <div class="position"></div>
               <div class="door-name"
@@ -17,10 +17,18 @@
               <a-button class="door-btn">一键双开</a-button>
             </div>
             <div class="door-header">
-              <div class="info-column" v-for="(item, index) in gateData" :key="index">
-                <span class="col-label">{{ item.label }}</span>
-                <span class="col-value" :class="[item.value === '打开' || item.value === '在线' ? 'status-open' : 'status-close', 'status-dot']">
-                  {{ item.value }}
+              <div class="info-column" v-for="(i, idx) in config.config.items" :key="idx">
+                <span class="col-label">{{ i.label }}</span>
+                <span
+                  class="col-value"
+                  :class="[
+                    getFormattedText(item, i.value, i.trans) === '打开' || getFormattedText(item, i.value, i.trans) === '连接'
+                      ? 'status-open'
+                      : 'status-close',
+                    'status-dot',
+                  ]"
+                >
+                  {{ getFormattedText(item, i.value, i.trans) }}
                 </span>
               </div>
             </div>
@@ -36,46 +44,29 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, nextTick, defineProps, watch } from 'vue';
-import * as echarts from 'echarts';
-import { get } from 'lodash-es';
+import { ref, onMounted, defineProps } from 'vue';
+import { getFormattedText } from '../../../hooks/helper';
 import gateSVG from '../gateSVG.vue';
-import { config } from 'dotenv';
-let props = defineProps({});
-const gateData = [
-  {
-    label: '前门状态',
-    value: 'frontStatus',
-    trans: {
-      '0': '关闭',
-      '1': '打开',
-    },
-  },
-  {
-    label: '后门状态',
-    value: 'backStatus',
-    trans: {
-      '0': '关闭',
-      '1': '打开',
-    },
-  },
-  {
-    label: '网络状态',
-    value: 'networkStatus',
-    trans: {
-      '0': '离线',
-      '1': '在线',
-    },
-  },
-];
+const props = defineProps<{
+  config: {
+    config: {
+      tilte: string;
+      items: {
+        value: string;
+        label: string;
+        trans?: any;
+      }[];
+    };
+  };
+  data: {
+    [key: string]: any;
+  };
+}>();
 const childRefs = ref<any[]>([]);
 const setChildRef = (el, index) => {
   childRefs.value[index] = el;
 };
-
-onMounted(() => {
-  console.log(props.data, 'qqqqqqqq');
-});
+onMounted(() => {});
 </script>
 
 <style scoped lang="less">

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

@@ -1,3 +1,4 @@
+import { title } from 'process';
 import { Config } from '../../../deviceManager/configurationTable/types';
 // 皮带巷三级防灭火首页
 export const testBeltLaneFire: Config[] = [
@@ -338,29 +339,37 @@ export const testYjkf: Config[] = [
       complex_list: [],
       preset: [
         {
-          readFrom: 'doorData',
-          items: [
-            {
-              label: '前门状态',
-              value: 'frontGateOpen',
-              trans: {
-                '0': '关闭',
-                '1': '打开',
+          readFrom: 'deviceInfo.gate.datalist',
+          type: 'C',
+          config: {
+            tilte: 'strname',
+            items: [
+              {
+                label: '前门状态',
+                value: '${readData.frontGateOpen}',
+                trans: {
+                  1: '打开',
+                  0: '关闭',
+                },
               },
-            },
-            {
-              label: '后门状态',
-              value: 'rearGateOpen',
-              trans: {
-                '0': '关闭',
-                '1': '打开',
+              {
+                label: '后门状态',
+                value: '${readData.rearGateOpen}',
+                trans: {
+                  1: '打开',
+                  0: '关闭',
+                },
               },
-            },
-            {
-              label: '网络状态',
-              value: 'warnLevel_str',
-            },
-          ],
+              {
+                label: '网络状态',
+                value: '${netStatus}',
+                trans: {
+                  1: '连接',
+                  0: '断开',
+                },
+              },
+            ],
+          },
         },
       ],
       // mock: doorMock,
@@ -397,7 +406,7 @@ export const testYjkf: Config[] = [
         direction: 'row',
         items: [
           {
-            name: 'list',
+            name: 'cameraList',
             basis: '100%',
           },
         ],
@@ -409,7 +418,21 @@ export const testYjkf: Config[] = [
       table: [],
       list: [],
       complex_list: [],
-      preset: [],
+      preset: [
+        {
+          readFrom: 'deviceInfo.gate.datalist',
+          config: {
+            title: 'name',
+            contents: [
+              {
+                code: '${id}',
+                value: '${warnLevel}',
+                info: '',
+              },
+            ],
+          },
+        },
+      ],
       // mock: BDfireMock,
     },
     showStyle: {
@@ -972,3 +995,146 @@ export const testBeltNew: Config[] = [
     },
   },
 ];
+export const testSpary: Config[] = [
+  {
+    deviceType: 'plmhInfo', //
+    moduleName: '',
+    pageType: 'beltYjkf1',
+    moduleData: {
+      header: {
+        show: false,
+        readFrom: '',
+        selector: {
+          show: false,
+          value: '',
+        },
+        slot: {
+          show: false,
+          value: '短路风门管控详情',
+          trans: {},
+        },
+      },
+      background: {
+        show: false,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'column',
+        items: [
+          {
+            name: 'sprayCtrl',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [],
+      complex_list: [],
+      preset: [
+        {
+          readFrom: 'sprayData',
+          type: 'C',
+          config: [
+            {
+              title: 'strinstallpos',
+              contentTop: [
+                {
+                  label: '皮带区域',
+                  code: 'beltArea',
+                },
+                {
+                  label: '设备位置',
+                  code: 'devicePosition',
+                },
+              ],
+              contents: [
+                {
+                  label: '网络状态',
+                  code: 'netStatus',
+                  trans: {
+                    0: '断开',
+                    1: '连接',
+                  },
+                },
+                {
+                  label: '运行状态',
+                  code: 'runStatus',
+                  trans: {
+                    0: '断开',
+                    1: '连接',
+                  },
+                },
+                {
+                  label: '水量',
+                  code: '${waterVolume}',
+                },
+                {
+                  label: '水压',
+                  code: 'waterPressure',
+                },
+              ],
+            },
+          ],
+        },
+      ],
+      // mock: doorMock,
+    },
+    showStyle: {
+      size: 'width:440px;height:825px;',
+      version: '原版',
+      position: 'top:20px;left:25px;',
+    },
+  },
+  {
+    deviceType: '',
+    moduleName: '摄像头视频信号',
+    pageType: 'beltYjkf',
+    moduleData: {
+      header: {
+        show: false,
+        readFrom: '',
+        selector: {
+          show: true,
+          value: '${beltName}',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
+      },
+      background: {
+        show: true,
+        type: 'video',
+        link: '',
+      },
+      layout: {
+        direction: 'row',
+        items: [
+          {
+            name: 'list',
+            basis: '100%',
+          },
+        ],
+      },
+      board: [],
+      chart: [],
+      gallery: [],
+      gallery_list: [],
+      table: [],
+      list: [],
+      complex_list: [],
+      preset: [],
+      // mock: BDfireMock,
+    },
+    showStyle: {
+      size: 'width:440px;height:820px;',
+      version: '原版',
+      position: 'top:20px;right:25px;',
+    },
+  },
+];

+ 96 - 0
src/views/vent/home/configurable/components/belt/CameraList.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="camera-modal">
+    <div v-for="(group, index) in allVideos" :key="index" class="sensor-group">
+      <div class="group-title">{{ group.name }}</div>
+      <div class="camrea-area">
+        <div v-if="renderPlayer" ref="playerRef" style="display: flex; width: 100%; height: 100%; overflow-y: auto; pointer-events: none"> </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref, reactive, onBeforeUnmount, computed } from 'vue';
+import { useCamera } from '/@/hooks/system/useCamera';
+
+const props = defineProps<{
+  config: Array<{
+    title: string;
+    contents: Array<{
+      code: string;
+    }>;
+  }>;
+  data: {
+    [key: string]: any;
+  };
+}>();
+const { getCamera, removeCamera } = useCamera();
+const playerRef = ref();
+const renderPlayer = ref(true);
+const allVideos = computed(() => {
+  return props.data?.flatMap((item) => item.cameras || []) || [];
+});
+const cameraIds = computed(() => {
+  // 把所有 cameras 里的 id 全部抽出来
+  return props.data?.flatMap((item) => item.cameras?.map((cam) => cam.id) || []) || [];
+});
+
+onMounted(async () => {
+  await getCamera(cameraIds.value, playerRef, renderPlayer);
+});
+
+onBeforeUnmount(() => {
+  removeCamera(playerRef);
+});
+</script>
+
+<style lang="less" scoped>
+.camera-modal {
+  width: 100%;
+  height: 100%;
+  padding: 5px 10px;
+  .sensor-group {
+    background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
+    background-size: 100% 100%;
+    padding: 10px;
+    height: 280px;
+  }
+  .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;
+  }
+  .camrea-area {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+:deep(#LivePlayerBox) {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  flex-wrap: wrap;
+  pointer-events: none;
+
+  .liveVideo {
+    width: 462px !important;
+    height: 276px !important;
+    padding: 15px !important;
+    align-self: auto !important;
+    margin: 10px 8px !important;
+    background-size: 100% 100% !important;
+  }
+
+  .video-parent {
+    pointer-events: auto !important;
+    align-self: auto !important;
+  }
+}
+</style>

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

@@ -9,15 +9,20 @@
 
         <!-- 循环渲染组内项 -->
         <div v-for="(item, itemIndex) in group.items" :key="itemIndex" class="sensor-item">
+          <div class="item-icon"></div>
           <template v-if="item.status !== undefined">
-            <div class="item-label">{{ item.label }}:</div>
-            <span v-if="item.status !== undefined" class="status-dot" :class="parseStatus(item.status)"></span>
+            <div class="item-status">
+              <div class="item-label">{{ item.label }}:</div>
+              <span v-if="item.status !== undefined" class="status-dot" :class="parseStatus(item.status)"></span>
+            </div>
           </template>
           <template v-else>
             <div class="item-label">{{ item.label }}:</div>
             <div class="item-content">
               <!-- 主要数值/状态 -->
-              <span class="item-value">{{ getFormattedText(data, item.code) }} 时刻 {{ getFormattedText(data, item.info!) }} </span>
+              <span class="item-value"
+                >{{ getFormattedText(data, item.code) }} <span class="label">时刻</span> {{ getFormattedText(data, item.info!) }}
+              </span>
             </div>
           </template>
         </div>
@@ -27,165 +32,169 @@
 </template>
 
 <script setup lang="ts">
-  import { computed } from 'vue';
-  import { getFormattedText } from '../../hooks/helper';
-
-  const props = defineProps<{
-    config: Array<{
-      title: string;
-      readFrom: string;
-      items: Array<{
-        label: string;
-        code: string;
-        status?: string;
-        info?: string;
-      }>;
+import { computed } from 'vue';
+import { getFormattedText } from '../../hooks/helper';
+
+const props = defineProps<{
+  config: Array<{
+    title: string;
+    readFrom: string;
+    items: Array<{
+      label: string;
+      code: string;
+      status?: string;
+      info?: string;
     }>;
-    data: {
-      [key: string]: any;
-    };
-  }>();
-
-  /**
-   * 解析状态并返回对应的 CSS 类名
-   */
-  const parseStatus = (statusStr: string) => {
-    const statusVal = getFormattedText(props.data, statusStr);
-    // 假设 0 为正常,1 为报警
-    return statusVal === '1' ? 'status-danger' : 'status-normal';
+  }>;
+  data: {
+    [key: string]: any;
   };
+}>();
+
+/**
+ * 解析状态并返回对应的 CSS 类名
+ */
+const parseStatus = (statusStr: string) => {
+  const statusVal = getFormattedText(props.data, statusStr);
+  // 假设 0 为正常,1 为报警
+  return statusVal === '1' ? 'status-danger' : 'status-normal';
+};
 </script>
 
 <style scoped lang="less">
-  /* 全局面板样式 */
-  .fire-safety-panel {
-    background-color: #0f2130; /* 深蓝背景 */
-    border-radius: 8px;
-    padding: 15px;
-    box-shadow: 0 0 15px rgba(0, 225, 255, 0.2);
-    color: #fff;
-    font-family: 'Microsoft YaHei', sans-serif;
-    padding-top: 30px;
-  }
-
-  .panel-title {
-    font-size: 16px;
-    font-weight: bold;
-    color: #00e1ff;
-    border-bottom: 1px solid #00aacc;
-    padding-bottom: 8px;
-    margin-bottom: 15px;
-    display: flex;
-    align-items: center;
-  }
-
-  /* 列表容器 */
-  .sensor-list {
-    display: flex;
-    flex-direction: column;
-    gap: 15px; /* 组间距 */
-  }
-
-  /* 分组卡片 */
-  .sensor-group {
-    background: rgba(0, 30, 50, 0.6);
-    border: 1px solid #00aacc;
-    border-radius: 6px;
-    padding: 10px 15px;
-    transition: all 0.3s;
-
-    &:hover {
-      background: rgba(0, 40, 60, 0.8);
-      transform: translateY(-1px);
-    }
+/* 全局面板样式 */
+.fire-safety-panel {
+  border-radius: 8px;
+  padding: 15px;
+  color: #fff;
+  font-family: 'Microsoft YaHei', sans-serif;
+  padding-top: 10px;
+}
+/* 列表容器 */
+.sensor-list {
+  display: flex;
+  flex-direction: column;
+  gap: 15px; /* 组间距 */
+}
+
+/* 分组卡片 */
+.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%;
+  color: #fff;
+  font-size: 12px;
+  font-weight: bold;
+  font-style: italic;
+  margin-bottom: 8px;
+  padding-bottom: 5px;
+  padding-left: 10px;
+}
+
+/* 列表项 */
+.sensor-item {
+  background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+  background-size: 100% 100%;
+  display: flex;
+  align-items: center;
+  margin-bottom: 5px;
+  font-size: 13px;
+  color: #c0d0e0;
+  overflow-y: auto;
+}
+.item-status {
+  width: 90%;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+}
+.item-icon {
+  background: url('@/assets/images/beltFire/fireMonitor/2-5.svg') no-repeat;
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  margin-left: -7px;
+}
+.item-label {
+  height: 30px;
+  line-height: 30px;
+  text-align: right;
+  color: #fff;
+  font-size: 11px;
+}
+
+.item-content {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  .label {
+    color: #fafafa;
   }
-
-  /* 组标题 */
-  .group-title {
-    color: #ffcc00;
-    font-size: 14px;
-    font-weight: bold;
-    margin-bottom: 8px;
-    padding-left: 10px;
-    border-left: 3px solid #ffcc00;
+}
+
+.item-value {
+  margin-right: 10px;
+  font-size: 12px;
+  color: #36dae7;
+}
+.item-info {
+  color: #889db0;
+  font-size: 11px;
+}
+
+/* 状态指示灯 */
+.status-dot {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  margin-left: 5px;
+  margin-top: 10px;
+  animation: pulse 2s infinite;
+
+  &.status-normal {
+    background-color: #00ff00;
+    box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
   }
 
-  /* 列表项 */
-  .sensor-item {
-    display: flex;
-    align-items: center;
-    margin-bottom: 5px;
-    font-size: 13px;
-    color: #c0d0e0;
+  &.status-danger {
+    background-color: #ff4d4d;
+    box-shadow: 0 0 6px 2px rgba(255, 48, 48, 0.6);
+    animation: flash 1s infinite;
   }
+}
 
-  .item-label {
-    // width: 70px; /* 标签宽度 */
-    text-align: right;
-    margin-right: 10px;
-    color: #889db0;
+/* 动画效果 */
+@keyframes pulse {
+  0% {
+    transform: scale(1);
+    opacity: 1;
   }
-
-  .item-content {
-    flex: 1;
-    display: flex;
-    align-items: center;
-  }
-
-  .item-value {
-    margin-right: 10px;
-    color: #ffffff;
+  50% {
+    transform: scale(1.2);
+    opacity: 0.8;
   }
-
-  .item-info {
-    color: #889db0;
-    font-size: 12px;
+  100% {
+    transform: scale(1);
+    opacity: 1;
   }
+}
 
-  /* 状态指示灯 */
-  .status-dot {
-    display: inline-block;
-    width: 10px;
-    height: 10px;
-    border-radius: 50%;
-    margin-left: 5px;
-    animation: pulse 2s infinite;
-
-    &.status-normal {
-      background-color: #00ff00;
-    }
-
-    &.status-danger {
-      background-color: #ff4d4d;
-      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>

+ 99 - 105
src/views/vent/home/configurable/components/belt/SensorStatusPanel.vue

@@ -5,7 +5,7 @@
       <!-- 循环渲染每一个传感器卡片 -->
       <div v-for="(sensor, index) in config.list" :key="index" class="sensor-card">
         <div class="sensor-header">
-          <h3 class="sensor-title">{{ sensor.title }}</h3>
+          <span class="sensor-title">{{ sensor.title }}</span>
         </div>
 
         <!-- 上半部分:三列数值 -->
@@ -30,12 +30,12 @@
           </div>
         </div>
 
-        <!-- 下半部分:折叠面板 -->
+        <!-- 下半部分 -->
         <div class="sensor-details">
-          <div class="detail-row" @click="toggleCollapse(index)" :class="{ 'is-collapsed': collapsedIndex === index }">
+          <div class="detail-row">
             <div class="row-label">
-              <span class="arrow-icon"></span>
-              <span> {{ sensor.contents[0].label }}: </span>
+              <span class="arrow-icon"></span>
+              <span class="labelInfo"> {{ sensor.contents[0].label }}: </span>
             </div>
             <div
               class="row-value"
@@ -43,22 +43,19 @@
                 color: getAlarmColor(getFormattedText(data, sensor.contents[0].code)),
               }"
             >
-              {{ getAlarmText(getFormattedText(data, sensor.contents[0].code)) }}
+              <span class="status-dot"></span>
+              <span>{{ getAlarmText(getFormattedText(data, sensor.contents[0].code)) }}</span>
             </div>
           </div>
-
-          <!-- 折叠内容 -->
-          <transition name="fade">
-            <div v-show="collapsedIndex === index" class="collapse-content">
-              <div class="detail-row">
-                <span class="row-label">{{ sensor.contents[1].label }}: </span>
-                <div class="row-value" :style="{ color: sensor.contents[1].color }">
-                  <span>{{ getFormattedText(data, sensor.contents[1].code) }} 时刻</span>
-                  <span v-if="sensor.contents[1].info" class="info">{{ getFormattedText(data, sensor.contents[1].code) }}</span>
-                </div>
-              </div>
+          <div class="detail-row1">
+            <span class="row-label">
+              <span class="arrow-icon"></span> <span class="labelInfo">{{ sensor.contents[1].label }}</span></span
+            >
+            <div class="row-value" :style="{ color: sensor.contents[1].color }">
+              <span class="label">{{ getFormattedText(data, sensor.contents[1].code) }} <span class="text">时刻</span></span>
+              <span v-if="sensor.contents[1].info" class="info">{{ getFormattedText(data, sensor.contents[1].info.code) }}</span>
             </div>
-          </transition>
+          </div>
         </div>
       </div>
     </div>
@@ -95,10 +92,6 @@ const props = defineProps<{
 // --- 3. 交互逻辑 ---
 const collapsedIndex = ref(null);
 
-const toggleCollapse = (index) => {
-  collapsedIndex.value = collapsedIndex.value === index ? null : index;
-};
-
 // --- 4. 状态判断方法 ---
 const getAlarmColor = (value) => {
   // 根据 trans 规则判断颜色
@@ -114,7 +107,7 @@ const getAlarmText = (value) => {
 };
 </script>
 
-<style scoped>
+<style scoped lang="less">
 .sensor-analysis-board {
   background: linear-gradient(180deg, #0b2b4a 0%, #020f1a 100%);
   color: #fff;
@@ -131,117 +124,118 @@ const getAlarmText = (value) => {
 }
 
 .sensor-card {
-  background: rgba(0, 40, 70, 0.6);
-  border: 1px solid #00bfff;
+  background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
+  background-size: 100% 100%;
   border-radius: 8px;
-  padding: 15px;
-  box-shadow: inset 0 0 10px rgba(0, 191, 255, 0.3);
+  padding: 10px;
 }
 
 .sensor-header {
-  border-bottom: 1px solid #00bfff;
-  padding-bottom: 8px;
-  margin-bottom: 10px;
+  background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
+  background-size: 38% 100%;
+  padding-bottom: 6px;
+  margin-bottom: 8px;
 }
 
 .sensor-title {
-  font-size: 18px;
+  color: #fff;
+  font-size: 12px;
   font-weight: bold;
-  color: #00bfff;
-  margin: 0;
+  font-style: italic;
+  margin-left: 10px;
 }
 
 .sensor-values {
+  width: 100%;
   display: flex;
-  justify-content: space-around;
+  justify-content: space-between;
   margin-bottom: 15px;
   text-align: center;
 }
 
 .value-item {
-  flex: 1;
+  background: url('@/assets/images/beltFire/yjkf/1-3-1.png') no-repeat;
+  background-size: 100% 100%;
+  width: 30%;
   padding: 5px;
-}
-
-.label {
-  display: block;
   font-size: 14px;
-  color: #8ecfff;
-  margin-bottom: 5px;
-}
-
-.value {
-  font-size: 24px;
-  font-weight: bold;
-  color: #fff;
-}
-
-.sensor-details {
-  background: rgba(0, 20, 40, 0.8);
-  border-radius: 6px;
-  padding: 10px;
+  .label {
+    display: block;
+    color: #fafafa;
+    margin-bottom: 5px;
+  }
+  .value {
+    font-weight: bold;
+    color: #3cf4fb;
+    padding-bottom: 2px;
+  }
 }
 
 .detail-row {
+  background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+  background-size: 100% 100%;
   display: flex;
   justify-content: space-between;
   padding: 8px 0;
-  cursor: pointer;
-  border-bottom: 1px solid rgba(142, 207, 255, 0.3);
-  transition: background 0.3s;
-}
-
-.detail-row:last-child {
-  border-bottom: none;
-}
-
-.detail-row:hover {
-  background: rgba(0, 100, 200, 0.3);
+  margin: 10px 0;
+  .row-label {
+    font-size: 12px;
+    color: #fafafa;
+    display: flex;
+    align-items: center;
+  }
+  .row-value {
+    margin-right: 10px;
+  }
+  .status-dot {
+    display: inline-block;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    margin-left: 5px;
+    margin-top: 10px;
+    margin-right: 10px;
+    animation: pulse 2s infinite;
+    background-color: #46ff9c;
+    box-shadow: 0 0 6px 2px rgba(62, 226, 146, 0.6);
+  }
 }
-
-.row-label {
-  font-size: 15px;
-  color: #a0daff;
+.detail-row1 {
+  background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+  background-size: 100% 100%;
   display: flex;
-  align-items: center;
-}
-
-.row-value {
-  font-size: 16px;
-  font-weight: bold;
+  justify-content: flex-start;
+  padding: 8px 0;
+  margin: 10px 0;
+  .row-label {
+    font-size: 12px;
+    color: #fafafa;
+    display: flex;
+    align-items: center;
+  }
+  .row-value {
+    .label {
+      font-size: 12px;
+      font-weight: bold;
+      color: #2db7c5 !important;
+    }
+    .text {
+      color: #fafafa;
+      font-size: 12px;
+    }
+    .info {
+      font-size: 12px;
+      font-weight: bold;
+      color: #2db7c5 !important;
+    }
+  }
 }
 
 .arrow-icon {
-  transition: transform 0.3s;
-  margin-right: 5px;
-  font-size: 12px;
-}
-
-.is-collapsed .arrow-icon {
-  transform: rotate(90deg);
-}
-
-.collapse-content {
-  padding-top: 10px;
-  animation: fadeIn 0.5s ease-in-out;
-}
-
-/* 折叠动画 */
-.fade-enter-active,
-.fade-leave-active {
-  transition: opacity 0.3s ease;
-}
-
-.fade-enter-from,
-.fade-leave-to {
-  opacity: 0;
-}
-
-/* 模拟图片中的样式 */
-@media (max-width: 600px) {
-  .sensor-values {
-    flex-direction: column;
-    gap: 10px;
-  }
+  background: url('@/assets/images/beltFire/fireMonitor/2-5.svg') no-repeat;
+  background-size: 100% 100%;
+  width: 20px;
+  height: 20px;
+  margin-left: -7px;
 }
 </style>

+ 280 - 0
src/views/vent/home/configurable/components/belt/SprayControl.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="fire-safety-panel">
+    <!-- 数据列表容器 -->
+    <div class="sensor-list">
+      <!-- 按钮 -->
+      <div class="control-bar">
+        <a-button class="control-btn">启动喷淋</a-button>
+        <a-button class="control-btn">停止喷淋</a-button>
+        <a-button class="control-btn">手动控制</a-button>
+        <a-button class="control-btn">自动控制</a-button>
+      </div>
+      <!-- 循环渲染分组 -->
+      <div v-for="(group, index) in config.config" :key="index" class="sensor-group">
+        <!-- 组标题 -->
+        <div class="group-title"> <a-checkbox class="check-btn">控制勾选</a-checkbox> </div>
+        <!-- 循环渲染组内项 -->
+        <div v-for="(item, itemIndex) in group.contentTop" :key="itemIndex" class="sensor-item" :class="getBgClass(itemIndex)">
+          <div class="item-icon" :class="getBgClass(itemIndex)"></div>
+          <div class="item-status">
+            <div class="item-label">{{ item.label }}</div>
+            <div class="item-code">{{ getFormattedText(data, item.code) }}</div>
+          </div>
+        </div>
+        <div class="container">
+          <div v-for="(item, itemIndex) in group.contents" :key="itemIndex" class="dataInfo-item" :class="getBgClass(itemIndex)">
+            <div class="item-status">
+              <div class="item-label">{{ item.label }}</div>
+              <div class="item-code"><span class="status-dot" v-if="item.trans"> </span>{{ getFormattedText(data, item.code, item.trans) }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+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;
+    }>;
+  }>;
+  data: {
+    [key: string]: any;
+  };
+}>();
+const getBgClass = (index) => {
+  return index % 2 === 0 ? 'bg-1' : 'bg-2';
+};
+onMounted(() => {
+  console.log(props.config, '123');
+});
+</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;
+}
+
+/* 分组卡片 */
+.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%;
+  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%;
+}
+
+.item-status {
+  width: 100%;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  margin-left: 20px;
+  font-weight: bold;
+  .item-label {
+    color: #fff;
+    height: 30px;
+    line-height: 30px;
+  }
+  .item-code {
+    height: 30px;
+    line-height: 30px;
+    text-align: right;
+    color: #91faff;
+    font-size: 12px;
+  }
+}
+
+.item-content {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  .label {
+    color: #fff;
+  }
+}
+
+.item-value {
+  margin-right: 10px;
+  font-size: 12px;
+  color: #36dae7;
+}
+.item-info {
+  color: #ffff;
+  font-size: 11px;
+}
+
+/* 状态指示灯 */
+.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 pulse {
+  0% {
+    transform: scale(1);
+    opacity: 1;
+  }
+  50% {
+    transform: scale(1.2);
+    opacity: 0.8;
+  }
+  100% {
+    transform: scale(1);
+    opacity: 1;
+  }
+}
+
+@keyframes flash {
+  0% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.5;
+  }
+  100% {
+    opacity: 1;
+  }
+}
+</style>

+ 334 - 284
src/views/vent/home/configurable/components/belt/VehicleCOAnalysis.vue

@@ -4,11 +4,14 @@
 
     <div class="section" v-for="item in filteredList('control')" :key="item.type">
       <div class="control-row">
-        <span class="label">车辆干扰排除</span>
-        <div class="toggle-switch" :class="{ 'is-on': monitData.isRisk }">
+        <div class="tip">
+          <div class="icon"></div>
+          <span class="label">车辆干扰排除</span>
           <span class="text">{{ monitData.isRisk ? '开启' : '关闭' }}</span>
-          <div class="slider"></div>
-          <span class="text">{{ monitData.isRisk ? '关闭' : '开启' }}</span>
+          <div class="toggle-switch" :class="{ 'is-on': isOn }" @click="toggleSwitch">
+            <div class="slider"></div>
+          </div>
+          <span class="text1">{{ monitData.isRisk ? '关闭' : '开启' }}</span>
         </div>
         <button class="btn-history">历史分析记录</button>
       </div>
@@ -19,315 +22,362 @@
       <div class="section-title">{{ item.title }}</div>
       <div class="activity-list">
         <div class="activity-item" v-for="(act, idx) in monitData.activityList" :key="idx">
-          <span class="pos">{{ act.pos }}</span>
-          <span class="vehicle">{{ act.vehicle }}</span>
-          <span class="status" :class="getStatusClass(act.status)">
-            {{ getStatusText(act.status) }}
-          </span>
+          <div class="info">
+            <span class="pos">{{ act.pos }}</span>
+            <span class="vehicle">{{ act.vehicle }}</span>
+          </div>
+          <div class="warnStatus">
+            <span class="status" :class="getStatusClass(act.status)"> </span>
+            <span class="status-text"> {{ getStatusText(act.status) }}</span>
+          </div>
         </div>
       </div>
     </div>
 
     <!-- 3. CO浓度异常分析 (Analysis Section) -->
-    <div class="section" v-for="item in filteredList('analysis')" :key="item.type">
-      <div class="section-title">{{ item.title }}</div>
-      <div class="analysis-list">
-        <div class="analysis-item" v-for="(ana, idx) in monitData.analysisList" :key="idx">
-          <span class="label">{{ ana.pos }}</span>
-          <span class="text">{{ ana.analysisText }}</span>
+    <div class="section">
+      <div v-for="item in filteredList('analysis')" :key="item.type">
+        <div class="section-title">{{ item.title }}</div>
+        <div class="analysis-list">
+          <div class="analysis-item" v-for="(ana, idx) in monitData.analysisList" :key="idx">
+            <span class="label">{{ ana.pos }}</span>
+            <span class="text">{{ ana.analysisText }}</span>
+          </div>
+        </div>
+        <!-- 4. 可能原因与建议 (Reason Section) -->
+        <div v-for="i in filteredList('reasonAnalysis')" :key="i.type">
+          <div class="reason-item">
+            <span class="label">{{ i.items[0].label }}:</span>
+            <span class="value reason">{{ monitData.possibleCause }}</span>
+          </div>
+          <div class="reason-item">
+            <span class="label">{{ i.items[1].label }}:</span>
+            <span class="value recommendation">{{ monitData.recommendation }}</span>
+          </div>
         </div>
-      </div>
-    </div>
-
-    <!-- 4. 可能原因与建议 (Reason Section) -->
-    <div class="section" v-for="item in filteredList('reasonAnalysis')" :key="item.type">
-      <div class="reason-item">
-        <span class="label">{{ item.items[0].label }}:</span>
-        <span class="value">{{ monitData.possibleCause }}</span>
-      </div>
-      <div class="reason-item">
-        <span class="label">{{ item.items[1].label }}:</span>
-        <span class="value recommendation">{{ monitData.recommendation }}</span>
       </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { computed } from 'vue';
-
-  // 定义 Props,接收配置和模拟数据
-  interface ConfigItem {
-    type: string;
-    title: string;
-    readFrom?: string;
-    items?: Array<{ label: string; code?: string; trans?: any }>;
-  }
-
-  const props = withDefaults(
-    defineProps<{
-      list: ConfigItem[];
-      data: {
-        isRisk: boolean;
-        activityList: Array<{ pos: string; vehicle: string; status: string }>;
-        analysisList: Array<{ pos: string; analysisText: string }>;
-        possibleCause: string;
-        recommendation: string;
-      };
-    }>(),
-    {
-      list: () => [],
-      data: () => ({
-        isRisk: false,
-        activityList: [],
-        analysisList: [],
-        possibleCause: '',
-        recommendation: '',
-      }),
-    }
-  );
-
-  const monitData = computed(() => props.data);
-  // --- 计算属性:根据 type 筛选配置项 ---
-  const filteredList = (type: string) => {
-    return props.list.filter((item) => item.type === type);
-  };
-
-  // --- 方法:获取状态类名和文本 ---
-  const getStatusClass = (status: string) => {
-    if (status === '0') return 'status-excluded';
-    if (status === '1') return 'status-warning';
-    return '';
-  };
-
-  const getStatusText = (status: string) => {
-    if (status === '0') return '已排除';
-    if (status === '1') return '预警';
-    return '未知';
-  };
+import { computed, ref } from 'vue';
+
+// 定义 Props,接收配置和模拟数据
+interface ConfigItem {
+  type: string;
+  title: string;
+  readFrom?: string;
+  items?: Array<{ label: string; code?: string; trans?: any }>;
+}
+
+const props = withDefaults(
+  defineProps<{
+    list: ConfigItem[];
+    data: {
+      isRisk: boolean;
+      activityList: Array<{ pos: string; vehicle: string; status: string }>;
+      analysisList: Array<{ pos: string; analysisText: string }>;
+      possibleCause: string;
+      recommendation: string;
+    };
+  }>(),
+  {
+    list: () => [],
+    data: () => ({
+      isRisk: false,
+      activityList: [],
+      analysisList: [],
+      possibleCause: '',
+      recommendation: '',
+    }),
+  }
+);
+
+const monitData = computed(() => props.data);
+// 自己维护开关状态,不依赖任何外部数据
+const isOn = ref(false);
+// --- 计算属性:根据 type 筛选配置项 ---
+const filteredList = (type: string) => {
+  return props.list.filter((item) => item.type === type);
+};
+//滑块滑动
+const toggleSwitch = () => {
+  // const isOn = monitData.isRisk;
+  isOn.value = !isOn.value;
+  console.log(monitData.isRisk, '123123');
+};
+// --- 方法:获取状态类名和文本 ---
+const getStatusClass = (status: string) => {
+  if (status === '0') return 'status-excluded';
+  if (status === '1') return 'status-warning';
+  return '';
+};
+
+const getStatusText = (status: string) => {
+  if (status === '0') return '已排除';
+  if (status === '1') return '预警';
+  return '未知';
+};
 </script>
 
-<style scoped>
-  /* 基础样式重置 */
-  * {
-    margin: 0;
-    padding: 0;
-    box-sizing: border-box;
-  }
-
-  .monitor-container {
-    width: 400px;
-    height: 410px;
-    background: linear-gradient(180deg, #0d213f 0%, #0a162a 100%);
-    border: 1px solid #1a3b5d;
-    color: #fff;
-    font-family: 'Microsoft YaHei', sans-serif;
-    padding: 10px 15px;
-    position: relative;
-    /* overflow: hidden; */
-  }
-
-  /* 顶部标题样式 (虽然图里有,但数据配置里没单独标题,这里用 CSS 模拟顶部栏) */
-  .monitor-container::before {
-    content: '';
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    height: 3px;
-    background: linear-gradient(90deg, #00c6ff, #0072ff);
-  }
-
-  /* 通用区块样式 */
-  .section {
-    margin-bottom: 15px;
-  }
-
-  .section-title {
-    font-size: 12px;
-    color: #4fd1ff;
-    font-weight: bold;
-    border-left: 3px solid #00c6ff;
-    padding-left: 8px;
-    margin-bottom: 8px;
-    letter-spacing: 1px;
+<style scoped lang="less">
+/* 基础样式重置 */
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+.monitor-container {
+  width: 400px;
+  height: 410px;
+  background: linear-gradient(180deg, #0d213f 0%, #0a162a 100%);
+  border: 1px solid #1a3b5d;
+  color: #fafafa;
+  font-family: 'Microsoft YaHei', sans-serif;
+  padding: 10px 15px;
+  position: relative;
+  /* overflow: hidden; */
+}
+
+/* 顶部标题样式 (虽然图里有,但数据配置里没单独标题,这里用 CSS 模拟顶部栏) */
+.monitor-container::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 3px;
+  background: linear-gradient(90deg, #00c6ff, #0072ff);
+}
+
+/* 通用区块样式 */
+.section {
+  margin-bottom: 15px;
+  background: url('@/assets/images/beltFire/fireMonitor/2-1.png') no-repeat;
+  background-size: 100% 100%;
+}
+
+.section-title {
+  background: url('@/assets/images/beltFire/fireMonitor/2-2.png') no-repeat;
+  background-size: 35% 100%;
+  font-size: 12px;
+  color: #fafafa;
+  font-weight: bold;
+  font-style: italic;
+  margin-bottom: 8px;
+  padding-bottom: 5px;
+  padding-left: 10px;
+  padding-top: 5px;
+}
+
+/* 1. 控制区样式 (开关) */
+.control-row {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  border-radius: 4px;
+}
+.tip {
+  display: flex;
+  justify-content: space-around;
+  height: 30px;
+  width: 70%;
+  background: url('@/assets/images/beltFire/fireMonitor/2-11.png') no-repeat;
+  background-size: 100% 100%;
+  .icon {
+    background: url('@/assets/images/beltFire/fireMonitor/2-10.svg') no-repeat;
+    background-size: 100% 100%;
+    height: 12px;
+    width: 12px;
+    margin-left: 2px;
+    margin-top: 8px;
   }
-
-  /* 1. 控制区样式 (开关) */
-  .control-row {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    background: rgba(0, 0, 0, 0.2);
-    padding: 5px 10px;
-    border-radius: 4px;
-    margin-bottom: 15px;
-  }
-
   .label {
-    font-size: 13px;
-    color: #fff;
-    text-align: left;
-  }
-
-  .toggle-switch {
-    display: flex;
-    align-items: center;
-    width: 120px;
-    height: 26px;
-    background: #1a2b42;
-    border-radius: 13px;
-    padding: 2px;
-    cursor: pointer;
-    position: relative;
-    overflow: hidden;
-  }
-
-  .toggle-switch.is-on {
-    background: #00c6ff;
+    padding: 5px;
   }
-
-  .toggle-switch .text {
-    flex: 1;
-    text-align: center;
+  .text {
+    line-height: 30px;
     font-size: 11px;
-    color: #7f9cb3;
-    transition: color 0.2s;
-  }
-
-  .toggle-switch.is-on .text {
-    color: #fff;
-  }
-
-  .toggle-switch .text:first-child {
-    color: #fff;
-  }
-
-  .toggle-switch.is-on .text:first-child {
-    color: #000;
+    padding-left: 20px;
   }
+  .text1 {
+    line-height: 30px;
+    font-size: 11px;
+    padding-left: 0px;
+  }
+}
+.label {
+  padding-left: 5px;
+  font-size: 12px;
+  color: #fafafa;
+}
+
+.toggle-switch {
+  display: inline-flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 5px 5px;
+  width: 50px;
+  height: 20px;
+  border-radius: 15px;
+  position: relative;
+  cursor: pointer;
+  border: 1px solid #15567f;
+  box-sizing: border-box;
+  margin-top: 3px;
+  background: #0f2840; /* 加背景更美观 */
 
   .slider {
-    width: 22px;
-    height: 22px;
-    background: #fff;
-    border-radius: 50%;
     position: absolute;
-    top: 2px;
-    left: 2px;
-    transition: transform 0.2s ease;
-  }
-
-  .toggle-switch.is-on .slider {
-    transform: translateX(64px);
-    background: #fff;
-  }
-
-  .btn-history {
-    background: rgba(0, 198, 255, 0.1);
-    border: 1px solid #00c6ff;
-    color: #00c6ff;
-    font-size: 11px;
-    padding: 2px 8px;
-    border-radius: 2px;
-    cursor: pointer;
-  }
+    top: 3px;
+    width: 12px;
+    height: 12px;
+    border-radius: 50%;
+    background-color: #ffffff;
+    transition: all 0.3s ease;
+    z-index: 1;
 
-  .btn-history:hover {
-    background: rgba(0, 198, 255, 0.2);
+    /* 默认关闭:左边 */
+    left: 3px;
   }
-
-  /* 2. 车辆活动列表 */
-  .activity-list {
-    background: rgba(0, 0, 0, 0.1);
-    border-radius: 4px;
-    padding: 8px 0;
+  /* 开启:滑块去右边 */
+  &.is-on {
+    .slider {
+      left: calc(100% - 15px);
+    }
   }
-
-  .activity-item {
+}
+
+.btn-history {
+  background: linear-gradient(180deg, #34b7f1 0%, #1890ff 100%);
+  border: 1px solid #40c4ff;
+  color: #fafafa;
+  font-size: 11px;
+  padding: 2px 6px;
+  margin-left: 10px;
+  box-shadow: 0 0 6px 2px rgba(24, 144, 255, 0.4);
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.btn-history:hover {
+  background: rgba(0, 198, 255, 0.2);
+}
+
+/* 2. 车辆活动列表 */
+.activity-list {
+  border-radius: 4px;
+  width: 100%;
+}
+
+.activity-item {
+  display: flex;
+  align-items: center;
+  justify-content: flex-start;
+  padding: 5px 8px;
+  color: #fafafa;
+  font-size: 12px;
+
+  .info {
     display: flex;
-    padding: 4px 10px;
-    font-size: 12px;
-    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
-  }
-
-  .activity-item:last-child {
-    border-bottom: none;
-  }
-
-  .pos {
-    flex: 1;
-    color: #a0cfff;
-  }
-
-  .vehicle {
-    flex: 2;
-    color: #fff;
-  }
-
-  .status {
-    padding: 2px 6px;
-    border-radius: 2px;
-    font-size: 10px;
-    font-weight: bold;
-    color: #fff;
-    min-width: 40px;
-    text-align: center;
-  }
-
-  .status-excluded {
-    background: #00c853;
-  }
-
-  .status-warning {
-    background: #ff5252;
-  }
-
-  /* 3. CO浓度分析列表 */
-  .analysis-list {
-    font-size: 12px;
-    line-height: 1.6;
-  }
-
-  .analysis-item {
-    margin-bottom: 8px;
-  }
-
-  .analysis-item .label {
-    color: #ff9800;
-    font-weight: bold;
-  }
-
-  .analysis-item .text {
-    color: #fff;
-    margin-left: 5px;
+    align-items: center;
+    padding: 2px 12px;
+    gap: 60px;
+    color: #fafafa;
+    background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+    background-size: 100% 100%;
+    .pos,
+    .vehicle {
+      color: #fafafa;
+    }
   }
 
-  /* 4. 原因与建议 */
-  .reason-item {
+  .warnStatus {
     display: flex;
-    align-items: flex-start;
-    font-size: 12px;
-    line-height: 1.6;
-    margin-bottom: 8px;
-  }
-
-  .reason-item .label {
-    color: #ff9800;
-    font-weight: bold;
-    width: 55px;
-    text-align: left;
-    margin-right: 10px;
-    white-space: nowrap;
-  }
-
-  .reason-item .value {
+    align-items: center;
+    justify-content: space-around;
+    margin-left: 10px;
+    padding: 2px 10px;
     flex: 1;
-    color: #fff;
-  }
-
-  .recommendation {
-    color: #ff5252;
-    font-weight: bold;
+    background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+    background-size: 100% 100%;
+    .status {
+      width: 6px;
+      height: 6px;
+      border-radius: 50%;
+      background-color: #38e4ef;
+      box-shadow: 0 0 8px 2px rgba(56, 228, 239, 0.6);
+      &.status-excluded {
+        background-color: #006eff;
+        box-shadow: 0 0 8px 2px rgba(29, 146, 255, 0);
+      }
+      &.status-warning {
+        background-color: #ff3333;
+        box-shadow: 0 0 8px 2px rgba(255, 51, 51, 0.6);
+      }
+    }
+    .status-text {
+      color: #fafafa;
+    }
   }
+}
+
+/* 3. CO浓度分析列表 */
+.analysis-list {
+  font-size: 12px;
+  line-height: 1.6;
+}
+
+.analysis-item {
+  background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+  background-size: 100% 100%;
+  padding: 4px 8px;
+  margin-bottom: 8px;
+  margin: 10px 8px;
+  width: 95%;
+  display: flex;
+  justify-content: space-between;
+}
+
+.analysis-item .label {
+  color: #fafafa;
+  font-weight: bold;
+}
+
+.analysis-item .text {
+  color: #fafafa;
+  margin-left: 5px;
+}
+
+/* 4. 原因与建议 */
+.reason-item {
+  background: url('@/assets/images/beltFire/fireMonitor/2-4.png') no-repeat;
+  background-size: 100% 100%;
+  padding: 4px 8px;
+  margin-bottom: 8px;
+  margin: 10px 8px;
+  width: 95%;
+  display: flex;
+  font-size: 12px;
+  font-weight: bold;
+  justify-content: space-between;
+}
+
+.reason-item .label {
+  color: #fafafa;
+  width: 55px;
+  margin-right: 10px;
+  white-space: nowrap;
+}
+
+.reason-item .reason {
+  color: #e6941f;
+}
+
+.recommendation {
+  color: #ff5252;
+}
 </style>

+ 14 - 5
src/views/vent/home/configurable/components/belt/WarningResultList.vue

@@ -59,7 +59,9 @@ const props = defineProps<{
     [key: string]: any;
   };
 }>();
-onMounted(() => {});
+onMounted(() => {
+  console.log(props.config, '123123');
+});
 </script>
 
 <style scoped lang="less">
@@ -68,6 +70,11 @@ onMounted(() => {});
   padding: 10px;
   box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
   font-family: 'Microsoft YaHei', 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', 'Arial', sans-serif;
+  height: 100%;
+  max-height: 250px;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden; /* 禁止外层整体滚动 */
 }
 
 /* --- 顶部标题栏 --- */
@@ -78,6 +85,7 @@ onMounted(() => {});
   align-items: center;
   padding-bottom: 15px;
   border-bottom: 1px dashed #0e324b;
+  flex-shrink: 0;
 }
 
 .header-left {
@@ -119,8 +127,8 @@ onMounted(() => {});
     height: 8px;
     border-radius: 50%;
     margin-right: 4px;
-    background-color: #ff0000;
-    box-shadow: 0 0 6px 2px rgba(255, 45, 45, 0.6);
+    background-color: #33ff00;
+    box-shadow: 0 0 6px 2px rgba(104, 255, 45, 0.6);
   }
 }
 
@@ -145,6 +153,7 @@ onMounted(() => {});
 /* --- 表格样式 --- */
 .table-container {
   width: 100%;
+  flex: 1;
   overflow-y: auto;
   -webkit-overflow-scrolling: touch;
 }
@@ -182,12 +191,12 @@ th {
 .table-cell {
   padding: 12px 15px;
   font-size: 14px;
-  color: #aebccf;
+  color: #fff;
   vertical-align: middle;
 }
 
 /* 操作列按钮样式 */
-.btn-start-spray {
+:deep(.btn-start-spray) {
   background: #2192d9;
   color: #fff;
   border: none;

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

@@ -114,22 +114,24 @@
         </template>
         <!-- 表格部分 -->
         <template v-if="config.name === 'table'">
-          <CustomTableBelt
-            v-if="config.pagetype === 'Belt'"
-            class="content__module text-center overflow-auto"
-            :type="config.type"
-            :columns="config.columns"
-            :auto-scroll="config.autoScroll"
-            :data="config.data"
-          />
-          <CustomTable
-            v-else
-            class="content__module text-center overflow-auto"
-            :type="config.type"
-            :columns="config.columns"
-            :auto-scroll="config.autoScroll"
-            :data="config.data"
-          />
+          <template v-if="config.pagetype === 'Belt'">
+            <CustomTableBelt
+              class="content__module text-center overflow-auto"
+              :type="config.type"
+              :columns="config.columns"
+              :auto-scroll="config.autoScroll"
+              :data="config.data"
+            />
+          </template>
+          <template v-else>
+            <CustomTable
+              class="content__module text-center overflow-auto"
+              :type="config.type"
+              :columns="config.columns"
+              :auto-scroll="config.autoScroll"
+              :data="config.data"
+            />
+          </template>
         </template>
         <template v-if="config.name === 'tabs'">
           <CustomTabs class="content__module" :type="config.type" :tab-config="config.items" :overflow="config.overflow" />
@@ -193,7 +195,14 @@
           />
         </template>
         <template v-if="config.name === 'gateBoard'">
-          <GateBoard class="content__module" :data="config.data" :config="config.config" />
+          <GateBoard class="content__module" :config="config.config" :data="config.data" />
+        </template>
+        <!-- 3. 火灾监测设备分析 -->
+        <template v-if="config.name === 'sprayCtrl'">
+          <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" />
         </template>
         <!-- <template v-if="config.key === 'fire_control'">
         <FIreControl class="content__module" />
@@ -204,7 +213,7 @@
         <!-- ==================== 新增皮带巷火灾监测模块 ==================== -->
         <!-- 1. 传感器状态面板 -->
         <template v-if="config.name === 'sensor_status'">
-          <SensorStatusPanel class="content__module" :config="config.config" :data="config.data" />
+          <SensorStatusPanel class="content__module" style="height: calc(100% - 30px)" :config="config.config" :data="config.data" />
         </template>
 
         <!-- 3. 火灾监测设备分析 -->
@@ -266,6 +275,8 @@ import CustomListBelt from './belt/CustomListBelt.vue';
 import ComplexListBelt from './belt/ComplexListBelt.vue';
 import ComplexList1Belt from './belt/ComplexList1Belt.vue';
 import CustomTableBelt from './belt/CustomTableBelt.vue';
+import SprayControl from './belt/SprayControl.vue';
+import CameraList from './belt/CameraList.vue';
 const props = defineProps<{
   data: any;
   moduleData: Config['moduleData'];

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

@@ -1,171 +0,0 @@
-<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>