ソースを参照

[Wip 0000] 保德可配置首页开发

houzekong 6 ヶ月 前
コミット
10efc54be1
72 ファイル変更1788 行追加406 行削除
  1. BIN
      src/assets/images/home-container/configurable/board_bg_1.png
  2. BIN
      src/assets/images/home-container/configurable/firehome/CH₄.png
  3. BIN
      src/assets/images/home-container/configurable/firehome/CO.png
  4. BIN
      src/assets/images/home-container/configurable/firehome/CO₂.png
  5. BIN
      src/assets/images/home-container/configurable/firehome/C₂H₂.png
  6. BIN
      src/assets/images/home-container/configurable/firehome/C₂H₄.png
  7. BIN
      src/assets/images/home-container/configurable/firehome/H₂.png
  8. BIN
      src/assets/images/home-container/configurable/firehome/NO₂.png
  9. BIN
      src/assets/images/home-container/configurable/firehome/N₂.png
  10. BIN
      src/assets/images/home-container/configurable/firehome/O₂.png
  11. BIN
      src/assets/images/home-container/configurable/firehome/bg.png
  12. BIN
      src/assets/images/home-container/configurable/firehome/co1.png
  13. BIN
      src/assets/images/home-container/configurable/firehome/common-border.png
  14. BIN
      src/assets/images/home-container/configurable/firehome/common-border1.png
  15. BIN
      src/assets/images/home-container/configurable/firehome/common-border2.png
  16. BIN
      src/assets/images/home-container/configurable/firehome/common-border3.png
  17. BIN
      src/assets/images/home-container/configurable/firehome/empty-qp.png
  18. BIN
      src/assets/images/home-container/configurable/firehome/fiber-jc.png
  19. BIN
      src/assets/images/home-container/configurable/firehome/ggxt.png
  20. BIN
      src/assets/images/home-container/configurable/firehome/img-1.png
  21. BIN
      src/assets/images/home-container/configurable/firehome/img-2.png
  22. BIN
      src/assets/images/home-container/configurable/firehome/img-3.png
  23. BIN
      src/assets/images/home-container/configurable/firehome/img-4.png
  24. BIN
      src/assets/images/home-container/configurable/firehome/img-5.png
  25. BIN
      src/assets/images/home-container/configurable/firehome/img-6.png
  26. BIN
      src/assets/images/home-container/configurable/firehome/img-7.png
  27. BIN
      src/assets/images/home-container/configurable/firehome/list-head.png
  28. BIN
      src/assets/images/home-container/configurable/firehome/list.png
  29. BIN
      src/assets/images/home-container/configurable/firehome/miehuo.png
  30. BIN
      src/assets/images/home-container/configurable/firehome/qkjaq.png
  31. BIN
      src/assets/images/home-container/configurable/firehome/safety1.png
  32. BIN
      src/assets/images/home-container/configurable/firehome/safety2.png
  33. BIN
      src/assets/images/home-container/configurable/firehome/smoke.png
  34. BIN
      src/assets/images/home-container/configurable/firehome/temp.png
  35. BIN
      src/assets/images/home-container/configurable/firehome/title-1.png
  36. BIN
      src/assets/images/home-container/configurable/firehome/title-2.png
  37. BIN
      src/assets/images/home-container/configurable/firehome/title-3.png
  38. BIN
      src/assets/images/home-container/configurable/firehome/title-4.png
  39. BIN
      src/assets/images/home-container/configurable/firehome/ty-e.png
  40. BIN
      src/assets/images/home-container/configurable/firehome/work-jc.png
  41. BIN
      src/assets/images/home-container/configurable/firehome/zjxt.png
  42. BIN
      src/assets/images/home-container/configurable/firehome/zu-14578.png
  43. BIN
      src/assets/images/home-container/configurable/firehome/zu-e.png
  44. 7 0
      src/views/vent/deviceManager/configurationTable/index.vue
  45. 94 67
      src/views/vent/deviceManager/configurationTable/types.ts
  46. 231 0
      src/views/vent/home/configurable/components/ModuleBD.vue
  47. 23 8
      src/views/vent/home/configurable/components/ModuleCommon.vue
  48. 25 10
      src/views/vent/home/configurable/components/ModuleEnhanced.vue
  49. 27 7
      src/views/vent/home/configurable/components/ModuleOriginal.vue
  50. 45 71
      src/views/vent/home/configurable/components/content.vue
  51. 184 0
      src/views/vent/home/configurable/components/detail/ComplexList.vue
  52. 1 1
      src/views/vent/home/configurable/components/detail/CustomChart.vue
  53. 0 0
      src/views/vent/home/configurable/components/detail/CustomGallery.vue
  54. 18 0
      src/views/vent/home/configurable/components/detail/CustomList.vue
  55. 25 0
      src/views/vent/home/configurable/components/detail/CustomTable.vue
  56. 0 0
      src/views/vent/home/configurable/components/detail/GalleryList.vue
  57. 18 0
      src/views/vent/home/configurable/components/detail/MiniBoard.vue
  58. 0 2
      src/views/vent/home/configurable/components/detail/TimelineList.vue
  59. 1 9
      src/views/vent/home/configurable/components/enhanced/moduleBottom.vue
  60. 1 9
      src/views/vent/home/configurable/components/enhanced/moduleLeft.vue
  61. 1 9
      src/views/vent/home/configurable/components/enhanced/moduleRight.vue
  62. 13 4
      src/views/vent/home/configurable/components/header.vue
  63. 48 61
      src/views/vent/home/configurable/components/original/moduleBottom.vue
  64. 49 62
      src/views/vent/home/configurable/components/original/moduleLeft.vue
  65. 1 1
      src/views/vent/home/configurable/components/preset/FIreControl.vue
  66. 2 2
      src/views/vent/home/configurable/components/preset/FIreWarn.vue
  67. 232 60
      src/views/vent/home/configurable/configurable.data.ts
  68. 189 0
      src/views/vent/home/configurable/dustBD.vue
  69. 260 0
      src/views/vent/home/configurable/fireBD.vue
  70. 7 1
      src/views/vent/home/configurable/hooks/useInit.ts
  71. 180 0
      src/views/vent/home/configurable/index copy.vue
  72. 106 22
      src/views/vent/home/configurable/index.vue

BIN
src/assets/images/home-container/configurable/board_bg_1.png


BIN
src/assets/images/home-container/configurable/firehome/CH₄.png


BIN
src/assets/images/home-container/configurable/firehome/CO.png


BIN
src/assets/images/home-container/configurable/firehome/CO₂.png


BIN
src/assets/images/home-container/configurable/firehome/C₂H₂.png


BIN
src/assets/images/home-container/configurable/firehome/C₂H₄.png


BIN
src/assets/images/home-container/configurable/firehome/H₂.png


BIN
src/assets/images/home-container/configurable/firehome/NO₂.png


BIN
src/assets/images/home-container/configurable/firehome/N₂.png


BIN
src/assets/images/home-container/configurable/firehome/O₂.png


BIN
src/assets/images/home-container/configurable/firehome/bg.png


BIN
src/assets/images/home-container/configurable/firehome/co1.png


BIN
src/assets/images/home-container/configurable/firehome/common-border.png


BIN
src/assets/images/home-container/configurable/firehome/common-border1.png


BIN
src/assets/images/home-container/configurable/firehome/common-border2.png


BIN
src/assets/images/home-container/configurable/firehome/common-border3.png


BIN
src/assets/images/home-container/configurable/firehome/empty-qp.png


BIN
src/assets/images/home-container/configurable/firehome/fiber-jc.png


BIN
src/assets/images/home-container/configurable/firehome/ggxt.png


BIN
src/assets/images/home-container/configurable/firehome/img-1.png


BIN
src/assets/images/home-container/configurable/firehome/img-2.png


BIN
src/assets/images/home-container/configurable/firehome/img-3.png


BIN
src/assets/images/home-container/configurable/firehome/img-4.png


BIN
src/assets/images/home-container/configurable/firehome/img-5.png


BIN
src/assets/images/home-container/configurable/firehome/img-6.png


BIN
src/assets/images/home-container/configurable/firehome/img-7.png


BIN
src/assets/images/home-container/configurable/firehome/list-head.png


BIN
src/assets/images/home-container/configurable/firehome/list.png


BIN
src/assets/images/home-container/configurable/firehome/miehuo.png


BIN
src/assets/images/home-container/configurable/firehome/qkjaq.png


BIN
src/assets/images/home-container/configurable/firehome/safety1.png


BIN
src/assets/images/home-container/configurable/firehome/safety2.png


BIN
src/assets/images/home-container/configurable/firehome/smoke.png


BIN
src/assets/images/home-container/configurable/firehome/temp.png


BIN
src/assets/images/home-container/configurable/firehome/title-1.png


BIN
src/assets/images/home-container/configurable/firehome/title-2.png


BIN
src/assets/images/home-container/configurable/firehome/title-3.png


BIN
src/assets/images/home-container/configurable/firehome/title-4.png


BIN
src/assets/images/home-container/configurable/firehome/ty-e.png


BIN
src/assets/images/home-container/configurable/firehome/work-jc.png


BIN
src/assets/images/home-container/configurable/firehome/zjxt.png


BIN
src/assets/images/home-container/configurable/firehome/zu-14578.png


BIN
src/assets/images/home-container/configurable/firehome/zu-e.png


+ 7 - 0
src/views/vent/deviceManager/configurationTable/index.vue

@@ -3,6 +3,7 @@
   <BasicTable @register="registerTable">
     <template #tableTitle>
       <a-button preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd">新增</a-button>
+      <a-button preIcon="ant-design:question-circle-outlined" type="primary" @click="handleHelp">帮助</a-button>
     </template>
     <template #action="{ record }">
       <a class="table-action-link" @click="handleConfig(record)">配置</a>
@@ -36,6 +37,7 @@
   import { BasicModal } from '/@/components/Modal';
   import CodeEditor from '/@/components/CodeEditor/src/CodeEditor.vue';
   import { ModulePresetMap } from './options';
+  import helpContext from './types?raw';
 
   const formData = reactive({});
   const isUpdate = ref(false);
@@ -116,6 +118,11 @@
     openModal(true);
   }
 
+  function handleHelp() {
+    configJSON.value = helpContext;
+    configModalCtx.openModal();
+  }
+
   /**
    * 编辑事件
    */

+ 94 - 67
src/views/vent/deviceManager/configurationTable/types.ts

@@ -15,9 +15,75 @@ export interface Config {
   desc?: string;
 }
 
+/**
+ * 模块的配置
+ *
+ * 该配置将描述本模块的基础样式,应该展示哪些内容,应该如何排布主要元素
+ *
+ * 配置中有几项常用的配置,以下是部分说明:
+ *
+ * 假设模块依赖的数据为:`{ f1Val: 2555 }`;
+ *
+ * 配置中有许多 value、lable 都是遵循 formatter 格式的,formatter 格式可以用于自定义展示文本
+ *
+ * 使用示例:`f1的值为:${f1Val}呀!`。则对应的文本将是`f1的值为:2555呀!`
+ *
+ */
+export interface ModuleData {
+  header: {
+    /** 是否展示 header,header 的展示与否影响各个模块的 readFrom 实现,详细请阅读各模块的详细介绍 */
+    show: boolean;
+    /** 是否展示左侧的选择框 */
+    showSelector: boolean;
+    /** 是否展示右侧插槽 */
+    showSlot: boolean;
+    /** 左侧选择框的配置 */
+    selector: {
+      /** 展示的内容,formatter 格式 */
+      value: string;
+    };
+    /** 右侧插槽的配置 */
+    slot: {
+      /** 展示的内容,formatter 格式 */
+      value: string;
+    };
+  };
+  background: {
+    /** 是否展示背景 */
+    show: boolean;
+    /** 背景资源的类型 */
+    type: 'image' | 'video';
+    /** 背景资源的链接 */
+    link: string;
+  };
+  /** 模块的布局,使用规定的枚举组合为一个数组,代表着从上到下所应展示的元素 */
+  layout: ('board' | 'list' | 'chart' | 'table' | 'gallery' | 'complex_list' | 'gallery_list' | 'blast_delta' | 'fire_control' | 'fire_warn')[];
+  preset: ModuleDataPreset[];
+  board: ModuleDataBoard[];
+  chart: ModuleDataChart[];
+  list: ModuleDataList[];
+  table: ModuleDataTable[];
+  gallery: ModuleDataGallery[];
+  complex_list: ModuleDataComplexList[];
+  gallery_list: ModuleDataGalleryList[];
+  /** 如果目前没有数据可以对接,可使用模拟数据先行展示 */
+  mock?: any;
+  /** 如果模块需要跳转,可以在这里配置,不支持 formatter 格式 */
+  to?: string;
+}
+
+export interface ShowStyle {
+  /** 模块的宽高,特殊情况下可以自定义宽高 */
+  size: keyof typeof ModuleSizeMap;
+  /** 模块的版本,除了新版,只要有一个模块指定为旧版或其他版本,那么整个页面风格将变更为对应版本,优先级 旧版 > 普通版 > 新版 */
+  version: '原版' | '新版' | '普通版' | '保德';
+  /** 模块的位置,即定位,特殊情况下可以自定义定位 */
+  position: keyof typeof ModulePositionMap;
+}
+
 export interface ModuleDataBoard {
   /** 展示牌预设的背景类型 */
-  type: 'A' | 'B' | 'C' | 'D';
+  type: 'A' | 'B' | 'C' | 'D' | 'E';
   /** 展示牌布局,决定是 label 部分在上方或是 value 在上方 */
   layout: 'val-top' | 'label-top';
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
@@ -33,7 +99,7 @@ export interface ModuleDataBoard {
 
 export interface ModuleDataList {
   /** 列表预设的背景类型 */
-  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E';
+  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
   /** 核心配置,每个列表项对应一项 */
@@ -65,7 +131,7 @@ export interface ModuleDataGallery {
   }[];
 }
 
-export interface ModuleDataComplexList {
+export interface ModuleDataGalleryList {
   /** 复杂列表预设的背景类型 */
   type: 'A' | 'B';
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
@@ -91,6 +157,7 @@ export interface ModuleDataComplexList {
     color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
   }[];
 }
+
 export interface ModuleDataChart {
   /** 图表类型,一个类型对应一种图表预设 */
   type: 'pie' | 'bar' | 'line' | 'line_area';
@@ -120,19 +187,21 @@ export interface ModuleDataChart {
     prop: string;
   }[];
 }
+
 export interface ModuleDataTable {
   /** 表格的预设样式 */
-  type: 'A' | 'B';
+  type: 'A' | 'B' | 'C';
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
   /** 核心配置,每个表格列对应一项 */
   columns: {
-    /** 数据说明,formatter 格式 */
-    label: string;
+    /** 数据说明,注意该项不支持 formatter 格式 */
+    name: string;
     /** 取值 prop,注意该项不支持 formatter 格式 */
     prop: string;
   }[];
 }
+
 export interface ModuleDataPreset {
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
@@ -140,66 +209,24 @@ export interface ModuleDataPreset {
   [key: string]: any;
 }
 
-/**
- * 模块的配置
- *
- * 该配置将描述本模块的基础样式,应该展示哪些内容,应该如何排布主要元素
- *
- * 配置中有几项常用的配置,以下是部分说明:
- *
- * 假设模块依赖的数据为:`{ f1Val: 2555 }`;
- *
- * 配置中有许多 value、lable 都是遵循 formatter 格式的,formatter 格式可以用于自定义展示文本
- *
- * 使用示例:`f1的值为:${f1Val}呀!`。则对应的文本将是`f1的值为:2555呀!`
- *
- */
-export interface ModuleData {
-  header: {
-    /** 是否展示 header,header 的展示与否影响各个模块的 readFrom 实现,详细请阅读各模块的详细介绍 */
-    show: boolean;
-    /** 是否展示左侧的选择框 */
-    showSelector: boolean;
-    /** 是否展示右侧插槽 */
-    showSlot: boolean;
-    /** 左侧选择框的配置 */
-    selector: {
-      /** 展示的内容,formatter 格式 */
-      value: string;
-    };
-    /** 右侧插槽的配置 */
-    slot: {
-      /** 展示的内容,formatter 格式 */
+export interface ModuleDataComplexList {
+  /** 列表预设的背景类型 */
+  type: 'A' | 'B';
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
+  readFrom: string;
+  /** 核心配置,每个列表项对应一项 */
+  items: {
+    /** 列表项标题,formatter 格式 */
+    title: string;
+    contents: {
+      /** 列表项说明内容,formatter 格式 */
+      label: string;
+      /** 列表项值内容,formatter 格式 */
       value: string;
-    };
-  };
-  background: {
-    /** 是否展示背景 */
-    show: boolean;
-    /** 背景资源的类型 */
-    type: 'image' | 'video';
-    /** 背景资源的链接 */
-    link: string;
-  };
-  /** 模块的布局,使用规定的枚举组合为一个数组,代表着从上到下所应展示的元素 */
-  layout: ('board' | 'list' | 'chart' | 'table' | 'gallery' | 'complex_list' | 'blast_delta' | 'fire_control' | 'fire_warn')[];
-  preset: ModuleDataPreset[];
-  board: ModuleDataBoard[];
-  chart: ModuleDataChart[];
-  list: ModuleDataList[];
-  table: ModuleDataTable[];
-  gallery: ModuleDataGallery[];
-  complex_list: ModuleDataComplexList[];
-  /** 如果目前没有数据可以对接,可使用模拟数据先行展示 */
-  mock?: any;
-  /** 如果模块需要跳转,可以在这里配置,不支持 formatter 格式 */
-  to?: string;
-}
-export interface ShowStyle {
-  /** 模块的宽高,特殊情况下可以自定义宽高 */
-  size: keyof typeof ModuleSizeMap;
-  /** 模块的版本,除了新版,只要有一个模块指定为旧版或其他版本,那么整个页面风格将变更为对应版本,优先级 旧版 > 普通版 > 新版 */
-  version: '原版' | '新版' | '普通版';
-  /** 模块的位置,即定位,特殊情况下可以自定义定位 */
-  position: keyof typeof ModulePositionMap;
+      /** 列表项指定颜色,根据类型不同会有各自的样式 */
+      color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
+      /** 针对列表项说明的额外信息,部分类型的列表项会使用 */
+      info: string;
+    }[];
+  }[];
 }

+ 231 - 0
src/views/vent/home/configurable/components/ModuleBD.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="dane-bd" :style="style" :class="daneClass">
+    <div v-if="moduleName" class="dane-title">
+      <div class="common-navL">{{ moduleName }}</div>
+
+      <div class="common-navR">
+        <!-- 下拉框 -->
+        <div class="common-navR-select" v-if="header.show && header.showSelector">
+          <a-select
+            style="width: 140px"
+            size="small"
+            placeholder="请选择"
+            v-model:value="selectedDeviceID"
+            allowClear
+            :options="options"
+            @change="selectHandler"
+          />
+        </div>
+        <!-- 日期组件 -->
+        <!-- <div class="common-navR-date" v-if="header.show && header.showSlot">
+          <a-range-picker
+            size="small"
+            style="width: 140px"
+            :show-time="{ format: 'HH:mm' }"
+            format="YYYY-MM-DD HH:mm"
+            :placeholder="['开始时间', '结束时间']"
+            @change="onChange"
+            @ok="onOk"
+          />
+        </div> -->
+        <!-- 开关组件 -->
+        <!-- <div class="common-navR-switch" v-if="commonTitle == 'switchs'">
+            <div :class="checked ? 'status-text1' : 'status-text'">风险来源</div>
+            <a-switch v-model:checked="checked" />
+            <div :class="checked ? 'status-text' : 'status-text1'">危险位置</div>
+          </div> -->
+      </div>
+    </div>
+    <slot>
+      <Content :style="{ height: '100%' }" :moduleData="moduleData" :data="selectedDevice" />
+    </slot>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import Content from './content.vue';
+  import { defineProps, defineEmits, computed, onMounted } from 'vue';
+  import { ModuleData, ShowStyle } from '../../../deviceManager/configurationTable/types';
+  import { useInitDevices } from '../hooks/useInit';
+
+  const props = defineProps<{
+    moduleData: ModuleData;
+    showStyle: ShowStyle;
+    moduleName: string;
+    deviceType: string;
+    visible: boolean;
+  }>();
+  const emit = defineEmits(['close', 'select']);
+
+  const { header } = props.moduleData;
+
+  const { selectedDeviceID, selectedDevice, options, fetchDevices } = useInitDevices(props.deviceType, props.moduleData.header);
+
+  const style = computed(() => {
+    const size = props.showStyle.size;
+    const position = props.showStyle.position;
+    return size + position;
+  });
+
+  // 根据配置里的定位判断应该使用哪个module组件
+  const daneClass = computed(() => {
+    const position = props.showStyle.position;
+    if (!props.moduleName) {
+      return 'dane-s';
+    }
+    if (position.includes('left:0')) {
+      return 'dane-m';
+    }
+    if (position.includes('right:0')) {
+      return 'dane-m';
+    }
+    return 'dane-w';
+  });
+
+  //切换时间选项
+  // function onChange(value, dateString) {
+  //   console.log('Selected Time: ', value);
+  //   console.log('Formatted Selected Time: ', dateString);
+  // }
+  // function onOk(val) {
+  //   console.log('onOk: ', val);
+  // }
+
+  //下拉框选项切换
+  function selectHandler({ key }) {
+    selectedDeviceID.value = key;
+    emit('select', selectedDevice);
+  }
+
+  onMounted(() => {
+    fetchDevices();
+  });
+</script>
+
+<style scoped lang="less">
+  .dane-bd {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+
+    .dane-title {
+      display: flex;
+      box-sizing: border-box;
+      align-items: center;
+      justify-content: space-between;
+      width: 100%;
+      height: 34px;
+      padding: 0 30px 0 50px;
+
+      .common-navL {
+        display: flex;
+        position: relative;
+        align-items: center;
+        color: #fff;
+        font-size: 14px;
+      }
+
+      .common-navR {
+        display: flex;
+        align-items: center;
+        justify-content: flex-end;
+      }
+
+      // .common-navR-switch {
+      //   display: flex;
+      //   align-items: center;
+      //   justify-content: space-around;
+      //   width: 90%;
+
+      //   .status-text {
+      //     color: #1fb3f7;
+      //     font-size: 14px;
+      //   }
+
+      //   .status-text1 {
+      //     color: #a1dff8;
+      //     font-size: 14px;
+      //   }
+      // }
+    }
+
+    .dane-content {
+      position: relative;
+      box-sizing: border-box;
+      width: 100%;
+      padding: 10px;
+    }
+  }
+
+  .dane-l {
+    background: url('@/assets/images/home-container/configurable/firehome/common-border.png') no-repeat;
+    background-size: 100% auto;
+  }
+
+  .dane-m {
+    background: url('@/assets/images/home-container/configurable/firehome/common-border1.png') no-repeat;
+    background-size: 100% auto;
+  }
+
+  .dane-s {
+    background: url('@/assets/images/home-container/configurable/firehome/common-border2.png') no-repeat;
+    background-size: 100% auto;
+  }
+
+  .dane-w {
+    background: url('@/assets/images/home-container/configurable/firehome/common-border3.png') no-repeat;
+    background-size: 100% auto;
+  }
+
+  :deep(.vMonitor-select-selector) {
+    height: 22px !important;
+    border: none !important;
+    // background-color: rgb(15 64 88) !important;
+    background-color: transparent !important;
+    color: #8087a1 !important;
+  }
+
+  :deep(.vMonitor-select-selection-placeholder) {
+    color: #8087a1 !important;
+  }
+
+  :deep(.vMonitor-select-arrow) {
+    color: #8087a1 !important;
+  }
+
+  :deep(.vMonitor-picker) {
+    border: none !important;
+    background-color: rgb(15 64 88) !important;
+    box-shadow: none;
+    color: #a1dff8 !important;
+  }
+
+  :deep(.vMonitor-picker-input > input) {
+    color: #a1dff8 !important;
+    text-align: center !important;
+  }
+
+  :deep(.vMonitor-picker-separator) {
+    color: #a1dff8 !important;
+  }
+
+  :deep(.vMonitor-picker-active-bar) {
+    display: none !important;
+  }
+
+  :deep(.vMonitor-picker-suffix) {
+    color: #a1dff8 !important;
+  }
+
+  :deep(.vMonitor-switch) {
+    min-width: 48px !important;
+  }
+
+  :deep(.vMonitor-switch-checked) {
+    background-color: rgb(15 64 89) !important;
+  }
+
+  :deep(.vMonitor-switch-handle::before) {
+    background-color: rgb(33 179 247) !important;
+  }
+</style>

+ 23 - 8
src/views/vent/home/configurable/components/ModuleCommon.vue

@@ -1,26 +1,38 @@
 <template>
+  <!-- 常用模块 -->
   <ventBox1 class="module-common" :style="style">
-    <template #title>
-      <div @click="clickHandler">{{ moduleName }}</div>
+    <template v-if="moduleName" #title>
+      <div @click="redirectTo">{{ moduleName }}</div>
     </template>
     <template #container>
-      <slot></slot>
+      <slot>
+        <Header :deviceType="deviceType" :headerConfig="header" @select="selectedData = $event" />
+        <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
+      </slot>
     </template>
   </ventBox1>
 </template>
 <script lang="ts" setup>
+  import Header from './header.vue';
+  import Content from './content.vue';
   // import ModuleLeft from './original/moduleLeft.vue';
   // import ModuleBottom from './original/moduleBottom.vue';
-  import { computed } from 'vue';
-  import { ShowStyle } from '../../../deviceManager/configurationTable/types';
+  import { computed, ref } from 'vue';
+  import { ShowStyle, ModuleData } from '../../../deviceManager/configurationTable/types';
   import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import { openWindow } from '/@/utils';
 
   const props = defineProps<{
+    moduleData: ModuleData;
     showStyle: ShowStyle;
     moduleName: string;
+    deviceType: string;
     visible: boolean;
   }>();
-  const emit = defineEmits(['close', 'click']);
+  defineEmits(['close', 'click']);
+
+  const { header } = props.moduleData;
+  const selectedData = ref();
 
   const style = computed(() => {
     const size = props.showStyle.size;
@@ -35,8 +47,11 @@
   //   }
   //   return ModuleLeft;
   // }
-  function clickHandler() {
-    emit('click');
+
+  function redirectTo() {
+    const { to } = props.moduleData;
+    if (!to) return;
+    openWindow(to);
   }
 </script>
 <style scoped>

+ 25 - 10
src/views/vent/home/configurable/components/ModuleEnhanced.vue

@@ -1,29 +1,41 @@
 <template>
+  <!-- 新版模块 -->
   <component
     :is="getModuleComponent(showStyle.position)"
     :style="style"
     :title="moduleName"
     :visible="visible"
     @close="$emit('close')"
-    @click="$emit('click')"
+    @click="redirectTo"
   >
-    <slot></slot>
+    <slot>
+      <Header :deviceType="deviceType" :headerConfig="header" @select="selectedData = $event" />
+      <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
+    </slot>
   </component>
 </template>
 <script lang="ts" setup>
+  import Header from './header.vue';
+  import Content from './content.vue';
   import ModuleLeft from './enhanced/moduleLeft.vue';
   import ModuleRight from './enhanced/moduleRight.vue';
   import ModuleBottom from './enhanced/moduleBottom.vue';
-  import { computed } from 'vue';
-  import { ShowStyle } from '../../../deviceManager/configurationTable/types';
+  import { computed, ref } from 'vue';
+  import { ShowStyle, ModuleData } from '../../../deviceManager/configurationTable/types';
+  import { openWindow } from '/@/utils';
 
   const props = defineProps<{
+    moduleData: ModuleData;
     showStyle: ShowStyle;
     moduleName: string;
+    deviceType: string;
     visible: boolean;
   }>();
   defineEmits(['close', 'click']);
 
+  const { header } = props.moduleData;
+  const selectedData = ref();
+
   const style = computed(() => {
     const size = props.showStyle.size;
     const position = props.showStyle.position;
@@ -32,15 +44,18 @@
 
   // 根据配置里的定位判断应该使用哪个module组件
   function getModuleComponent(position) {
-    if (position.includes('')) {
+    if (position.includes('left:0')) {
       return ModuleLeft;
     }
-    if (position.includes('')) {
+    if (position.includes('right:0')) {
       return ModuleRight;
     }
-    if (position === '中下') {
-      return ModuleBottom;
-    }
-    return ModuleLeft; //
+    return ModuleBottom;
+  }
+
+  function redirectTo() {
+    const { to } = props.moduleData;
+    if (!to) return;
+    openWindow(to);
   }
 </script>

+ 27 - 7
src/views/vent/home/configurable/components/ModuleOriginal.vue

@@ -1,28 +1,40 @@
 <template>
+  <!-- 原版模块 -->
   <component
     :is="getModuleComponent(showStyle.position)"
     :style="style"
     :title="moduleName"
     :visible="visible"
     @close="$emit('close')"
-    @click="$emit('click')"
+    @click="redirectTo"
   >
-    <slot></slot>
+    <slot>
+      <Header :deviceType="deviceType" :headerConfig="header" @select="selectedData = $event" />
+      <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
+    </slot>
   </component>
 </template>
 <script lang="ts" setup>
+  import Header from './header.vue';
+  import Content from './content.vue';
   import ModuleLeft from './original/moduleLeft.vue';
   import ModuleBottom from './original/moduleBottom.vue';
-  import { computed } from 'vue';
-  import { ShowStyle } from '../../../deviceManager/configurationTable/types';
+  import { computed, ref } from 'vue';
+  import { ShowStyle, ModuleData } from '../../../deviceManager/configurationTable/types';
+  import { openWindow } from '/@/utils';
 
   const props = defineProps<{
+    moduleData: ModuleData;
     showStyle: ShowStyle;
     moduleName: string;
+    deviceType: string;
     visible: boolean;
   }>();
   defineEmits(['close', 'click']);
 
+  const { header } = props.moduleData;
+  const selectedData = ref();
+
   const style = computed(() => {
     const size = props.showStyle.size;
     const position = props.showStyle.position;
@@ -31,9 +43,17 @@
 
   // 根据配置里的定位判断应该使用哪个module组件
   function getModuleComponent(position) {
-    if (position === '中下') {
-      return ModuleBottom;
+    if (position.includes('left:0')) {
+      return ModuleLeft;
+    }
+    if (position.includes('right:0')) {
+      return ModuleLeft;
     }
-    return ModuleLeft;
+    return ModuleBottom;
+  }
+  function redirectTo() {
+    const { to } = props.moduleData;
+    if (!to) return;
+    openWindow(to);
   }
 </script>

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

@@ -1,42 +1,7 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <!-- Header部分 -->
-  <div v-if="headerConfig.show" class="w-100% flex content__header">
-    <!-- 选择下拉框,自动填充剩余空间,这种实现是因为 Select 不支持 suffix -->
-    <Dropdown
-      v-if="headerConfig.showSelector"
-      class="flex-grow-1 content__header_left"
-      :trigger="['click']"
-      :bordered="false"
-      @open-change="headerVisible = $event"
-    >
-      <div class="w-100% flex flex-items-center" @click.prevent>
-        <SwapOutlined class="w-30px" />
-        <div class="flex-grow-1">
-          {{ selectedDeviceLabel }}
-        </div>
-        <CaretUpOutlined class="w-30px" v-if="headerVisible" />
-        <CaretDownOutlined class="w-30px" v-else />
-      </div>
-      <template #overlay>
-        <Menu :selected-keys="[selectedDeviceID]" @click="headerSelectHandler">
-          <MenuItem v-for="item in options" :key="item.value" :title="item.label">
-            {{ item.label }}
-          </MenuItem>
-        </Menu>
-      </template>
-    </Dropdown>
-    <template v-if="headerConfig.showSlot">
-      <div class="flex flex-items-center flex-grow-1 content__header_right">
-        <SwapOutlined class="w-30px" />
-        <div class="flex-grow-1">
-          {{ selectedDeviceSlot }}
-        </div>
-      </div>
-    </template>
-  </div>
   <!-- 主体内容部分 -->
-  <div class="content" :class="{ content_without_header: !headerConfig.show }">
+  <div class="content">
     <!-- 背景 -->
     <img v-if="background.show && background.type === 'image'" class="content__background" :src="background.link" />
     <video
@@ -80,8 +45,12 @@
         <CustomGallery class="content__module" :type="config.type" :gallery-config="config.items" />
       </template>
       <!-- 复杂列表部分 -->
+      <template v-if="config.key === 'gallery_list'">
+        <GalleryList class="content__module" :type="config.type" :list-config="config.items" :gallery-config="config.galleryItems" />
+      </template>
+      <!-- 复杂列表部分 -->
       <template v-if="config.key === 'complex_list'">
-        <ComplexList class="content__module" :type="config.type" :list-config="config.items" :gallery-config="config.galleryItems" />
+        <ComplexList class="content__module" :type="config.type" :list-config="config.items" />
       </template>
       <!-- 表格部分,这部分通常是占一整个模块的 -->
       <template v-if="config.key === 'table'">
@@ -112,7 +81,7 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { computed, onMounted, ref } from 'vue';
+  import { computed } from 'vue';
   import {
     Config,
     // ModuleDataBoard,
@@ -121,41 +90,29 @@
     // ModuleDataPreset,
     // ModuleDataTable,
   } from '../../../deviceManager/configurationTable/types';
-  import { useInitDevices } from '../hooks/useInit';
-  import { MenuItem, Menu, Dropdown } from 'ant-design-vue';
-  import { SwapOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons-vue';
-  import MiniBoard from './MiniBoard.vue';
-  import TimelineList from './TimelineList.vue';
-  import CustomList from './CustomList.vue';
-  import CustomGallery from './CustomGallery.vue';
-  import ComplexList from './ComplexList.vue';
-  import CustomTable from './CustomTable.vue';
-  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
-  import CustomChart from './CustomChart.vue';
+  import MiniBoard from './detail/MiniBoard.vue';
+  import TimelineList from './detail/TimelineList.vue';
+  import CustomList from './detail/CustomList.vue';
+  import CustomGallery from './detail/CustomGallery.vue';
+  import ComplexList from './detail/ComplexList.vue';
+  import GalleryList from './detail/GalleryList.vue';
+  import CustomTable from './detail/CustomTable.vue';
+  import CustomChart from './detail/CustomChart.vue';
   import { get, clone } from 'lodash-es';
+  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
   import CommonTable from '../../billboard/components/CommonTable.vue';
   import BlastDelta from '../../../monitorManager/deviceMonitor/components/device/modal/blastDelta.vue';
-  import FIreWarn from './FIreWarn.vue';
-  import FIreControl from './FIreControl.vue';
+  import FIreWarn from './preset/FIreWarn.vue';
+  import FIreControl from './preset/FIreControl.vue';
 
   const props = defineProps<{
-    deviceType: Config['deviceType'];
+    data: any;
     moduleData: Config['moduleData'];
-    showStyle: Config['showStyle'];
   }>();
 
-  const { header: headerConfig, background, layout, mock } = props.moduleData;
+  const { background, layout, mock } = props.moduleData;
 
   // 额外的 header 相关的变量
-  const headerVisible = ref(false);
-  function headerSelectHandler({ key }) {
-    selectedDeviceID.value = key;
-  }
-
-  const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
-    props.deviceType,
-    headerConfig
-  );
 
   function getData(raw, readFrom) {
     if (mock) return mock;
@@ -167,11 +124,12 @@
 
   /** 根据配置里的layout将配置格式化为带 key 的具体配置,例如:[{ key: 'list', value: any, ...ModuleDataList }] */
   const layoutConfig = computed(() => {
-    const refData = selectedDevice.value;
+    const refData = props.data;
     const board = clone(props.moduleData.board);
     const list = clone(props.moduleData.list);
     const gallery = clone(props.moduleData.gallery);
     const complex_list = clone(props.moduleData.complex_list);
+    const gallery_list = clone(props.moduleData.gallery_list);
     const chart = clone(props.moduleData.chart);
     const table = clone(props.moduleData.table);
     const preset = clone(props.moduleData.preset);
@@ -242,6 +200,29 @@
             key,
             items: cfg.items.map((i) => {
               return {
+                title: getFormattedText(data, i.title),
+                contents: i.contents.map((e) => {
+                  return {
+                    ...e,
+                    label: getFormattedText(data, e.label),
+                    value: getFormattedText(data, e.value),
+                  };
+                }),
+              };
+            }),
+          });
+          break;
+        }
+        case 'gallery_list': {
+          const cfg = gallery_list.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom);
+
+          arr.push({
+            ...cfg,
+            key,
+            items: cfg.items.map((i) => {
+              return {
                 ...i,
                 label: getFormattedText(data, i.label),
                 value: getFormattedText(data, i.value),
@@ -298,10 +279,6 @@
       return arr;
     }, []);
   });
-
-  onMounted(() => {
-    fetchDevices();
-  });
 </script>
 <style lang="less" scoped>
   @import '@/design/vent/color.less';
@@ -331,9 +308,6 @@
     display: flex;
     flex-direction: column;
   }
-  .content_without_header {
-    height: 100%;
-  }
   .content__background {
     width: 100%;
     height: 100%;

+ 184 - 0
src/views/vent/home/configurable/components/detail/ComplexList.vue

@@ -0,0 +1,184 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <!-- 基准的列表模块,通过不同的 type 展示不同的样式 -->
+  <div class="list flex items-center" :class="`list_${type}`">
+    <!-- 部分类型的列表需要加一张图片 -->
+    <div :class="`list__image_${type}`"></div>
+    <!-- 剩下的部分填充剩余宽度 -->
+    <div class="flex-grow" :class="`list__wrapper_${type}`">
+      <div v-for="(item, i) in listConfig" :key="`vvhccdcl${i}`" :class="`list-item_${type}`">
+        <!-- 列表项前面的图标 -->
+        <div :class="`list-item__title_${type}`">{{ item.title }}</div>
+        <!-- 列表项的具体内容填充剩余宽度 -->
+        <div v-for="(ctx, j) in item.contents" :key="`vvhccdclc${j}`" :class="`list-item__content_${type}`">
+          <div class="list-item__label">{{ ctx.label }}</div>
+          <div class="list-item__info" :class="`list-item__info_${ctx.color}`">{{ ctx.info }}</div>
+          <div class="list-item__value" :class="`list-item__value_${ctx.color} 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;
+        }[];
+      }[];
+      /** A B */
+      type: string;
+    }>(),
+    {
+      listConfig: () => [],
+      type: 'A',
+    }
+  );
+
+  //   defineEmits(['click']);
+</script>
+<style lang="less" scoped>
+  @import '@/design/vent/color.less';
+  /* Timeline 相关的样式 */
+
+  .list {
+    padding: 5px 20px;
+    position: relative;
+    width: 100%;
+    height: 100%;
+  }
+
+  .list-item_A {
+    position: relative;
+    height: 155px;
+    background-repeat: no-repeat;
+    background-image: url(/@/assets/images/home-container/configurable/firehome/img-3.png);
+  }
+  .list-item__title_A {
+    position: absolute;
+    left: 35%;
+    font-size: 20px;
+    top: 15px;
+  }
+  // .list-item__content_A {
+  //   position: absolute;
+  //   left: 35%;
+  //   top: 55px;
+  //   display: flex;
+  //   justify-content: space-evenly;
+  // }
+  .list-item__content_A:nth-of-type(2) {
+    position: absolute;
+    top: 15px;
+    left: 5%;
+    width: 22%;
+    text-align: center;
+    display: block;
+
+    .list-item__label {
+      font-size: 20px;
+      margin-bottom: 25px;
+    }
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 24px;
+    }
+  }
+  .list-item__content_A:nth-of-type(3) {
+    position: absolute;
+    left: 35%;
+    top: 55px;
+
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 20px;
+    }
+  }
+  .list-item__content_A:nth-of-type(4) {
+    position: absolute;
+    left: 60%;
+    top: 55px;
+
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 20px;
+    }
+  }
+  .list-item__content_A:nth-of-type(5) {
+    position: absolute;
+    left: 35%;
+    bottom: 10px;
+    display: flex;
+    align-items: center;
+
+    .list-item__info {
+      display: none;
+    }
+    .list-item__value {
+      font-size: 20px;
+      margin-left: 5px;
+    }
+  }
+
+  .list-item_B {
+    // height: 155px;
+    background-repeat: no-repeat;
+    background-size: 100% auto;
+    background-position: center;
+    background-image: url(/@/assets/images/home-container/configurable/firehome/fiber-jc.png);
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    text-align: center;
+    padding-right: 20px;
+
+    .list-item__content_B {
+      display: flex;
+    }
+    .list-item__title_B {
+      flex-basis: 24%;
+    }
+    .list-item__info {
+      display: none;
+    }
+  }
+
+  // .list-item__label {
+  //   flex-basis: 55%;
+  // }
+  // .list-item__info {
+  //   flex-grow: 1;
+  // }
+  // .list-item__value {
+  //   flex-basis: 30%;
+  // }
+  .list-item__value_red {
+    color: red;
+  }
+  .list-item__value_orange {
+    color: orange;
+  }
+  .list-item__value_yellow {
+    color: yellow;
+  }
+  .list-item__value_green {
+    color: yellowgreen;
+  }
+  .list-item__value_blue {
+    color: lightblue;
+  }
+  .list-item__value_white {
+    color: white;
+  }
+</style>

+ 1 - 1
src/views/vent/home/configurable/components/CustomChart.vue → src/views/vent/home/configurable/components/detail/CustomChart.vue

@@ -7,7 +7,7 @@
   import { get } from 'lodash-es';
   import { Config } from '/@/views/vent/deviceManager/configurationTable/types';
   import { EChartsOption, graphic } from 'echarts';
-  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
+  import { getFormattedText } from '../../../../deviceManager/configurationTable/adapters';
 
   const props = withDefaults(
     defineProps<{

+ 0 - 0
src/views/vent/home/configurable/components/CustomGallery.vue → src/views/vent/home/configurable/components/detail/CustomGallery.vue


+ 18 - 0
src/views/vent/home/configurable/components/CustomList.vue → src/views/vent/home/configurable/components/detail/CustomList.vue

@@ -162,6 +162,24 @@
     padding-top: 32px;
     font-size: 12px;
   }
+
+  .list_F {
+    background: none;
+  }
+  .list-item__content_F {
+    height: 40px;
+    background-repeat: no-repeat;
+    padding: 0 50px 0 50px;
+    display: flex;
+    background-position: center;
+    background-size: 100% auto;
+    background-image: url(/@/assets/images/home-container/configurable/firehome/list.png);
+    margin-bottom: 10px;
+    text-align: center;
+  }
+  .list-item__content_F > div {
+    flex-basis: 33.3%;
+  }
   // .list-item__icon_red {
   //   background-image: url('@/assets/images/home-container/configurable/warn_icon_5.png');
   // }

+ 25 - 0
src/views/vent/home/configurable/components/CustomTable.vue → src/views/vent/home/configurable/components/detail/CustomTable.vue

@@ -22,6 +22,7 @@
 
   let props = withDefaults(
     defineProps<{
+      /** B | C */
       type: string;
       /** 列表表头配置,每个prop都有其对应的slot来提供定制化功能 */
       columns: { prop: string; name: string }[];
@@ -80,6 +81,21 @@
       background-repeat: no-repeat;
       color: #31b9ef;
     }
+    .table__content_label_C {
+      // border: 1px solid @vent-gas-tab-border;
+      background-position: center 100%;
+      background-size: 100% 25px;
+      background-repeat: no-repeat;
+      background-image: url('@/assets/images/company/content-text.png');
+      height: 40px;
+
+      .label-t {
+        background-repeat: no-repeat;
+        background-size: 80% auto;
+        background-position: center;
+        background-image: url('/@/assets/images/home-container/configurable/firehome/list-head.png');
+      }
+    }
 
     .table__content_list {
       height: calc(100% - 32px);
@@ -110,5 +126,14 @@
       //   border: 1px solid @vent-gas-tab-border;
       // }
     }
+
+    .table__content_list_C {
+      .table__content_list_row {
+        // background-position: center;
+        background-size: 100% auto;
+        background-repeat: no-repeat;
+        background-image: url('@/assets/images/company/content-text.png');
+      }
+    }
   }
 </style>

+ 0 - 0
src/views/vent/home/configurable/components/ComplexList.vue → src/views/vent/home/configurable/components/detail/GalleryList.vue


+ 18 - 0
src/views/vent/home/configurable/components/MiniBoard.vue → src/views/vent/home/configurable/components/detail/MiniBoard.vue

@@ -86,6 +86,14 @@
     background-position: center bottom;
     background-repeat: no-repeat;
   }
+  .mini-board_E {
+    width: 95px;
+    height: 100px;
+    padding: 20px 0 0 0;
+    background-image: url('/@/assets/images/home-container/configurable/board_bg_1.png');
+    background-position: center bottom;
+    background-repeat: no-repeat;
+  }
 
   .mini-board__value_A {
     color: @vent-gas-primary-text;
@@ -129,4 +137,14 @@
     line-height: 17px;
     height: 17px;
   }
+  .mini-board__value_E {
+    font-size: 20px;
+    font-weight: bold;
+    height: 76px;
+    line-height: 76px;
+  }
+  .mini-board__label_E {
+    line-height: 17px;
+    height: 17px;
+  }
 </style>

+ 0 - 2
src/views/vent/home/configurable/components/TimelineList.vue → src/views/vent/home/configurable/components/detail/TimelineList.vue

@@ -25,8 +25,6 @@
       listConfig: () => [],
     }
   );
-
-  //   defineEmits(['click']);
 </script>
 <style lang="less" scoped>
   @import '@/design/vent/color.less';

+ 1 - 9
src/views/vent/home/configurable/components/enhanced/moduleBottom.vue

@@ -1,8 +1,7 @@
 <template>
   <Transition class="module-bottom">
-    <!-- 正常展示模块时 -->
     <div v-if="visible" class="module-content">
-      <div class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>
@@ -10,13 +9,6 @@
         <slot></slot>
       </div>
     </div>
-    <!-- 隐藏模块时 -->
-    <!-- <div v-else class="w-100%">
-      <div class="module-content__title">
-        <span class="action-btn show-btn" @click="showModel"></span>
-        {{ title }}
-      </div>
-    </div> -->
   </Transition>
 </template>
 <script lang="ts" setup>

+ 1 - 9
src/views/vent/home/configurable/components/enhanced/moduleLeft.vue

@@ -1,8 +1,7 @@
 <template>
   <Transition class="module-left">
-    <!-- 正常展示模块时 -->
     <div v-if="visible" class="module-content">
-      <div class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>
@@ -10,13 +9,6 @@
         <slot></slot>
       </div>
     </div>
-    <!-- 隐藏模块时 -->
-    <!-- <div v-else class="w-100%">
-      <div class="module-content__title">
-        <span class="action-btn show-btn" @click="showModel"></span>
-        {{ title }}
-      </div>
-    </div> -->
   </Transition>
 </template>
 <script lang="ts" setup>

+ 1 - 9
src/views/vent/home/configurable/components/enhanced/moduleRight.vue

@@ -1,8 +1,7 @@
 <template>
   <Transition class="module-right">
-    <!-- 正常展示模块时 -->
     <div v-if="visible" class="module-content">
-      <div class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>
@@ -10,13 +9,6 @@
         <slot></slot>
       </div>
     </div>
-    <!-- 隐藏模块时 -->
-    <!-- <div v-else class="w-100%">
-      <div class="module-content__title">
-        <span class="action-btn show-btn" @click="showModel"></span>
-        {{ title }}
-      </div>
-    </div> -->
   </Transition>
 </template>
 <script lang="ts" setup>

+ 13 - 4
src/views/vent/home/configurable/components/customHeader.vue → src/views/vent/home/configurable/components/header.vue

@@ -1,9 +1,11 @@
+<!-- eslint-disable vue/multi-word-component-names -->
 <template>
-  <div v-if="headerConfig.show" class="w-100% flex costume-header__header">
+  <!-- Header部分 -->
+  <div v-if="headerConfig.show" class="w-100% flex content__header">
     <!-- 选择下拉框,自动填充剩余空间,这种实现是因为 Select 不支持 suffix -->
     <Dropdown
       v-if="headerConfig.showSelector"
-      class="flex-grow-1 costume-header__header_left"
+      class="flex-grow-1 content__header_left"
       :trigger="['click']"
       :bordered="false"
       @open-change="visible = $event"
@@ -17,7 +19,7 @@
         <CaretDownOutlined class="w-30px" v-else />
       </div>
       <template #overlay>
-        <Menu :selected-keys="[selectedDeviceID]" @click="selectedDeviceID = $event">
+        <Menu :selected-keys="[selectedDeviceID]" @click="selectHandler">
           <MenuItem v-for="item in options" :key="item.value" :title="item.label">
             {{ item.label }}
           </MenuItem>
@@ -25,7 +27,7 @@
       </template>
     </Dropdown>
     <template v-if="headerConfig.showSlot">
-      <div class="costume-header__header_right">
+      <div class="flex flex-items-center flex-grow-1 content__header_right">
         <SwapOutlined class="w-30px" />
         <div class="flex-grow-1">
           {{ selectedDeviceSlot }}
@@ -45,12 +47,19 @@
     deviceType: Config['deviceType'];
   }>();
 
+  const emit = defineEmits(['select']);
+
   const visible = ref(false);
   const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
     props.deviceType,
     props.headerConfig
   );
 
+  function selectHandler({ key }) {
+    selectedDeviceID.value = key;
+    emit('select', selectedDevice);
+  }
+
   onMounted(() => {
     fetchDevices();
   });

+ 48 - 61
src/views/vent/home/configurable/components/original/moduleBottom.vue

@@ -1,23 +1,13 @@
 <template>
-  <Transition class="module-bottom">
-    <!-- 正常展示模块时 -->
-    <div v-if="visible" class="module-content">
-      <div class="module-content__title__expand">
-        <span class="action-btn close-btn" @click="closeModel"></span>
-        <span @click="clickHandler">{{ title }}</span>
-      </div>
-      <div class="module-slot">
-        <slot></slot>
-      </div>
+  <div v-if="visible" class="module-content">
+    <div v-if="title" class="module-content__title__expand">
+      <span class="action-btn close-btn" @click="closeModel"></span>
+      <span @click="clickHandler">{{ title }}</span>
     </div>
-    <!-- 隐藏模块时 -->
-    <!-- <div v-else class="w-100%">
-      <div class="module-content__title">
-        <span class="action-btn show-btn" @click="showModel"></span>
-        {{ title }}
-      </div>
-    </div> -->
-  </Transition>
+    <div class="module-slot">
+      <slot></slot>
+    </div>
+  </div>
 </template>
 <script lang="ts" setup>
   defineProps<{ title: string; visible: boolean }>();
@@ -31,57 +21,54 @@
   }
 </script>
 <style lang="less" scoped>
-  .module-bottom {
+  .module-content {
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
     position: absolute;
+    width: 100%;
+    height: 100%;
+  }
 
-    .module-content {
-      width: 100%;
-      height: 100%;
-    }
-
-    .module-content__title__expand {
-      width: 100%;
-      height: var(--bg-height);
-      background: url('@/assets/images/home-container/configurable/model_original_title_bg_expand.png') no-repeat;
-      background-size: 100% 100%;
-      position: relative;
-      text-align: center;
-      line-height: var(--bg-height);
-    }
+  .module-content__title__expand {
+    width: 100%;
+    height: var(--bg-height);
+    background: url('@/assets/images/home-container/configurable/model_original_title_bg_expand.png') no-repeat;
+    background-size: 100% 100%;
+    position: relative;
+    text-align: center;
+    line-height: var(--bg-height);
+  }
 
-    // .module-content__title {
-    //   width: 50%;
-    //   height: var(--bg-height);
-    //   background: url('../../../../../assets/images/home-container/configurable/model_bottom_title_bg.png') no-repeat;
-    //   background-size: 100% 100%;
-    //   position: relative;
-    //   text-align: left;
-    //   padding-left: 5%;
-    // }
+  // .module-content__title {
+  //   width: 50%;
+  //   height: var(--bg-height);
+  //   background: url('../../../../../assets/images/home-container/configurable/model_bottom_title_bg.png') no-repeat;
+  //   background-size: 100% 100%;
+  //   position: relative;
+  //   text-align: left;
+  //   padding-left: 5%;
+  // }
 
-    // 固定在父容器右上角的按钮图标
-    // .action-btn {
-    //   width: 18px;
-    //   height: 18px;
-    //   background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
-    //   position: absolute;
-    //   left: 0;
-    //   top: 0;
-    // }
-    // .show-btn {
-    //   transform: rotate(-90deg);
-    // }
+  // 固定在父容器右上角的按钮图标
+  // .action-btn {
+  //   width: 18px;
+  //   height: 18px;
+  //   background: url('../../../../../assets/images/home-container/configurable/expand.svg') no-repeat center;
+  //   position: absolute;
+  //   left: 0;
+  //   top: 0;
+  // }
+  // .show-btn {
+  //   transform: rotate(-90deg);
+  // }
 
-    .module-slot {
-      height: calc(100% - 33px);
-      width: calc(100% - 15px);
-      backdrop-filter: blur(5px);
-      background-color: #6ad6ff1c;
-      margin-left: 5px;
-    }
+  .module-slot {
+    height: calc(100% - 33px);
+    width: calc(100% - 15px);
+    backdrop-filter: blur(5px);
+    background-color: #6ad6ff1c;
+    margin-left: 5px;
   }
 
   // Transition动画相关

+ 49 - 62
src/views/vent/home/configurable/components/original/moduleLeft.vue

@@ -1,23 +1,13 @@
 <template>
-  <Transition class="module-left">
-    <!-- 正常展示模块时 -->
-    <div v-if="visible" class="module-content">
-      <div class="module-content__title__expand">
-        <span class="action-btn close-btn" @click="closeModel"></span>
-        <span @click="clickHandler">{{ title }}</span>
-      </div>
-      <div class="module-slot">
-        <slot></slot>
-      </div>
+  <div v-if="visible" class="module-content">
+    <div v-if="title" class="module-content__title__expand">
+      <span class="action-btn close-btn" @click="closeModel"></span>
+      <span @click="clickHandler">{{ title }}</span>
     </div>
-    <!-- 隐藏模块时 -->
-    <!-- <div v-else class="w-100%">
-      <div class="module-content__title">
-        <span class="action-btn show-btn" @click="showModel"></span>
-        {{ title }}
-      </div>
-    </div> -->
-  </Transition>
+    <div class="module-slot">
+      <slot></slot>
+    </div>
+  </div>
 </template>
 <script lang="ts" setup>
   defineProps<{ title: string; visible: boolean }>();
@@ -31,58 +21,55 @@
   }
 </script>
 <style lang="less" scoped>
-  .module-left {
+  .module-content {
     --bg-height: 33px;
     color: #fff;
     box-sizing: border-box;
     position: absolute;
+    width: 100%;
+    height: 100%;
+  }
 
-    .module-content {
-      width: 100%;
-      height: 100%;
-    }
-
-    .module-content__title__expand {
-      width: 100%;
-      height: var(--bg-height);
-      background: url('@/assets/images/home-container/configurable/model_original_title_bg.png') no-repeat;
-      background-size: 100% 100%;
-      position: relative;
-      text-align: center;
-      line-height: var(--bg-height);
-    }
+  .module-content__title__expand {
+    width: 100%;
+    height: var(--bg-height);
+    background: url('@/assets/images/home-container/configurable/model_original_title_bg.png') no-repeat;
+    background-size: 100% 100%;
+    position: relative;
+    text-align: center;
+    line-height: var(--bg-height);
+  }
 
-    // .module-content__title {
-    //   width: 50%;
-    //   height: var(--bg-height);
-    //   background: url('@/assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
-    //   background-size: 100% 100%;
-    //   position: relative;
-    //   text-align: right;
-    //   padding: 4px 10% 0 0;
-    // }
+  // .module-content__title {
+  //   width: 50%;
+  //   height: var(--bg-height);
+  //   background: url('@/assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
+  //   background-size: 100% 100%;
+  //   position: relative;
+  //   text-align: right;
+  //   padding: 4px 10% 0 0;
+  // }
 
-    // 固定在父容器右上角的按钮图标
-    // .action-btn {
-    //   width: 18px;
-    //   height: 18px;
-    //   background: url('@/assets/images/home-container/configurable/expand.svg') no-repeat center;
-    //   position: absolute;
-    //   right: 0;
-    //   top: 0;
-    // }
-    // .close-btn {
-    //   transform: rotate(-90deg);
-    // }
+  // 固定在父容器右上角的按钮图标
+  // .action-btn {
+  //   width: 18px;
+  //   height: 18px;
+  //   background: url('@/assets/images/home-container/configurable/expand.svg') no-repeat center;
+  //   position: absolute;
+  //   right: 0;
+  //   top: 0;
+  // }
+  // .close-btn {
+  //   transform: rotate(-90deg);
+  // }
 
-    .module-slot {
-      height: calc(100% - 33px);
-      width: calc(100% - 20px);
-      backdrop-filter: blur(5px);
-      // #182d47
-      background-color: #6ad6ff1c;
-      margin-left: 10px;
-    }
+  .module-slot {
+    height: calc(100% - 33px);
+    width: calc(100% - 20px);
+    backdrop-filter: blur(5px);
+    // #182d47
+    background-color: #6ad6ff1c;
+    margin-left: 10px;
   }
 
   // Transition动画相关

+ 1 - 1
src/views/vent/home/configurable/components/FIreControl.vue → src/views/vent/home/configurable/components/preset/FIreControl.vue

@@ -19,7 +19,7 @@
   //   import MiniBoard from './MiniBoard.vue';
   //   import TimelineList from './TimelineList.vue';
   //   import CustomList from './CustomList.vue';
-  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
+  import { getFormattedText } from '../../../../deviceManager/configurationTable/adapters';
   //   import CustomChart from './CustomChart.vue';
   //   import { get } from 'lodash-es';
   //   import CommonTable from '../../billboard/components/CommonTable.vue';

+ 2 - 2
src/views/vent/home/configurable/components/FIreWarn.vue → src/views/vent/home/configurable/components/preset/FIreWarn.vue

@@ -20,8 +20,8 @@
   //   import { SwapOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons-vue';
   //   import MiniBoard from './MiniBoard.vue';
   //   import TimelineList from './TimelineList.vue';
-  import CustomList from './CustomList.vue';
-  import { getFormattedText } from '../../../deviceManager/configurationTable/adapters';
+  import CustomList from '../detail/CustomList.vue';
+  import { getFormattedText } from '../../../../deviceManager/configurationTable/adapters';
   //   import CustomChart from './CustomChart.vue';
   //   import { get } from 'lodash-es';
   //   import CommonTable from '../../billboard/components/CommonTable.vue';

+ 232 - 60
src/views/vent/home/configurable/configurable.data.ts

@@ -428,12 +428,12 @@ export const testConfigA: Config[] = [
   // },
   {
     deviceType: 'warn',
-    moduleName: '采空区火情综合预警',
+    moduleName: '工作面监测',
     pageType: '',
     moduleData: {
       header: {
-        show: false,
-        showSelector: false,
+        show: true,
+        showSelector: true,
         showSlot: true,
         selector: {
           value: '${strinstallpos}',
@@ -447,103 +447,275 @@ export const testConfigA: Config[] = [
         type: 'video',
         link: '',
       },
-      layout: ['list', 'list'],
+      // layout: ['table'],
       // layout: ['list'],
-      board: [],
-      chart: [],
-      gallery: [],
-      table: [],
-      list: [
+      layout: ['board'],
+      // layout: ['complex_list'],
+      board: [
         {
-          type: 'B',
-          readFrom: '',
+          type: 'E',
+          layout: 'label-top',
+          readFrom: 'readFromMe[0]',
           items: [
             {
-              label: '堵塞状态',
-              value: '${fsectarea}',
-              color: 'yellow',
-              info: '',
+              label: 'A',
+              value: '${a}',
             },
             {
-              label: '甲烷浓度',
-              value: '${stationname}',
-              color: 'yellow',
-              info: '',
+              label: 'B',
+              value: '${b}',
+            },
+            {
+              label: 'C',
+              value: '${c}',
             },
           ],
         },
+      ],
+      chart: [],
+      gallery: [],
+      table: [
         {
-          type: 'B',
-          readFrom: '',
-          items: [
+          type: 'C',
+          readFrom: 'readFromMe',
+          columns: [
             {
-              label: '堵塞状态',
-              value: '${fsectarea}',
-              color: 'yellow',
-              info: '',
+              name: 'A',
+              prop: 'a',
             },
             {
-              label: '甲烷浓度',
-              value: '${stationname}',
-              color: 'yellow',
-              info: '',
+              name: 'B',
+              prop: 'b',
+            },
+            {
+              name: 'C',
+              prop: 'c',
+            },
+            {
+              name: 'D',
+              prop: 'd',
             },
           ],
         },
       ],
-      complex_list: [
+      list: [
         {
-          type: 'A',
-          readFrom: '',
+          type: 'F',
+          readFrom: 'readFromMe[0]',
           items: [
             {
-              label: '火情状态',
-              value: '${fsectarea}',
-              color: 'yellow',
-              info: '',
-            },
-            {
-              label: '回采位置',
-              value: '${stationname}',
+              label: 'A',
+              value: '${a}',
               color: 'white',
-              info: '',
+              info: 'AInfo',
             },
             {
-              label: '硐室火情',
-              value: '${stationtype}',
-              color: 'blue',
-              info: '',
+              label: 'B',
+              value: '${b}',
+              color: 'white',
+              info: 'AInfo',
             },
             {
-              label: '联动设备状态',
-              value: '${typeName}',
-              color: 'blue',
-              info: '',
+              label: 'C',
+              value: '${c}',
+              color: 'white',
+              info: 'AInfo',
             },
           ],
-          galleryItems: [
+        },
+      ],
+      complex_list: [
+        {
+          type: 'B',
+          readFrom: 'readFromMe[0]',
+          items: [
             {
-              value: '低风险',
-              label: '',
-              color: 'white',
-            },
-            {
-              value: '${CO}',
-              label: '',
-              color: 'white',
+              title: 'TITLEA',
+              contents: [
+                {
+                  label: 'A',
+                  value: '${a}',
+                  color: 'white',
+                  info: 'AInfo',
+                },
+                {
+                  label: 'B',
+                  value: '${b}',
+                  color: 'white',
+                  info: 'AInfo',
+                },
+                {
+                  label: 'C',
+                  value: '${c}',
+                  color: 'white',
+                  info: 'AInfo',
+                },
+                {
+                  label: 'D',
+                  value: '${d}',
+                  color: 'white',
+                  info: 'DInfo',
+                },
+              ],
             },
           ],
         },
       ],
       preset: [],
       to: 'https://baidu.com',
+      mock: {
+        readFromMe: [
+          {
+            a: 1,
+            b: 2,
+            c: 3,
+            d: 4,
+          },
+          {
+            a: 1,
+            b: 2,
+            c: 3,
+            d: 4,
+          },
+          {
+            a: 1,
+            b: 2,
+            c: 3,
+            d: 4,
+          },
+        ],
+      },
     },
     showStyle: {
       size: 'width:450px;height:280px;',
-      version: '新版',
+      version: '保德',
+      // version: '原版',
+      // version: '新版',
+      // version: '普通版',
       position: 'top:640px;left:0;',
     },
   },
+  // {
+  //   deviceType: 'warn',
+  //   moduleName: '采空区火情综合预警',
+  //   pageType: '',
+  //   moduleData: {
+  //     header: {
+  //       show: false,
+  //       showSelector: false,
+  //       showSlot: true,
+  //       selector: {
+  //         value: '${strinstallpos}',
+  //       },
+  //       slot: {
+  //         value: '网络异常:${netstatus.val} 台',
+  //       },
+  //     },
+  //     background: {
+  //       show: false,
+  //       type: 'video',
+  //       link: '',
+  //     },
+  //     layout: ['list', 'list'],
+  //     // layout: ['list'],
+  //     board: [],
+  //     chart: [],
+  //     gallery: [],
+  //     table: [],
+  //     list: [
+  //       {
+  //         type: 'B',
+  //         readFrom: '',
+  //         items: [
+  //           {
+  //             label: '堵塞状态',
+  //             value: '${fsectarea}',
+  //             color: 'yellow',
+  //             info: '',
+  //           },
+  //           {
+  //             label: '甲烷浓度',
+  //             value: '${stationname}',
+  //             color: 'yellow',
+  //             info: '',
+  //           },
+  //         ],
+  //       },
+  //       {
+  //         type: 'B',
+  //         readFrom: '',
+  //         items: [
+  //           {
+  //             label: '堵塞状态',
+  //             value: '${fsectarea}',
+  //             color: 'yellow',
+  //             info: '',
+  //           },
+  //           {
+  //             label: '甲烷浓度',
+  //             value: '${stationname}',
+  //             color: 'yellow',
+  //             info: '',
+  //           },
+  //         ],
+  //       },
+  //     ],
+  //     complex_list: [
+  //       {
+  //         type: 'A',
+  //         readFrom: '',
+  //         items: [
+  //           {
+  //             label: '火情状态',
+  //             value: '${fsectarea}',
+  //             color: 'yellow',
+  //             info: '',
+  //           },
+  //           {
+  //             label: '回采位置',
+  //             value: '${stationname}',
+  //             color: 'white',
+  //             info: '',
+  //           },
+  //           {
+  //             label: '硐室火情',
+  //             value: '${stationtype}',
+  //             color: 'blue',
+  //             info: '',
+  //           },
+  //           {
+  //             label: '联动设备状态',
+  //             value: '${typeName}',
+  //             color: 'blue',
+  //             info: '',
+  //           },
+  //         ],
+  //         galleryItems: [
+  //           {
+  //             value: '低风险',
+  //             label: '',
+  //             color: 'white',
+  //           },
+  //           {
+  //             value: '${CO}',
+  //             label: '',
+  //             color: 'white',
+  //           },
+  //         ],
+  //       },
+  //     ],
+  //     preset: [],
+  //     to: 'https://baidu.com',
+  //   },
+  //   showStyle: {
+  //     size: 'width:450px;height:280px;',
+  //     version: '保德',
+  //     // version: '原版',
+  //     // version: '新版',
+  //     // version: '普通版',
+  //     position: 'top:640px;left:0;',
+  //   },
+  // },
   {
     deviceType: 'midinfo',
     moduleName: 'midinfo-中间',

+ 189 - 0
src/views/vent/home/configurable/dustBD.vue

@@ -0,0 +1,189 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="top-bg">
+      <div class="main-title">{{ mainTitle }}</div>
+    </div>
+    <!-- <a-dropdown class="module-dropdown" :class="{ 'module-dropdown-original': isOriginal }" :trigger="['click']" placement="bottomRight">
+      <a class="ant-dropdown-link" @click.prevent>
+        全矿井通风检测
+        <CaretDownOutlined />
+      </a>
+      <template #overlay>
+        <MonitorCenter />
+      </template>
+    </a-dropdown> -->
+    <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
+    <template v-if="isOriginal">
+      <ModuleOriginal
+        v-for="cfg in configs"
+        :key="cfg.deviceType"
+        :show-style="cfg.showStyle"
+        :module-name="cfg.moduleName"
+        :visible="true"
+        @click="redirectTo(cfg)"
+      >
+        <Content v-bind="cfg" />
+      </ModuleOriginal>
+    </template>
+    <template v-else-if="isCommon">
+      <ModuleCommon
+        v-for="cfg in configs"
+        :key="cfg.deviceType"
+        :show-style="cfg.showStyle"
+        :module-name="cfg.moduleName"
+        :visible="true"
+        @click="redirectTo(cfg)"
+      >
+        <Content v-bind="cfg" />
+      </ModuleCommon>
+    </template>
+    <template v-else>
+      <!-- 下面是正常展示的各新版模块 -->
+      <ModuleEnhanced
+        v-for="cfg in enhancedConfigs"
+        :key="cfg.deviceType"
+        :visible="cfg.visible"
+        :show-style="cfg.showStyle"
+        :module-name="cfg.moduleName"
+        @close="cfg.visible = false"
+        @click="redirectTo(cfg)"
+      >
+        <Content v-bind="cfg" />
+      </ModuleEnhanced>
+      <!-- 下面是用于呼出已隐藏的模块的按钮 -->
+      <div class="pos-absolute top-70px left-460px">
+        <div v-for="(item, i) in hiddenList" :key="`vvhchg${i}`">
+          <AButton class="module-trigger-button" @click="item.visible = true">{{ item.moduleName }}</AButton>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { computed, onMounted, ref } from 'vue';
+  // import { CaretDownOutlined } from '@ant-design/icons-vue';
+  // import MonitorCenter from './components/MonitorCenter.vue';
+  import { useInitConfigs } from './hooks/useInit';
+  import { Config } from '../../deviceManager/configurationTable/types';
+  import ModuleEnhanced from './components/ModuleEnhanced.vue';
+  import ModuleOriginal from './components/ModuleOriginal.vue';
+  import ModuleCommon from './components/ModuleCommon.vue';
+  import Content from './components/content.vue';
+  import { testConfigA } from './configurable.data';
+  import { useRoute } from 'vue-router';
+  import { openWindow } from '/@/utils';
+
+  interface EnhancedConfig extends Config {
+    visible: boolean;
+  }
+
+  const mainTitle = ref('智能通风管控系统');
+
+  // const moduleCodes = ['fanlocal', 'fanmain' /** 'vc', 'ar', 'va', 'ws', 'dw' */];
+
+  const enhancedConfigs = ref<EnhancedConfig[]>([]);
+
+  const hiddenList = computed(() => {
+    return enhancedConfigs.value.filter((e) => e.visible === false);
+  });
+  const { configs, isOriginal, isCommon, fetchConfigs } = useInitConfigs();
+
+  function redirectTo(config: Config) {
+    const { to } = config.moduleData;
+    if (!to) return;
+    openWindow(to);
+  }
+
+  onMounted(() => {
+    const query = useRoute().query;
+    if (query.fire) {
+      mainTitle.value = '智能火灾管控系统';
+    }
+    if (query.gas) {
+      mainTitle.value = '智能瓦斯管控系统';
+    }
+    // configs.value = testConfigB;
+    fetchConfigs().then(() => {
+      configs.value.push(...testConfigA);
+      enhancedConfigs.value = configs.value.map((c) => {
+        return {
+          visible: true,
+          ...c,
+        };
+      });
+    });
+  });
+</script>
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  .company-home {
+    width: 100%;
+    height: 100%;
+    color: @white;
+    position: relative;
+
+    .top-bg {
+      width: 100%;
+      height: 56px;
+      background: url('@/assets/images/home-container/configurable/main_title_bg.png') no-repeat center;
+      position: absolute;
+      z-index: 1;
+      .main-title {
+        height: 56px;
+        font-family: 'douyuFont';
+        font-size: 20px;
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    // .module-left {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   left: 0;
+    // }
+    // .module-right {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   right: 0;
+    // }
+    // .module-bottom {
+    //   position: absolute;
+    //   width: 1000px;
+    //   height: 280px;
+    // }
+    .module-dropdown {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-dropdown-original {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-trigger-button {
+      color: #fff;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border: none;
+      border-bottom: 2px solid #3df6ff;
+    }
+  }
+</style>

+ 260 - 0
src/views/vent/home/configurable/fireBD.vue

@@ -0,0 +1,260 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="top-bg">
+      <div class="main-title">{{ mainTitle }}</div>
+    </div>
+    <!-- <a-dropdown class="module-dropdown" :class="{ 'module-dropdown-original': isOriginal }" :trigger="['click']" placement="bottomRight">
+      <a class="ant-dropdown-link" @click.prevent>
+        全矿井通风检测
+        <CaretDownOutlined />
+      </a>
+      <template #overlay>
+        <MonitorCenter />
+      </template>
+    </a-dropdown> -->
+    <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
+
+    <!-- <div class="left-t">
+      <div class="tcontent-area">
+        <div class="tcontent-l">
+          <div>全矿井</div>
+          <div>监测区域</div>
+        </div>
+        <div class="tcontent-c">
+          <div style="margin-bottom: 15px; color: #009bff; font-size: 24px; font-weight: bolder; letter-spacing: 10px"> 低风险</div>
+          <div style="color: #fff; font-size: 12px">自燃倾向性等级 : 容易自燃</div>
+        </div>
+        <div class="tcontent-r">火灾风险</div>
+      </div>
+    </div>
+    <div class="right-t">
+      <DanelBd :moduleName="''" :contentStyle="{ contentH: '121px' }" :bgSize="'small'">
+        <systemJc />
+      </DanelBd>
+    </div> -->
+    <template v-if="isOriginal">
+      <ModuleOriginal
+        v-for="cfg in configs"
+        :key="cfg.deviceType"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        :visible="true"
+      />
+    </template>
+    <template v-else-if="isCommon">
+      <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"
+        :visible="true"
+      />
+    </template>
+    <template v-else>
+      <!-- 下面是正常展示的各新版模块 -->
+      <ModuleEnhanced
+        v-for="cfg in enhancedConfigs"
+        :key="cfg.deviceType"
+        :visible="cfg.visible"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        @close="cfg.visible = false"
+      />
+      <!-- 下面是用于呼出已隐藏的模块的按钮 -->
+      <div class="pos-absolute top-70px left-460px">
+        <div v-for="(item, i) in hiddenList" :key="`vvhchg${i}`">
+          <AButton class="module-trigger-button" @click="item.visible = true">{{ item.moduleName }}</AButton>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { computed, onMounted, ref } from 'vue';
+  // import { CaretDownOutlined } from '@ant-design/icons-vue';
+  // import MonitorCenter from './components/MonitorCenter.vue';
+  import { useInitConfigs } from './hooks/useInit';
+  import { Config } from '../../deviceManager/configurationTable/types';
+  import ModuleEnhanced from './components/ModuleEnhanced.vue';
+  import ModuleOriginal from './components/ModuleOriginal.vue';
+  import ModuleCommon from './components/ModuleCommon.vue';
+  import { testConfigA } from './configurable.data';
+  import { useRoute } from 'vue-router';
+
+  interface EnhancedConfig extends Config {
+    visible: boolean;
+  }
+
+  const mainTitle = ref('智能通风管控系统');
+
+  // const moduleCodes = ['fanlocal', 'fanmain' /** 'vc', 'ar', 'va', 'ws', 'dw' */];
+
+  const enhancedConfigs = ref<EnhancedConfig[]>([]);
+
+  const hiddenList = computed(() => {
+    return enhancedConfigs.value.filter((e) => e.visible === false);
+  });
+  const { configs, isOriginal, isCommon, fetchConfigs } = useInitConfigs();
+
+  onMounted(() => {
+    const query = useRoute().query;
+    if (query.fire) {
+      mainTitle.value = '智能火灾管控系统';
+    }
+    if (query.gas) {
+      mainTitle.value = '智能瓦斯管控系统';
+    }
+    // configs.value = testConfigB;
+    fetchConfigs().then(() => {
+      configs.value = testConfigA;
+      // configs.value.push(...testConfigA);
+      enhancedConfigs.value = configs.value.map((c) => {
+        return {
+          visible: true,
+          ...c,
+        };
+      });
+    });
+  });
+</script>
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  .company-home {
+    width: 100%;
+    height: 100%;
+    color: @white;
+    position: relative;
+
+    .top-bg {
+      width: 100%;
+      height: 56px;
+      background: url('@/assets/images/home-container/configurable/main_title_bg.png') no-repeat center;
+      position: absolute;
+      z-index: 1;
+      .main-title {
+        height: 56px;
+        font-family: 'douyuFont';
+        font-size: 20px;
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    // .module-left {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   left: 0;
+    // }
+    // .module-right {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   right: 0;
+    // }
+    // .module-bottom {
+    //   position: absolute;
+    //   width: 1000px;
+    //   height: 280px;
+    // }
+    .module-dropdown {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-dropdown-original {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-trigger-button {
+      color: #fff;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border: none;
+      border-bottom: 2px solid #3df6ff;
+    }
+  }
+
+  .left-t {
+    position: absolute;
+    height: 115px;
+    margin-bottom: 25px;
+    width: 450px;
+    background: url('../../../../assets/images/fire/firehome/qkjaq.png') no-repeat center;
+    background-size: 100% 100%;
+
+    .tcontent-area {
+      display: flex;
+      position: absolute;
+      top: 50%;
+      left: 0;
+      box-sizing: border-box;
+      align-items: center;
+      justify-content: space-around;
+      width: 100%;
+      height: 70px;
+      padding: 0 15px;
+      transform: translate(0, -40%);
+
+      .tcontent-l {
+        display: flex;
+        flex: 1;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+        color: #9da5aa;
+        font-size: 14px;
+        font-weight: bold;
+        letter-spacing: 2px;
+      }
+
+      .tcontent-c {
+        display: flex;
+        flex: 3;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+      }
+
+      .tcontent-r {
+        display: flex;
+        flex: 1;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+        color: #9da5aa;
+        font-size: 14px;
+        font-weight: bold;
+        letter-spacing: 2px;
+      }
+    }
+  }
+  .right-t {
+    position: absolute;
+    width: 450px;
+  }
+</style>

+ 7 - 1
src/views/vent/home/configurable/hooks/useInit.ts

@@ -34,6 +34,11 @@ export function useInitConfigs() {
       return c.showStyle.version === '普通版';
     });
   });
+  const isBD = computed(() => {
+    return configs.value.some((c) => {
+      return c.showStyle.version === '保德';
+    });
+  });
 
   function fetchConfigs() {
     return cfgList({}).then(({ records }) => {
@@ -46,6 +51,7 @@ export function useInitConfigs() {
     configs,
     isOriginal,
     isCommon,
+    isBD,
   };
 }
 
@@ -69,7 +75,7 @@ export function useInitDevices(devicekind: string, config: Config['moduleData'][
     return res ? res.label : '';
   });
   const selectedDeviceSlot = computed(() => {
-    return getFormattedText(selectedDevice.value, config.slot.prop, config.slot.formatter);
+    return getFormattedText(selectedDevice.value, config.slot.value);
   });
 
   // 获取设备数据,赋值并以选项格式返回给 Header 消费

+ 180 - 0
src/views/vent/home/configurable/index copy.vue

@@ -0,0 +1,180 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="top-bg">
+      <div class="main-title">{{ mainTitle }}</div>
+    </div>
+    <!-- <a-dropdown class="module-dropdown" :class="{ 'module-dropdown-original': isOriginal }" :trigger="['click']" placement="bottomRight">
+      <a class="ant-dropdown-link" @click.prevent>
+        全矿井通风检测
+        <CaretDownOutlined />
+      </a>
+      <template #overlay>
+        <MonitorCenter />
+      </template>
+    </a-dropdown> -->
+    <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
+
+    <template v-if="isOriginal">
+      <ModuleOriginal
+        v-for="cfg in configs"
+        :key="cfg.deviceType"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        :visible="true"
+      />
+    </template>
+    <template v-else-if="isCommon">
+      <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"
+        :visible="true"
+      />
+    </template>
+    <template v-else>
+      <!-- 下面是正常展示的各新版模块 -->
+      <ModuleEnhanced
+        v-for="cfg in enhancedConfigs"
+        :key="cfg.deviceType"
+        :visible="cfg.visible"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        @close="cfg.visible = false"
+      />
+      <!-- 下面是用于呼出已隐藏的模块的按钮 -->
+      <div class="pos-absolute top-70px left-460px">
+        <div v-for="(item, i) in hiddenList" :key="`vvhchg${i}`">
+          <AButton class="module-trigger-button" @click="item.visible = true">{{ item.moduleName }}</AButton>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { computed, onMounted, ref } from 'vue';
+  // import { CaretDownOutlined } from '@ant-design/icons-vue';
+  // import MonitorCenter from './components/MonitorCenter.vue';
+  import { useInitConfigs } from './hooks/useInit';
+  import { Config } from '../../deviceManager/configurationTable/types';
+  import ModuleEnhanced from './components/ModuleEnhanced.vue';
+  import ModuleOriginal from './components/ModuleOriginal.vue';
+  import ModuleCommon from './components/ModuleCommon.vue';
+  import { testConfigA } from './configurable.data';
+  import { useRoute } from 'vue-router';
+
+  interface EnhancedConfig extends Config {
+    visible: boolean;
+  }
+
+  const mainTitle = ref('智能通风管控系统');
+
+  // const moduleCodes = ['fanlocal', 'fanmain' /** 'vc', 'ar', 'va', 'ws', 'dw' */];
+
+  const enhancedConfigs = ref<EnhancedConfig[]>([]);
+
+  const hiddenList = computed(() => {
+    return enhancedConfigs.value.filter((e) => e.visible === false);
+  });
+  const { configs, isOriginal, isCommon, fetchConfigs } = useInitConfigs();
+
+  onMounted(() => {
+    const query = useRoute().query;
+    if (query.fire) {
+      mainTitle.value = '智能火灾管控系统';
+    }
+    if (query.gas) {
+      mainTitle.value = '智能瓦斯管控系统';
+    }
+    // configs.value = testConfigB;
+    fetchConfigs().then(() => {
+      configs.value = testConfigA;
+      // configs.value.push(...testConfigA);
+      enhancedConfigs.value = configs.value.map((c) => {
+        return {
+          visible: true,
+          ...c,
+        };
+      });
+    });
+  });
+</script>
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  .company-home {
+    width: 100%;
+    height: 100%;
+    color: @white;
+    position: relative;
+
+    .top-bg {
+      width: 100%;
+      height: 56px;
+      background: url('@/assets/images/home-container/configurable/main_title_bg.png') no-repeat center;
+      position: absolute;
+      z-index: 1;
+      .main-title {
+        height: 56px;
+        font-family: 'douyuFont';
+        font-size: 20px;
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    // .module-left {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   left: 0;
+    // }
+    // .module-right {
+    //   position: absolute;
+    //   width: 450px;
+    //   height: 280px;
+    //   right: 0;
+    // }
+    // .module-bottom {
+    //   position: absolute;
+    //   width: 1000px;
+    //   height: 280px;
+    // }
+    .module-dropdown {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-dropdown-original {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+    .module-trigger-button {
+      color: #fff;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border: none;
+      border-bottom: 2px solid #3df6ff;
+    }
+  }
+</style>

+ 106 - 22
src/views/vent/home/configurable/index.vue

@@ -14,29 +14,57 @@
       </template>
     </a-dropdown> -->
     <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
+
+    <!-- <div class="left-t">
+      <div class="tcontent-area">
+        <div class="tcontent-l">
+          <div>全矿井</div>
+          <div>监测区域</div>
+        </div>
+        <div class="tcontent-c">
+          <div style="margin-bottom: 15px; color: #009bff; font-size: 24px; font-weight: bolder; letter-spacing: 10px"> 低风险</div>
+          <div style="color: #fff; font-size: 12px">自燃倾向性等级 : 容易自燃</div>
+        </div>
+        <div class="tcontent-r">火灾风险</div>
+      </div>
+    </div>
+    <div class="right-t">
+      <DanelBd :moduleName="''" :contentStyle="{ contentH: '121px' }" :bgSize="'small'">
+        <systemJc />
+      </DanelBd>
+    </div> -->
     <template v-if="isOriginal">
       <ModuleOriginal
         v-for="cfg in configs"
         :key="cfg.deviceType"
         :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
         :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
         :visible="true"
-        @click="redirectTo(cfg)"
-      >
-        <Content v-bind="cfg" />
-      </ModuleOriginal>
+      />
     </template>
     <template v-else-if="isCommon">
       <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"
         :visible="true"
-        @click="redirectTo(cfg)"
-      >
-        <Content v-bind="cfg" />
-      </ModuleCommon>
+      />
+    </template>
+    <template v-else-if="isBD">
+      <ModuleBD
+        v-for="cfg in configs"
+        :key="cfg.deviceType"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        :visible="true"
+      />
     </template>
     <template v-else>
       <!-- 下面是正常展示的各新版模块 -->
@@ -45,12 +73,11 @@
         :key="cfg.deviceType"
         :visible="cfg.visible"
         :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
         :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
         @close="cfg.visible = false"
-        @click="redirectTo(cfg)"
-      >
-        <Content v-bind="cfg" />
-      </ModuleEnhanced>
+      />
       <!-- 下面是用于呼出已隐藏的模块的按钮 -->
       <div class="pos-absolute top-70px left-460px">
         <div v-for="(item, i) in hiddenList" :key="`vvhchg${i}`">
@@ -69,10 +96,9 @@
   import ModuleEnhanced from './components/ModuleEnhanced.vue';
   import ModuleOriginal from './components/ModuleOriginal.vue';
   import ModuleCommon from './components/ModuleCommon.vue';
-  import Content from './components/content.vue';
+  import ModuleBD from './components/ModuleBD.vue';
   import { testConfigA } from './configurable.data';
   import { useRoute } from 'vue-router';
-  import { openWindow } from '/@/utils';
 
   interface EnhancedConfig extends Config {
     visible: boolean;
@@ -87,13 +113,7 @@
   const hiddenList = computed(() => {
     return enhancedConfigs.value.filter((e) => e.visible === false);
   });
-  const { configs, isOriginal, isCommon, fetchConfigs } = useInitConfigs();
-
-  function redirectTo(config: Config) {
-    const { to } = config.moduleData;
-    if (!to) return;
-    openWindow(to);
-  }
+  const { configs, isOriginal, isCommon, isBD, fetchConfigs } = useInitConfigs();
 
   onMounted(() => {
     const query = useRoute().query;
@@ -105,7 +125,8 @@
     }
     // configs.value = testConfigB;
     fetchConfigs().then(() => {
-      configs.value.push(...testConfigA);
+      configs.value = testConfigA;
+      // configs.value.push(...testConfigA);
       enhancedConfigs.value = configs.value.map((c) => {
         return {
           visible: true,
@@ -126,6 +147,7 @@
     height: 100%;
     color: @white;
     position: relative;
+    background: url('@/assets/images/home-container/configurable/firehome/bg.png') no-repeat center;
 
     .top-bg {
       width: 100%;
@@ -186,4 +208,66 @@
       border-bottom: 2px solid #3df6ff;
     }
   }
+
+  .left-t {
+    position: absolute;
+    height: 115px;
+    margin-bottom: 25px;
+    width: 450px;
+    background: url('../../../../assets/images/fire/firehome/qkjaq.png') no-repeat center;
+    background-size: 100% 100%;
+
+    .tcontent-area {
+      display: flex;
+      position: absolute;
+      top: 50%;
+      left: 0;
+      box-sizing: border-box;
+      align-items: center;
+      justify-content: space-around;
+      width: 100%;
+      height: 70px;
+      padding: 0 15px;
+      transform: translate(0, -40%);
+
+      .tcontent-l {
+        display: flex;
+        flex: 1;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+        color: #9da5aa;
+        font-size: 14px;
+        font-weight: bold;
+        letter-spacing: 2px;
+      }
+
+      .tcontent-c {
+        display: flex;
+        flex: 3;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+      }
+
+      .tcontent-r {
+        display: flex;
+        flex: 1;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        height: 100%;
+        color: #9da5aa;
+        font-size: 14px;
+        font-weight: bold;
+        letter-spacing: 2px;
+      }
+    }
+  }
+  .right-t {
+    position: absolute;
+    width: 450px;
+  }
 </style>