Ver código fonte

Merge branch 'master' of http://182.92.126.35:3000/hrx/mky-vent-base

lxh 7 meses atrás
pai
commit
4f74cc1785
100 arquivos alterados com 1432 adições e 773 exclusões
  1. BIN
      src/assets/images/home-container/configurable/board_bg_1.png
  2. BIN
      src/assets/images/home-container/configurable/dusthome/1.png
  3. BIN
      src/assets/images/home-container/configurable/dusthome/2.png
  4. BIN
      src/assets/images/home-container/configurable/dusthome/btn1.png
  5. BIN
      src/assets/images/home-container/configurable/dusthome/content-item.png
  6. BIN
      src/assets/images/home-container/configurable/dusthome/dwsl.png
  7. BIN
      src/assets/images/home-container/configurable/dusthome/dyfl.png
  8. BIN
      src/assets/images/home-container/configurable/dusthome/dz.png
  9. BIN
      src/assets/images/home-container/configurable/dusthome/dz1.png
  10. BIN
      src/assets/images/home-container/configurable/dusthome/dz2.png
  11. BIN
      src/assets/images/home-container/configurable/dusthome/gl-1.png
  12. BIN
      src/assets/images/home-container/configurable/dusthome/gl-2.png
  13. BIN
      src/assets/images/home-container/configurable/dusthome/gl-3.png
  14. BIN
      src/assets/images/home-container/configurable/dusthome/gl-4.png
  15. BIN
      src/assets/images/home-container/configurable/dusthome/gl-5.png
  16. BIN
      src/assets/images/home-container/configurable/dusthome/gl-6.png
  17. BIN
      src/assets/images/home-container/configurable/dusthome/hycd.png
  18. BIN
      src/assets/images/home-container/configurable/dusthome/img-5.png
  19. BIN
      src/assets/images/home-container/configurable/dusthome/img-7.png
  20. BIN
      src/assets/images/home-container/configurable/dusthome/img-8.png
  21. BIN
      src/assets/images/home-container/configurable/dusthome/img-9.png
  22. BIN
      src/assets/images/home-container/configurable/dusthome/jdjl.png
  23. BIN
      src/assets/images/home-container/configurable/dusthome/jtzb.png
  24. BIN
      src/assets/images/home-container/configurable/dusthome/lwsl.png
  25. BIN
      src/assets/images/home-container/configurable/dusthome/pwkqs.png
  26. BIN
      src/assets/images/home-container/configurable/dusthome/sbzs.png
  27. BIN
      src/assets/images/home-container/configurable/dusthome/图片-3.png
  28. BIN
      src/assets/images/home-container/configurable/dusthome/图片-4.png
  29. BIN
      src/assets/images/home-container/configurable/dusthome/图片-6.png
  30. BIN
      src/assets/images/home-container/configurable/dusthome/风险监测.png
  31. BIN
      src/assets/images/home-container/configurable/firehome/CH₄.png
  32. BIN
      src/assets/images/home-container/configurable/firehome/CO.png
  33. BIN
      src/assets/images/home-container/configurable/firehome/CO₂.png
  34. BIN
      src/assets/images/home-container/configurable/firehome/C₂H₂.png
  35. BIN
      src/assets/images/home-container/configurable/firehome/C₂H₄.png
  36. BIN
      src/assets/images/home-container/configurable/firehome/H₂.png
  37. BIN
      src/assets/images/home-container/configurable/firehome/NO₂.png
  38. BIN
      src/assets/images/home-container/configurable/firehome/N₂.png
  39. BIN
      src/assets/images/home-container/configurable/firehome/O₂.png
  40. BIN
      src/assets/images/home-container/configurable/firehome/bg.png
  41. BIN
      src/assets/images/home-container/configurable/firehome/co1.png
  42. BIN
      src/assets/images/home-container/configurable/firehome/common-border.png
  43. BIN
      src/assets/images/home-container/configurable/firehome/common-border1.png
  44. BIN
      src/assets/images/home-container/configurable/firehome/common-border2.png
  45. BIN
      src/assets/images/home-container/configurable/firehome/common-border3.png
  46. BIN
      src/assets/images/home-container/configurable/firehome/empty-qp.png
  47. BIN
      src/assets/images/home-container/configurable/firehome/fiber-jc.png
  48. BIN
      src/assets/images/home-container/configurable/firehome/fire-title.png
  49. BIN
      src/assets/images/home-container/configurable/firehome/ggxt.png
  50. BIN
      src/assets/images/home-container/configurable/firehome/img-1.png
  51. BIN
      src/assets/images/home-container/configurable/firehome/img-2.png
  52. BIN
      src/assets/images/home-container/configurable/firehome/img-3.png
  53. BIN
      src/assets/images/home-container/configurable/firehome/img-4.png
  54. BIN
      src/assets/images/home-container/configurable/firehome/img-5.png
  55. BIN
      src/assets/images/home-container/configurable/firehome/img-6.png
  56. BIN
      src/assets/images/home-container/configurable/firehome/img-7.png
  57. BIN
      src/assets/images/home-container/configurable/firehome/list-head.png
  58. BIN
      src/assets/images/home-container/configurable/firehome/list.png
  59. BIN
      src/assets/images/home-container/configurable/firehome/miehuo.png
  60. BIN
      src/assets/images/home-container/configurable/firehome/qkjaq.png
  61. BIN
      src/assets/images/home-container/configurable/firehome/safety1.png
  62. BIN
      src/assets/images/home-container/configurable/firehome/safety2.png
  63. BIN
      src/assets/images/home-container/configurable/firehome/smoke.png
  64. BIN
      src/assets/images/home-container/configurable/firehome/temp.png
  65. BIN
      src/assets/images/home-container/configurable/firehome/title-1.png
  66. BIN
      src/assets/images/home-container/configurable/firehome/title-2.png
  67. BIN
      src/assets/images/home-container/configurable/firehome/title-3.png
  68. BIN
      src/assets/images/home-container/configurable/firehome/title-4.png
  69. BIN
      src/assets/images/home-container/configurable/firehome/ty-e.png
  70. BIN
      src/assets/images/home-container/configurable/firehome/work-jc.png
  71. BIN
      src/assets/images/home-container/configurable/firehome/zjxt.png
  72. BIN
      src/assets/images/home-container/configurable/firehome/zu-14578.png
  73. BIN
      src/assets/images/home-container/configurable/firehome/zu-e.png
  74. 2 38
      src/views/vent/deviceManager/configurationTable/adapters.ts
  75. 7 0
      src/views/vent/deviceManager/configurationTable/index.vue
  76. 83 75
      src/views/vent/deviceManager/configurationTable/options.ts
  77. 165 106
      src/views/vent/deviceManager/configurationTable/types.ts
  78. 1 1
      src/views/vent/home/configurable/README.md
  79. 0 165
      src/views/vent/home/configurable/components/CustomGallery.vue
  80. 231 0
      src/views/vent/home/configurable/components/ModuleBD.vue
  81. 24 6
      src/views/vent/home/configurable/components/ModuleCommon.vue
  82. 33 11
      src/views/vent/home/configurable/components/ModuleEnhanced.vue
  83. 35 8
      src/views/vent/home/configurable/components/ModuleOriginal.vue
  84. 79 190
      src/views/vent/home/configurable/components/content.vue
  85. 189 0
      src/views/vent/home/configurable/components/detail/ComplexList.vue
  86. 4 4
      src/views/vent/home/configurable/components/detail/CustomChart.vue
  87. 358 0
      src/views/vent/home/configurable/components/detail/CustomGallery.vue
  88. 18 0
      src/views/vent/home/configurable/components/detail/CustomList.vue
  89. 25 0
      src/views/vent/home/configurable/components/detail/CustomTable.vue
  90. 0 0
      src/views/vent/home/configurable/components/detail/GalleryList.vue
  91. 36 0
      src/views/vent/home/configurable/components/detail/MiniBoard.vue
  92. 0 2
      src/views/vent/home/configurable/components/detail/TimelineList.vue
  93. 6 11
      src/views/vent/home/configurable/components/enhanced/moduleBottom.vue
  94. 6 11
      src/views/vent/home/configurable/components/enhanced/moduleLeft.vue
  95. 6 11
      src/views/vent/home/configurable/components/enhanced/moduleRight.vue
  96. 16 6
      src/views/vent/home/configurable/components/header.vue
  97. 52 62
      src/views/vent/home/configurable/components/original/moduleBottom.vue
  98. 53 63
      src/views/vent/home/configurable/components/original/moduleLeft.vue
  99. 1 1
      src/views/vent/home/configurable/components/preset/FIreControl.vue
  100. 2 2
      src/views/vent/home/configurable/components/preset/FIreWarn.vue

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


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


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


BIN
src/assets/images/home-container/configurable/dusthome/btn1.png


BIN
src/assets/images/home-container/configurable/dusthome/content-item.png


BIN
src/assets/images/home-container/configurable/dusthome/dwsl.png


BIN
src/assets/images/home-container/configurable/dusthome/dyfl.png


BIN
src/assets/images/home-container/configurable/dusthome/dz.png


BIN
src/assets/images/home-container/configurable/dusthome/dz1.png


BIN
src/assets/images/home-container/configurable/dusthome/dz2.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-1.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-2.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-3.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-4.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-5.png


BIN
src/assets/images/home-container/configurable/dusthome/gl-6.png


BIN
src/assets/images/home-container/configurable/dusthome/hycd.png


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


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


BIN
src/assets/images/home-container/configurable/dusthome/img-8.png


BIN
src/assets/images/home-container/configurable/dusthome/img-9.png


BIN
src/assets/images/home-container/configurable/dusthome/jdjl.png


BIN
src/assets/images/home-container/configurable/dusthome/jtzb.png


BIN
src/assets/images/home-container/configurable/dusthome/lwsl.png


BIN
src/assets/images/home-container/configurable/dusthome/pwkqs.png


BIN
src/assets/images/home-container/configurable/dusthome/sbzs.png


BIN
src/assets/images/home-container/configurable/dusthome/图片-3.png


BIN
src/assets/images/home-container/configurable/dusthome/图片-4.png


BIN
src/assets/images/home-container/configurable/dusthome/图片-6.png


BIN
src/assets/images/home-container/configurable/dusthome/风险监测.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/fire-title.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


+ 2 - 38
src/views/vent/deviceManager/configurationTable/adapters.ts

@@ -13,7 +13,7 @@ export function parseFormDataToParams(formData: Record<string, number | string |
   return params;
 }
 
-/** 将 api.list 返回的数据格式化,格式化之后可以支持对应的表单用,该方法会修改源数据 */
+/** 将 api.list 返回的数据格式化,格式化之后可以支持对应的表单使用,该方法会修改源数据 */
 export function parseModuleData(listData: { moduleData: ModuleData; showStyle: ShowStyle }) {
   _.forEach(listData.showStyle, (v, k) => {
     listData[`showStyle.${k}`] = _.get(
@@ -29,43 +29,6 @@ export function parseModuleData(listData: { moduleData: ModuleData; showStyle: S
   return listData;
 }
 
-// export function parseModuleDataToConfig(moduleData: ModuleData): {
-//   chart: { label: string; prop: string }[];
-//   list: { label: string; prop: string }[];
-// };
-// export function parseModuleDataToConfig(
-//   moduleData: ModuleData,
-//   data: any
-// ): {
-//   chart: { label: string; value: string }[];
-//   list: { label: string; value: string }[];
-// };
-
-/** 将 api.list 返回的 moduleData 格式化为配置对象,如果传入了 data,那么会返回带数据的配置,否则返回默认配置,这些配置通常可用于页面展示 */
-// export function parseModuleDataToConfig(moduleData: ModuleData): {
-//   chart: { label: string; prop: string }[];
-//   list: { label: string; prop: string }[];
-// } {
-//   // if (data) {
-//   //   return {
-//   //     chart: _.map(_.get(moduleData, 'chart', []), (label, prop) => {
-//   //       return { label, value: _.get(data, prop, '/') };
-//   //     }),
-//   //     list: _.map(_.get(moduleData, 'list', []), (label, prop) => {
-//   //       return { label, value: _.get(data, prop, '/') };
-//   //     }),
-//   //   };
-//   // }
-//   return {
-//     chart: _.map(_.get(moduleData, 'chart', []), (label, prop) => {
-//       return { label, prop };
-//     }),
-//     list: _.map(_.get(moduleData, 'list', []), (label, prop) => {
-//       return { label, prop };
-//     }),
-//   };
-// }
-
 /** 根据配置中的 formatter 将文本格式并返回 */
 export function getFormattedText(data: any, formatter: string, defaultValue?: any): string {
   // e.g. 'pre${prop[0].name}suf' => ['pre${prop[0].name}suf', 'prop[0].name']
@@ -78,6 +41,7 @@ export function getFormattedText(data: any, formatter: string, defaultValue?: an
   return formatter.replace(exp, _.get(data, prop, val));
 }
 
+/** 获取 formatter 需要取的源 prop,用于在一些不支持 formatter 的组件中使用 */
 export function getRawProp(formatter: string): string {
   // e.g. 'pre${prop[0].name}suf' => ['pre${prop[0].name}suf', 'prop[0].name']
   const exp = /\$\{([\w|\.|\[|\]]*)\}/g;

+ 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();
+  }
+
   /**
    * 编辑事件
    */

+ 83 - 75
src/views/vent/deviceManager/configurationTable/options.ts

@@ -8,11 +8,14 @@ export const ModuleSizeMap = {
   'width:1000px;height:280px;': '横向拉伸(1000*280)',
   'width:1920px;height:280px;': '横向填充(1920*280)',
 };
+
+/** 默认的模块宽高选项 */
 export const ModuleSizeOptions = _.map(ModuleSizeMap, (v, k) => ({
   value: k,
   label: v,
 }));
 
+/** 默认的模块版本选项,即外边框样式 */
 export const ModuleVersionOptions = _.map(['原版', '新版'], (k) => ({
   value: k,
   label: k,
@@ -28,11 +31,14 @@ export const ModulePositionMap = {
   'top:640px;right:0;': '右下',
   'top:640px;left:460px;': '中下',
 };
+
+/** 默认的模块定位选项 */
 export const ModulePositionOptions = _.map(ModulePositionMap, (v, k) => ({
   value: k,
   label: v,
 }));
 
+/** 默认的模块预设选项,每个预设对应着一种写好的配置 */
 export const ModulePresetOptions = _.map(
   [
     '告示版(1*1)',
@@ -50,6 +56,8 @@ export const ModulePresetOptions = _.map(
     label: k,
   })
 );
+
+/** 默认的模块预设表 */
 export const ModulePresetMap: Record<
   string,
   {
@@ -64,10 +72,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -83,11 +91,11 @@ export const ModulePresetMap: Record<
           readFrom: 'readData',
           items: [
             {
-              prop: '${Fan1StartStatus_str}',
+              value: '${Fan1StartStatus_str}',
               label: '一号机状态',
             },
             {
-              prop: '${Fan2StartStatus_str}',
+              value: '${Fan2StartStatus_str}',
               label: '二号机状态',
             },
           ],
@@ -111,10 +119,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -129,15 +137,15 @@ export const ModulePresetMap: Record<
         {
           type: 'line',
           readFrom: 'majorpath.paths',
-          xAxis: [{ prop: '${name}' }],
+          xAxis: [{ label: '${name}' }],
           yAxis: [
             { label: 'Drag', align: 'left' },
             { label: 'M3', align: 'right' },
           ],
           series: [
-            { label: 'Drag', prop: '${drag}' },
-            { label: 'M3', prop: '${m3}' },
-            // { label: '回2', prop: '${hui2}' },
+            { label: 'Drag', value: '${drag}' },
+            { label: 'M3', value: '${m3}' },
+            // { label: '回2', value: '${hui2}' },
           ],
         },
       ],
@@ -157,10 +165,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -175,15 +183,15 @@ export const ModulePresetMap: Record<
         {
           type: 'line_area',
           readFrom: 'majorpath.paths',
-          xAxis: [{ prop: '${name}' }],
+          xAxis: [{ label: '${name}' }],
           yAxis: [
             { label: 'Drag', align: 'left' },
             { label: 'M3', align: 'right' },
           ],
           series: [
-            { label: 'Drag', prop: '${drag}' },
-            { label: 'M3', prop: '${m3}' },
-            // { label: '回2', prop: '${hui2}' },
+            { label: 'Drag', value: '${drag}' },
+            { label: 'M3', value: '${m3}' },
+            // { label: '回2', value: '${hui2}' },
           ],
         },
       ],
@@ -201,10 +209,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -222,9 +230,9 @@ export const ModulePresetMap: Record<
           xAxis: [],
           yAxis: [],
           series: [
-            { label: 'Drag', prop: '${drag}' },
-            { label: 'M3', prop: '${m3}' },
-            // { label: '回2', prop: '${hui2}' },
+            { label: 'Drag', value: '${drag}' },
+            { label: 'M3', value: '${m3}' },
+            // { label: '回2', value: '${hui2}' },
           ],
         },
       ],
@@ -242,10 +250,10 @@ export const ModulePresetMap: Record<
         showSelector: false,
         showSlot: false,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -264,9 +272,9 @@ export const ModulePresetMap: Record<
         {
           type: 'bar',
           readFrom: 'sysdata.history',
-          xAxis: [{ prop: '${time}' }],
+          xAxis: [{ label: '${time}' }],
           yAxis: [{ label: '回1', align: 'left' }],
-          series: [{ label: '回1', prop: '${hui1}' }],
+          series: [{ label: '回1', value: '${hui1}' }],
         },
       ],
     },
@@ -279,10 +287,10 @@ export const ModulePresetMap: Record<
         showSelector: false,
         showSlot: false,
         selector: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
         slot: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
       },
       background: {
@@ -298,25 +306,25 @@ export const ModulePresetMap: Record<
           readFrom: 'device',
           items: [
             {
-              prop: '${gate}',
+              value: '${gate}',
               label: '风门',
               // label: '光纤预警',
               color: 'blue',
             },
             {
-              prop: '${window}',
+              value: '${window}',
               label: '风窗',
               // label: '喷雾开启数',
               color: 'blue',
             },
             {
-              prop: '${windrect}',
+              value: '${windrect}',
               label: '测风',
               // label: '联网数量',
               color: 'blue',
             },
             {
-              prop: '${stationtype}',
+              value: '${stationtype}',
               label: '空位',
               // label: '断网数量',
               color: 'blue',
@@ -339,10 +347,10 @@ export const ModulePresetMap: Record<
         showSelector: false,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${网络异常:}${netstatus.val} 台',
+          value: '${网络异常:}${netstatus.val} 台',
         },
       },
       background: {
@@ -364,31 +372,31 @@ export const ModulePresetMap: Record<
           items: [
             {
               label: '正常',
-              prop: '${blue}.val',
+              value: '${blue}.val',
               color: 'blue',
               info: '',
             },
             {
               label: '告警',
-              prop: '${orange}.val',
+              value: '${orange}.val',
               color: 'orange',
               info: '',
             },
             {
               label: '报警',
-              prop: '${yellow}.val',
+              value: '${yellow}.val',
               color: 'yellow',
               info: '',
             },
             {
               label: '危险',
-              prop: '${red}.val',
+              value: '${red}.val',
               color: 'red',
               info: '',
             },
             {
               label: '错误',
-              prop: '${alarm}.val',
+              value: '${alarm}.val',
               color: 'green',
               info: '',
             },
@@ -405,10 +413,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
         slot: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
       },
       background: {
@@ -428,19 +436,19 @@ export const ModulePresetMap: Record<
           readFrom: 'history',
           columns: [
             {
-              prop: '${cate}',
+              prop: 'cate',
               label: '类别',
             },
             {
-              prop: '${temp}',
+              prop: 'temp',
               label: '温度',
             },
             {
-              prop: '${wspd}',
+              prop: 'wspd',
               label: '风速',
             },
             {
-              prop: '${spst}',
+              prop: 'spst',
               label: '喷雾状态',
             },
           ],
@@ -457,10 +465,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: false,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
       },
       background: {
@@ -486,10 +494,10 @@ export const ModulePresetMap: Record<
         showSelector: false,
         showSlot: true,
         selector: {
-          prop: '${strinstallpos}',
+          value: '${strinstallpos}',
         },
         slot: {
-          prop: '${网络异常:}${netstatus.val} 台',
+          value: '${网络异常:}${netstatus.val} 台',
         },
       },
       background: {
@@ -510,13 +518,13 @@ export const ModulePresetMap: Record<
           items: [
             {
               label: '堵塞状态',
-              prop: '${fsectarea}',
+              value: '${fsectarea}',
               color: 'yellow',
               info: '',
             },
             {
               label: '甲烷浓度',
-              prop: '${stationname}',
+              value: '${stationname}',
               color: 'yellow',
               info: '',
             },
@@ -530,37 +538,37 @@ export const ModulePresetMap: Record<
           items: [
             {
               label: '火情状态',
-              prop: '${fsectarea}',
+              value: '${fsectarea}',
               color: 'yellow',
               info: '',
             },
             {
               label: '回采位置',
-              prop: '${stationname}',
+              value: '${stationname}',
               color: 'white',
               info: '',
             },
             {
               label: '硐室火情',
-              prop: '${stationtype}',
+              value: '${stationtype}',
               color: 'blue',
               info: '',
             },
             {
               label: '联动设备状态',
-              prop: '${typeName}',
+              value: '${typeName}',
               color: 'blue',
               info: '',
             },
           ],
           galleryItems: [
             {
-              prop: '${低风险}',
+              value: '${低风险}',
               label: '',
               color: 'white',
             },
             {
-              prop: '${CO}',
+              value: '${CO}',
               label: '',
               color: 'white',
             },
@@ -580,10 +588,10 @@ export const ModulePresetMap: Record<
         showSelector: true,
         showSlot: true,
         selector: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
         slot: {
-          prop: '${devicePos}',
+          value: '${devicePos}',
         },
       },
       background: {
@@ -601,73 +609,73 @@ export const ModulePresetMap: Record<
           items: [
             {
               label: '火情状态',
-              prop: '${fsectarea}',
+              value: '${fsectarea}',
               color: 'yellow',
               info: '',
             },
             {
               label: '回采位置',
-              prop: '${stationname}',
+              value: '${stationname}',
               color: 'white',
               info: '',
             },
             {
               label: '硐室火情',
-              prop: '${stationtype}',
+              value: '${stationtype}',
               color: 'blue',
               info: '',
             },
             {
               label: '联动设备状态',
-              prop: '${typeName}',
+              value: '${typeName}',
               color: 'blue',
               info: '',
             },
             {
               label: '火情状态',
-              prop: '${fsectarea}',
+              value: '${fsectarea}',
               color: 'yellow',
               info: '',
             },
             {
               label: '回采位置',
-              prop: '${stationname}',
+              value: '${stationname}',
               color: 'white',
               info: '',
             },
             {
               label: '硐室火情',
-              prop: '${stationtype}',
+              value: '${stationtype}',
               color: 'blue',
               info: '',
             },
             {
               label: '联动设备状态',
-              prop: '${typeName}',
+              value: '${typeName}',
               color: 'blue',
               info: '',
             },
             // {
             //   label: '火情状态',
-            //   prop: '${fsectarea}',
+            //   value: '${fsectarea}',
             //   color: 'yellow',
             //   info: '',
             // },
             // {
             //   label: '回采位置',
-            //   prop: '${stationname}',
+            //   value: '${stationname}',
             //   color: 'white',
             //   info: '',
             // },
             // {
             //   label: '硐室火情',
-            //   prop: '${stationtype}',
+            //   value: '${stationtype}',
             //   color: 'blue',
             //   info: '',
             // },
             // {
             //   label: '联动设备状态',
-            //   prop: '${typeName}',
+            //   value: '${typeName}',
             //   color: 'blue',
             //   info: '',
             // },
@@ -684,32 +692,32 @@ export const ModulePresetMap: Record<
           items: [
             {
               label: '火情状态',
-              prop: '${fsectarea}',
+              value: '${fsectarea}',
               color: 'yellow',
               info: '',
             },
             {
               label: '回采位置',
-              prop: '${stationname}',
+              value: '${stationname}',
               color: 'white',
               info: '',
             },
             {
               label: '硐室火情',
-              prop: '${stationtype}',
+              value: '${stationtype}',
               color: 'blue',
               info: '',
             },
             {
               label: '联动设备状态',
-              prop: '${typeName}',
+              value: '${typeName}',
               color: 'blue',
               info: '',
             },
           ],
           galleryItems: [
             {
-              prop: '${低风险}',
+              value: '${低风险}',
               label: '风险等级',
               color: 'white',
             },

+ 165 - 106
src/views/vent/deviceManager/configurationTable/types.ts

@@ -3,171 +3,230 @@ import { ModulePositionMap, ModuleSizeMap } from './options';
 export interface Config {
   /** 模块的名称 */
   moduleName: string;
-  /** 所属页面 */
+  /** 所属页面,用于在有多个可配置首页时划分归类 */
   pageType: string;
-  /** 设备类型,但目前不重要了 */
+  /** 设备类型,在模块设置了 header 后作为取数据依赖的 prop */
   deviceType: string;
   /** 模块配置,核心之一 */
   moduleData: ModuleData;
   /** 模块样式,核心之一 */
   showStyle: ShowStyle;
-  /** 模块描述,可用于存储其他信息 */
+  /** 模块描述,可用于存储其他信息,目前用于原始预设信息存储 */
   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 配取值路径,反之应配置详尽路径 */
   readFrom: string;
+  /** 核心配置,每个展示牌对应一项 */
   items: {
-    /** 展示牌说明内容 */
+    /** 展示牌说明内容,formatter 格式 */
     label: string;
-    prop: string;
+    /** 展示牌值内容,formatter 格式 */
+    value: string;
   }[];
 }
+
 export interface ModuleDataList {
-  /** 列表项预设的背景类型 */
-  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E';
-  /** 读取数据时的基础路径 */
+  /** 列表预设的背景类型 */
+  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
+  /** 核心配置,每个列表项对应一项 */
   items: {
-    /** 列表项说明内容 */
+    /** 列表项说明内容,formatter 格式 */
     label: string;
-    prop: string;
-    color: string;
-    /** 针对列表项说明的额外信息 */
+    /** 列表项值内容,formatter 格式 */
+    value: string;
+    /** 列表项指定颜色,根据类型不同会有各自的样式 */
+    color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
+    /** 针对列表项说明的额外信息,部分类型的列表项会使用 */
     info: string;
   }[];
-  /** 列表左侧展示的图片路径 */
-  image?: string;
 }
+
 export interface ModuleDataGallery {
-  /** 列表项预设的背景类型 */
-  type: 'A' | 'B';
-  /** 读取数据时的基础路径 */
+  /** 画廊预设的背景类型 */
+  type: 'A' | 'B' | 'C' | 'D' | 'E';
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
+  /** 核心配置,每个画廊项对应一项 */
   items: {
-    /** 列表项说明内容 */
+    /** 画廊项说明内容,formatter 格式 */
     label: string;
-    prop: string;
-    color: string;
+    /** 画廊项值内容,formatter 格式 */
+    value: string;
+    /** 画廊项指定颜色,根据类型不同会有各自的样式 */
+    color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
   }[];
 }
-export interface ModuleDataComplexList {
-  /** 列表项预设的背景类型 */
+
+export interface ModuleDataGalleryList {
+  /** 复杂列表预设的背景类型 */
   type: 'A' | 'B';
-  /** 读取数据时的基础路径 */
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
+  /** 核心配置,每个复杂列表的列表项对应一项 */
   items: {
-    /** 列表项说明内容 */
+    /** 列表项说明内容,formatter 格式 */
     label: string;
-    prop: string;
-    color: string;
-    /** 针对列表项说明的额外信息 */
+    /** 列表项值内容,formatter 格式 */
+    value: string;
+    /** 列表项指定颜色,根据类型不同会有各自的样式 */
+    color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
+    /** 针对列表项说明的额外信息,部分类型的列表项会使用 */
     info: string;
   }[];
+  /** 核心配置,每个复杂列表的画廊项对应一项 */
   galleryItems: {
-    /** 列表项说明内容 */
+    /** 画廊项说明内容,formatter 格式 */
     label: string;
-    prop: string;
-    color: string;
+    /** 画廊项值内容,formatter 格式 */
+    value: string;
+    /** 画廊项指定颜色,根据类型不同会有各自的样式 */
+    color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
   }[];
 }
+
 export interface ModuleDataChart {
-  /** 图表通用类型,一个类型对应一种图表预设 */
+  /** 图表类型,一个类型对应一种图表预设 */
   type: 'pie' | 'bar' | 'line' | 'line_area';
-  /** 读取数据时的基础路径,例如如果图表依赖一个数组,那么该项应设置能读取到该数组的路径。例如:readData.history */
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径。特别的是,pie 类型的图表应将路径指到对象上,其他的图表应该指到数组上 */
   readFrom: string;
-  /** 排序依据,该项应配置为`readFrom`指向的数据中的可读项。例如:createTime */
+  /** 排序依据,该项应配置将配合 readFrom 使用 */
   sortBy?: string;
   /** 排序规则,desc降序,asc升序 */
   order?: 'desc' | 'asc';
-  /** 图表x轴配置(若有),例如:{ prop: 'strInstallPos' } */
+  /** 图表x轴配置(若有),支持多个 */
   xAxis: {
-    prop: string;
+    /** x轴内容,formatter 格式 */
+    label: string;
   }[];
-  /** 图表y轴配置(若有),例如:['风量', '风速'] */
+  /** 图表y轴配置(若有),支持多个 */
   yAxis: {
+    /** y轴内容,formatter 格式 */
     label: string;
+    /** y轴的对齐方式 */
     align: 'left' | 'right';
   }[];
-  /** 图表各系列配置,一个系列应对应一个数据维度,例如:[{ label: '风量', prop: 'f1Val' }] */
-  series: { label: string; prop: string }[];
+  /** 核心配置,一个系列应对应一个数据维度,例如:[{ label: '风量', prop: '${f1Val}' }] */
+  series: {
+    /** 数据说明,formatter 格式 */
+    label: string;
+    /** 取值 prop,注意该项不支持 formatter 格式 */
+    prop: string;
+  }[];
 }
+
 export interface ModuleDataTable {
   /** 表格的预设样式 */
-  type: 'A' | 'B';
-  /** 读取数据时的基础路径 */
+  type: 'A' | 'B' | 'C';
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
-  columns: { label: string; prop: string }[];
+  /** 核心配置,每个表格列对应一项 */
+  columns: {
+    /** 数据说明,注意该项不支持 formatter 格式 */
+    name: string;
+    /** 取值 prop,注意该项不支持 formatter 格式 */
+    prop: string;
+  }[];
 }
+
 export interface ModuleDataPreset {
-  /** 表格的预设样式 */
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
+  readFrom: string;
+  /** 表格的预设样式,由各个预设单独使用,没有固定类型 */
   [key: string]: any;
 }
 
-/**
- * 模块的配置
- *
- * 该配置将描述本模块的基础样式,应该展示哪些内容,应该如何排布主要元素
- *
- * 配置中有几项常用的配置,以下是其说明:
- *
- * 假设模块依赖的数据为:`{ f1Val: 2555 }`
- *
- * `formatter`该配置是用于自定义展示文本的,应配合`prop`使用。
- *
- * 使用示例:formatter:`前缀${}后缀`; prop:`f1Val`。则对应的文本将是`前缀f1Val后缀`
- *
- */
-export interface ModuleData {
-  header: {
-    show: boolean;
-    /** 是否展示左侧的选择框 */
-    showSelector: boolean;
-    /** 是否展示右侧插槽 */
-    showSlot: boolean;
-    /** 左侧选择框的配置 */
-    selector: {
-      /** 图标,具体支持的输入种类请联系技术人员 */
-      icon?: string;
-      prop: string;
-    };
-    /** 右侧插槽的配置 */
-    slot: {
-      /** 图标,具体支持的输入种类请联系技术人员 */
-      icon?: string;
-      prop: string;
-    };
-  };
-  background: {
-    show: boolean;
-    /** 背景资源的类型 */
-    type: 'image' | 'video';
-    /** 背景资源的链接 */
-    link: string;
-  };
-  // layout: (ModuleDataBoard | ModuleDataChart | ModuleDataList | ModuleDataTable | ModuleDataPreset)[];
-  /** 模块的布局,使用规定的枚举组合为一个数组,代表着从上到下所应展示的元素 */
-  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[];
-}
-export interface ShowStyle {
-  /** 模块的宽高,一般来说是选好不动即可。特殊情况下可以自定义宽高 */
-  size: keyof typeof ModuleSizeMap;
-  /** 模块的版本,分新版及旧版,只要有一个模块指定为旧版,那么整个页面风格将变更为旧版 */
-  version: '原版' | '新版' | '普通版';
-  /** 模块的位置,即定位 */
-  position: keyof typeof ModulePositionMap;
+export interface ModuleDataComplexList {
+  /** 列表预设的背景类型 */
+  type: 'A' | 'B';
+  /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
+  readFrom: string;
+  /** 核心配置,每个列表项对应一项 */
+  items: {
+    /** 列表项标题,formatter 格式 */
+    title: string;
+    contents: {
+      /** 列表项说明内容,formatter 格式 */
+      label: string;
+      /** 列表项值内容,formatter 格式 */
+      value: string;
+      /** 列表项指定颜色,根据类型不同会有各自的样式 */
+      color: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white';
+      /** 针对列表项说明的额外信息,部分类型的列表项会使用 */
+      info: string;
+    }[];
+  }[];
 }

+ 1 - 1
src/views/vent/home/configurable/README.md

@@ -10,4 +10,4 @@
 
 将上述两个组件配置到菜单中之后:
 
-点开配置表格,对各个设备进行配置,配置好的点表/字段/样式等将用于在首页展示。如有多个需要配置的首页。首页各个模块都有其对应的设备,例如:左上角对应主通风机
+点开配置表格,对各个设备进行配置,配置好的点表/字段/样式等将用于在首页展示。

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

@@ -1,165 +0,0 @@
-<!-- eslint-disable vue/multi-word-component-names -->
-<template>
-  <!-- 基准的画廊模块,通过不同的 type 展示不同的样式 -->
-  <div class="gallery" :class="`gallery_${type}`">
-    <!-- 部分类型的画廊需要加一张图片 -->
-    <div :class="`gallery-item_center_${type}`"></div>
-    <div v-for="item in galleryConfig" :key="item.prop" :class="`gallery-item_${type}`">
-      <!-- 画廊项的具体内容填充剩余宽度 -->
-      <div class="gallery-item__label">{{ item.label }}</div>
-      <div class="gallery-item__value" :class="`gallery-item__value_${item.color}`">{{ item.value }}</div>
-    </div>
-  </div>
-</template>
-<script lang="ts" setup>
-  // import { get } from 'lodash-es';
-  // import { computed } from 'vue';
-
-  withDefaults(
-    defineProps<{
-      galleryConfig: {
-        value: string;
-        color: string;
-        label: string;
-        prop: string;
-      }[];
-      type: string;
-    }>(),
-    {
-      galleryConfig: () => [],
-      type: 'A',
-    }
-  );
-  //   defineEmits(['click']);
-</script>
-<style lang="less" scoped>
-  @import '@/design/vent/color.less';
-  /* Timeline 相关的样式 */
-
-  .gallery {
-    position: relative;
-    width: 100%;
-    height: 100%;
-  }
-
-  .gallery-item_center_A {
-    background: url(@/assets/images/home-container/configurable/gallery_center.png) no-repeat;
-    width: 144px;
-    height: 126px;
-    left: calc(50% - 72px);
-    top: calc(50% - 63px);
-    position: absolute;
-    background-size: 100% 100%;
-  }
-  .gallery > .gallery-item_A {
-    background: url(@/assets/images/home-container/configurable/gallery_1.png) no-repeat;
-    width: 90px;
-    height: 90px;
-    position: absolute;
-    text-align: center;
-  }
-  .gallery > .gallery-item_A:nth-child(2) {
-    top: 20px;
-    left: 60px;
-  }
-  .gallery > .gallery-item_A:nth-child(3) {
-    top: 20px;
-    right: 60px;
-  }
-  .gallery > .gallery-item_A:nth-child(4) {
-    bottom: 20px;
-    left: 60px;
-  }
-  .gallery > .gallery-item_A:nth-child(5) {
-    bottom: 20px;
-    right: 60px;
-  }
-
-  .gallery-item_center_B {
-    background: url(/@/assets/images/home-container/configurable/deco_2.png) no-repeat;
-    width: 100%;
-    height: 90%;
-    top: 5%;
-    position: absolute;
-    background-position: center;
-    background-size: auto 100%;
-  }
-  // .gallery .gallery-item__value {
-  //   display: none;
-  // }
-  .gallery > .gallery-item_B {
-    background: url(/@/assets/images/home-container/configurable/deco_3.png) no-repeat;
-    position: absolute;
-    text-align: center;
-    background-position: center;
-    background-size: auto 100%;
-  }
-  .gallery > .gallery-item_B:nth-child(2) {
-    width: 70px;
-    height: 70px;
-    line-height: 70px;
-    top: 20px;
-    left: calc(50% - 70px);
-  }
-  .gallery > .gallery-item_B:nth-child(3) {
-    width: 60px;
-    height: 60px;
-    line-height: 60px;
-    top: 50px;
-    // right: 34%;
-    right: calc(50% - 70px);
-  }
-  .gallery > .gallery-item_B:nth-child(4) {
-    width: 55px;
-    height: 55px;
-    line-height: 55px;
-    bottom: 90px;
-    left: calc(50% - 55px);
-  }
-  .gallery > .gallery-item_B:nth-child(5) {
-    width: 50px;
-    height: 50px;
-    line-height: 50px;
-    bottom: 70px;
-    right: calc(50% - 50px);
-  }
-  .gallery-item_B > .gallery-item__label {
-    display: none;
-  }
-
-  .gallery-item_center_C {
-    background: url(/@/assets/images/home-container/configurable/deco_4.png) no-repeat;
-    width: 100%;
-    height: 100%;
-    // top: 5%;
-    position: absolute;
-    background-position: center;
-    background-size: auto 100%;
-  }
-  .gallery_C {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: space-around;
-    text-align: center;
-  }
-  .gallery-item_C > .gallery-item__value {
-    font-size: 20px;
-  }
-
-  .gallery-item__value_red {
-    color: red;
-  }
-  .gallery-item__value_orange {
-    color: orange;
-  }
-  .gallery-item__value_yellow {
-    color: yellow;
-  }
-  .gallery-item__value_green {
-    color: yellowgreen;
-  }
-  .gallery-item__value_blue {
-    color: lightblue;
-  }
-</style>

+ 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);
+
+  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>

+ 24 - 6
src/views/vent/home/configurable/components/ModuleCommon.vue

@@ -1,26 +1,38 @@
 <template>
+  <!-- 常用模块 -->
   <ventBox1 class="module-common" :style="style">
-    <template #title>
-      <div>{{ moduleName }}</div>
+    <template v-if="moduleName" #title>
+      <div @click="redirectTo">{{ moduleName }}</div>
     </template>
     <template #container>
-      <slot></slot>
+      <slot>
+        <Header :deviceType="deviceType" :moduleData="moduleData" @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;
   }>();
-  defineEmits(['close']);
+  defineEmits(['close', 'click']);
+
+  const { header } = props.moduleData;
+  const selectedData = ref();
 
   const style = computed(() => {
     const size = props.showStyle.size;
@@ -35,6 +47,12 @@
   //   }
   //   return ModuleLeft;
   // }
+
+  function redirectTo() {
+    const { to } = props.moduleData;
+    if (!to) return;
+    openWindow(to);
+  }
 </script>
 <style scoped>
   .module-common .box1-center {

+ 33 - 11
src/views/vent/home/configurable/components/ModuleEnhanced.vue

@@ -1,21 +1,40 @@
 <template>
-  <component :is="getModuleComponent(showStyle.position)" :style="style" :title="moduleName" :visible="visible" @close="$emit('close')">
-    <slot></slot>
+  <!-- 新版模块 -->
+  <component
+    :is="getModuleComponent(showStyle.position)"
+    :style="style"
+    :title="moduleName"
+    :visible="visible"
+    @close="$emit('close')"
+    @click="redirectTo"
+  >
+    <slot>
+      <Header :deviceType="deviceType" :moduleData="moduleData" @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']);
+  defineEmits(['close', 'click']);
+
+  const { header } = props.moduleData;
+  const selectedData = ref();
 
   const style = computed(() => {
     const size = props.showStyle.size;
@@ -25,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>

+ 35 - 8
src/views/vent/home/configurable/components/ModuleOriginal.vue

@@ -1,20 +1,39 @@
 <template>
-  <component :is="getModuleComponent(showStyle.position)" :style="style" :title="moduleName" :visible="visible" @close="$emit('close')">
-    <slot></slot>
+  <!-- 原版模块 -->
+  <component
+    :is="getModuleComponent(showStyle.position)"
+    :style="style"
+    :title="moduleName"
+    :visible="visible"
+    @close="$emit('close')"
+    @click="redirectTo"
+  >
+    <slot>
+      <Header :deviceType="deviceType" :moduleData="moduleData" @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']);
+  defineEmits(['close', 'click']);
+
+  const { header } = props.moduleData;
+  const selectedData = ref();
 
   const style = computed(() => {
     const size = props.showStyle.size;
@@ -24,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>

+ 79 - 190
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
@@ -75,30 +40,36 @@
           <CustomList class="content__module" :type="config.type" :list-config="config.items" />
         </template>
       </template>
+      <!-- 画廊部分 -->
       <template v-if="config.key === 'gallery'">
         <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'">
         <CommonTable
           v-if="config.type === 'A'"
           :columns="config.columns"
-          :data="tableData"
+          :data="config.data"
           class="content__module text-center flex-grow overflow-auto"
         />
         <CustomTable
           v-else
           :type="config.type"
           :columns="config.columns"
-          :data="tableData"
+          :data="config.data"
           class="content__module text-center flex-grow overflow-auto"
         />
       </template>
       <template v-if="config.key === 'blast_delta'">
-        <BlastDelta class="content__module" :pos-monitor="blastDeltaData" :canvas-size="{ width: 250, height: 137 }" />
+        <BlastDelta class="content__module" :pos-monitor="config.config.mock" :canvas-size="{ width: 250, height: 137 }" />
       </template>
       <template v-if="config.key === 'fire_control'">
         <FIreControl class="content__module" />
@@ -110,7 +81,7 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { computed, onMounted, ref } from 'vue';
+  import { computed } from 'vue';
   import {
     Config,
     // ModuleDataBoard,
@@ -119,39 +90,45 @@
     // 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, getRawProp } 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 { posMonitorData } from '../configurable.data';
+  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 } = props.moduleData;
+
+  // 额外的 header 相关的变量
+
+  function getData(raw, readFrom) {
+    if (readFrom) {
+      return get(raw, readFrom);
+    }
+    return raw;
+  }
 
   /** 根据配置里的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);
@@ -161,7 +138,7 @@
         case 'board': {
           const cfg = board.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
 
           arr.push({
             ...cfg,
@@ -170,7 +147,7 @@
               return {
                 ...i,
                 label: getFormattedText(data, i.label),
-                value: getFormattedText(data, i.prop),
+                value: getFormattedText(data, i.value),
               };
             }),
           });
@@ -179,7 +156,8 @@
         case 'list': {
           const cfg = list.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
+
           arr.push({
             ...cfg,
             key,
@@ -187,7 +165,7 @@
               return {
                 ...i,
                 label: getFormattedText(data, i.label),
-                value: getFormattedText(data, i.prop),
+                value: getFormattedText(data, i.value),
               };
             }),
           });
@@ -196,7 +174,7 @@
         case 'gallery': {
           const cfg = gallery.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
 
           arr.push({
             ...cfg,
@@ -205,7 +183,7 @@
               return {
                 ...i,
                 label: getFormattedText(data, i.label),
-                value: getFormattedText(data, i.prop),
+                value: getFormattedText(data, i.value),
               };
             }),
           });
@@ -214,7 +192,30 @@
         case 'complex_list': {
           const cfg = complex_list.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
+
+          arr.push({
+            ...cfg,
+            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,
@@ -223,14 +224,14 @@
               return {
                 ...i,
                 label: getFormattedText(data, i.label),
-                value: getFormattedText(data, i.prop),
+                value: getFormattedText(data, i.value),
               };
             }),
             galleryItems: cfg.galleryItems.map((i) => {
               return {
                 ...i,
                 label: getFormattedText(data, i.label),
-                value: getFormattedText(data, i.prop),
+                value: getFormattedText(data, i.value),
               };
             }),
           });
@@ -239,7 +240,7 @@
         case 'chart': {
           const cfg = chart.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
 
           arr.push({
             key,
@@ -251,17 +252,12 @@
         case 'table': {
           const cfg = table.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
 
           arr.push({
             ...cfg,
             key,
-            columns: (cfg.columns || []).map((e) => {
-              return {
-                name: e.label,
-                prop: getRawProp(e.prop),
-              };
-            }),
+            columns: cfg.columns,
             data: get(data, cfg.readFrom, []),
           });
           break;
@@ -269,7 +265,7 @@
         default: {
           const cfg = preset.shift();
           if (!cfg) break;
-          const data = mock || cfg.readFrom ? get(refData, cfg.readFrom) : refData;
+          const data = getData(refData, cfg.readFrom);
 
           arr.push({
             key,
@@ -282,110 +278,6 @@
       return arr;
     }, []);
   });
-
-  // 额外的 header 相关的变量
-  const headerVisible = ref(false);
-  function headerSelectHandler({ key }) {
-    selectedDeviceID.value = key;
-  }
-
-  // 额外的告示牌相关的变量
-  // const boardConfig = computed(() => {
-  //   const data = selectedDevice.value;
-  //   return (board || []).map((b) => {
-  //     return {
-  //       ...b.items,
-  //       value: getFormattedText(data, b.prop, b.formatter),
-  //     };
-  //   });
-  // });
-
-  // 额外的时间线列表相关的变量
-  // const listConfig = computed(() => {
-  //   const data = selectedDevice.value;
-  //   return (list || []).map((b) => {
-  //     return {
-  //       ...b,
-  //       value: getFormattedText(data, b.prop, b.formatter),
-  //     };
-  //   });
-  // });
-  // const listType = computed(() => {
-  //   return list[0]?.type || 'A';
-  // });
-
-  // const chartConfig = computed(() => {
-  //   return chart[0];
-  // });
-  // const chartData = computed(() => {
-  //   const data = selectedDevice.value;
-  //   return get(data, chart[0]?.readFrom, []);
-  // });
-
-  // const tableConfig = computed(() => {
-  //   return {
-  //     columns: (table[0]?.columns || []).map((e) => {
-  //       return {
-  //         name: e.label,
-  //         prop: e.prop,
-  //       };
-  //     }),
-  //   };
-  // });
-  const tableData = computed(() => {
-    // const data = selectedDevice.value;
-    return [
-      {
-        index: '1',
-        time: '2024/07/22 07:00',
-        warn: '未知',
-        cate: 'xxx综采工作面',
-        temp: '26',
-        wspd: '2',
-        spst: 'ON',
-      },
-      {
-        index: '2',
-        time: '2024/07/22 08:00',
-        warn: '未知',
-        cate: 'xxx综采工作面',
-        temp: '26',
-        wspd: '2',
-        spst: 'ON',
-      },
-      {
-        index: '3',
-        time: '2024/07/22 09:00',
-        warn: '未知',
-        cate: 'xxx综采工作面',
-        temp: '26',
-        wspd: '2',
-        spst: 'ON',
-      },
-      {
-        index: '4',
-        time: '2024/07/22 10:00',
-        warn: '未知',
-        cate: 'xxx综采工作面',
-        temp: '26',
-        wspd: '2',
-        spst: 'ON',
-      },
-    ];
-    // return get(data, table[0]?.readFrom, []);
-  });
-
-  const blastDeltaData = ref();
-
-  const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
-    props.deviceType,
-    headerConfig
-  );
-
-  onMounted(() => {
-    blastDeltaData.value = posMonitorData;
-    fetchDevices();
-  });
 </script>
 <style lang="less" scoped>
   @import '@/design/vent/color.less';
@@ -415,9 +307,6 @@
     display: flex;
     flex-direction: column;
   }
-  .content_without_header {
-    height: 100%;
-  }
   .content__background {
     width: 100%;
     height: 100%;
@@ -431,12 +320,12 @@
     margin-top: 5px;
     margin-bottom: 5px;
   }
-  .content__module:first-of-type {
-    margin-top: 0;
-  }
-  .content__module:last-of-type {
-    margin-bottom: 0;
-  }
+  // .content__module:first-of-type {
+  //   margin-top: 0;
+  // }
+  // .content__module:last-of-type {
+  //   margin-bottom: 0;
+  // }
   ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
     /* background-color: transparent; */
     color: #fff;

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

@@ -0,0 +1,189 @@
+<!-- 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;
+    margin-bottom: 10px;
+
+    .list-item__label {
+      font-size: 12px;
+    }
+    .list-item__content_B {
+      display: flex;
+      align-items: center;
+    }
+    .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>

+ 4 - 4
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<{
@@ -88,7 +88,7 @@
           return {
             type: 'category',
             data: sorttedData.map((d) => {
-              return getFormattedText(d, e.prop);
+              return getFormattedText(d, e.label);
             }),
           };
         }),
@@ -172,7 +172,7 @@
           return {
             type: 'category',
             data: sorttedData.map((d) => {
-              return getFormattedText(d, e.prop);
+              return getFormattedText(d, e.label);
             }),
           };
         }),
@@ -225,7 +225,7 @@
             type: 'category',
             boundaryGap: false,
             data: sorttedData.map((d) => {
-              return getFormattedText(d, e.prop);
+              return getFormattedText(d, e.label);
             }),
           };
         }),

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

@@ -0,0 +1,358 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <!-- 基准的画廊模块,通过不同的 type 展示不同的样式 -->
+  <div class="gallery" :class="`gallery_${type}`">
+    <!-- 部分类型的画廊需要加一张图片 -->
+    <div :class="`gallery-item_center_${type}`"></div>
+    <div v-for="item in galleryConfig" :key="item.prop" :class="`gallery-item_${type}`">
+      <!-- 画廊项的具体内容填充剩余宽度 -->
+      <div class="gallery-item__label">{{ item.label }}</div>
+      <div class="gallery-item__value" :class="`gallery-item__value_${item.color}`">{{ item.value }}</div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  // import { get } from 'lodash-es';
+  // import { computed } from 'vue';
+
+  withDefaults(
+    defineProps<{
+      galleryConfig: {
+        value: string;
+        color: string;
+        label: string;
+        prop: string;
+      }[];
+      /** A | B | C | D */
+      type: string;
+    }>(),
+    {
+      galleryConfig: () => [],
+      type: 'A',
+    }
+  );
+  //   defineEmits(['click']);
+</script>
+<style lang="less" scoped>
+  @import '@/design/vent/color.less';
+  /* Timeline 相关的样式 */
+
+  .gallery {
+    position: relative;
+    width: 100%;
+    height: 100%;
+  }
+
+  .gallery-item_center_A {
+    background: url(@/assets/images/home-container/configurable/gallery_center.png) no-repeat;
+    width: 144px;
+    height: 126px;
+    left: calc(50% - 72px);
+    top: calc(50% - 63px);
+    position: absolute;
+    background-size: 100% 100%;
+  }
+  .gallery > .gallery-item_A {
+    background: url(@/assets/images/home-container/configurable/gallery_1.png) no-repeat;
+    width: 90px;
+    height: 90px;
+    position: absolute;
+    text-align: center;
+  }
+  .gallery > .gallery-item_A:nth-child(2) {
+    top: 20px;
+    left: 60px;
+  }
+  .gallery > .gallery-item_A:nth-child(3) {
+    top: 20px;
+    right: 60px;
+  }
+  .gallery > .gallery-item_A:nth-child(4) {
+    bottom: 20px;
+    left: 60px;
+  }
+  .gallery > .gallery-item_A:nth-child(5) {
+    bottom: 20px;
+    right: 60px;
+  }
+
+  .gallery-item_center_B {
+    background: url(/@/assets/images/home-container/configurable/deco_2.png) no-repeat;
+    width: 100%;
+    height: 90%;
+    top: 5%;
+    position: absolute;
+    background-position: center;
+    background-size: auto 100%;
+  }
+  // .gallery .gallery-item__value {
+  //   display: none;
+  // }
+  .gallery > .gallery-item_B {
+    background: url(/@/assets/images/home-container/configurable/deco_3.png) no-repeat;
+    position: absolute;
+    text-align: center;
+    background-position: center;
+    background-size: auto 100%;
+  }
+  .gallery > .gallery-item_B:nth-child(2) {
+    width: 70px;
+    height: 70px;
+    line-height: 70px;
+    top: 20px;
+    left: calc(50% - 70px);
+  }
+  .gallery > .gallery-item_B:nth-child(3) {
+    width: 60px;
+    height: 60px;
+    line-height: 60px;
+    top: 50px;
+    // right: 34%;
+    right: calc(50% - 70px);
+  }
+  .gallery > .gallery-item_B:nth-child(4) {
+    width: 55px;
+    height: 55px;
+    line-height: 55px;
+    bottom: 90px;
+    left: calc(50% - 55px);
+  }
+  .gallery > .gallery-item_B:nth-child(5) {
+    width: 50px;
+    height: 50px;
+    line-height: 50px;
+    bottom: 70px;
+    right: calc(50% - 50px);
+  }
+  .gallery-item_B > .gallery-item__label {
+    display: none;
+  }
+
+  .gallery-item_center_C {
+    background: url(/@/assets/images/home-container/configurable/deco_4.png) no-repeat;
+    width: 100%;
+    height: 100%;
+    // top: 5%;
+    position: absolute;
+    background-position: center;
+    background-size: auto 100%;
+  }
+  .gallery_C {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-around;
+    text-align: center;
+  }
+  .gallery-item_C > .gallery-item__value {
+    font-size: 20px;
+  }
+
+  .gallery_D {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: auto;
+  }
+  .gallery-item_center_D {
+    background: url(/@/assets/images/home-container/configurable/firehome/img-2.png) no-repeat;
+    background-size: auto 100%;
+    width: 100px;
+    height: 100px;
+  }
+  .gallery > .gallery-item_D {
+    background-image: url(/@/assets/images/home-container/configurable/firehome/img-1.png);
+    background-size: auto 100%;
+    width: 213px;
+    height: 87px;
+    align-items: center;
+    text-align: center;
+    line-height: 35px;
+    display: none;
+
+    .gallery-item__value {
+      font-size: 24px;
+    }
+  }
+  .gallery > .gallery-item_D:nth-child(2) {
+    display: block;
+  }
+
+  .gallery-item_center_E {
+    background: url(/@/assets/images/home-container/configurable/dusthome/img-8.png) no-repeat;
+    width: 200px;
+    height: 200px;
+    left: calc(50% - 100px);
+    top: calc(50% - 110px);
+    position: absolute;
+    background-size: 100% auto;
+  }
+  .gallery > .gallery-item_E {
+    background: url(/@/assets/images/home-container/configurable/dusthome/img-9.png) no-repeat;
+    width: 100px;
+    height: 90px;
+    position: absolute;
+    text-align: center;
+    background-size: 100% 100%;
+
+    .gallery-item__label {
+      height: 60px;
+      text-align: center;
+      background-size: 30px 30px;
+      background-position: center top;
+      background-repeat: no-repeat;
+      padding-top: 30px;
+    }
+  }
+  .gallery > .gallery-item_E:nth-child(2) {
+    top: 20px;
+    left: 80px;
+    .gallery-item__label {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/sbzs.png);
+    }
+  }
+  .gallery > .gallery-item_E:nth-child(3) {
+    top: 20px;
+    right: 80px;
+    .gallery-item__label {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/pwkqs.png);
+    }
+  }
+  .gallery > .gallery-item_E:nth-child(4) {
+    bottom: 20px;
+    left: 80px;
+    .gallery-item__label {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/lwsl.png);
+    }
+  }
+  .gallery > .gallery-item_E:nth-child(5) {
+    bottom: 20px;
+    right: 80px;
+    .gallery-item__label {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/dwsl.png);
+    }
+  }
+
+  // .gallery-item_center_F {
+  // }
+  .gallery > .gallery-item_F {
+    width: 120px;
+    height: 65px;
+    position: absolute;
+    text-align: center;
+    padding-left: 20px;
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-image: url(/@/assets/images/home-container/configurable/firehome/img-1.png);
+
+    .gallery-item__value {
+      font-size: 20px;
+    }
+  }
+  .gallery > .gallery-item_F:nth-child(2) {
+    top: 10px;
+    left: 10px;
+    width: 150px;
+    height: 150px;
+    line-height: 150px;
+    padding: 0;
+    background-image: url(/@/assets/images/home-container/configurable/dusthome/img-7.png);
+
+    .gallery-item__label {
+      display: none;
+    }
+  }
+  .gallery > .gallery-item_F:nth-child(3) {
+    top: 10px;
+    left: 160px;
+    padding-top: 5px;
+  }
+  .gallery > .gallery-item_F:nth-child(4) {
+    top: 10px;
+    left: 280px;
+    padding-top: 5px;
+  }
+  .gallery > .gallery-item_F:nth-child(5) {
+    top: 90px;
+    left: 160px;
+    padding-top: 5px;
+  }
+  .gallery > .gallery-item_F:nth-child(6) {
+    top: 90px;
+    left: 280px;
+    padding-top: 5px;
+  }
+
+  .gallery_G {
+    height: 300px;
+  }
+  .gallery > .gallery-item_G {
+    width: 120px;
+    height: 120px;
+    position: absolute;
+    text-align: center;
+    padding-top: 34px;
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    background-position: center;
+    background-image: url(/@/assets/images/home-container/configurable/firehome/img-4.png);
+
+    .gallery-item__value {
+      font-size: 20px;
+    }
+  }
+  .gallery > .gallery-item_G:nth-child(2) {
+    top: calc(50% - 60px);
+    left: calc(50% - 60px);
+  }
+  .gallery > .gallery-item_G:nth-child(3) {
+    top: calc(50% - 60px);
+    left: 60px;
+    transform: scale(0.7);
+  }
+  .gallery > .gallery-item_G:nth-child(4) {
+    top: calc(50% - 60px);
+    right: 60px;
+    transform: scale(0.7);
+  }
+  .gallery > .gallery-item_G:nth-child(5) {
+    top: 15px;
+    left: 30px;
+    transform: scale(0.5);
+  }
+  .gallery > .gallery-item_G:nth-child(6) {
+    bottom: 15px;
+    left: 30px;
+    transform: scale(0.5);
+  }
+  .gallery > .gallery-item_G:nth-child(7) {
+    top: 15px;
+    right: 30px;
+    transform: scale(0.5);
+  }
+  .gallery > .gallery-item_G:nth-child(8) {
+    bottom: 15px;
+    right: 30px;
+    transform: scale(0.5);
+  }
+
+  .gallery-item__value_red {
+    color: red;
+  }
+  .gallery-item__value_orange {
+    color: orange;
+  }
+  .gallery-item__value_yellow {
+    color: yellow;
+  }
+  .gallery-item__value_green {
+    color: yellowgreen;
+  }
+  .gallery-item__value_blue {
+    color: lightblue;
+  }
+  .gallery-item__value_white {
+    color: white;
+  }
+</style>

+ 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


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

@@ -86,6 +86,15 @@
     background-position: center bottom;
     background-repeat: no-repeat;
   }
+  .mini-board_E {
+    width: 30%;
+    height: 200px;
+    padding: 20px 5px;
+    background-image: url('/@/assets/images/home-container/configurable/board_bg_1.png');
+    background-position: center bottom;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+  }
 
   .mini-board__value_A {
     color: @vent-gas-primary-text;
@@ -129,4 +138,31 @@
     line-height: 17px;
     height: 17px;
   }
+  .mini-board__value_E {
+    font-size: 20px;
+    font-weight: bold;
+    line-height: 76px;
+  }
+  .mini-board__label_E {
+    line-height: 17px;
+    height: 80px;
+    padding-top: 60px;
+    background-repeat: no-repeat;
+    background-position: center top;
+  }
+  .mini-board_E:nth-child(1) {
+    .mini-board__label_E {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/hycd.png);
+    }
+  }
+  .mini-board_E:nth-child(2) {
+    .mini-board__label_E {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/dyfl.png);
+    }
+  }
+  .mini-board_E:nth-child(3) {
+    .mini-board__label_E {
+      background-image: url(/@/assets/images/home-container/configurable/dusthome/jdjl.png);
+    }
+  }
 </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';

+ 6 - 11
src/views/vent/home/configurable/components/enhanced/moduleBottom.vue

@@ -1,31 +1,26 @@
 <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>
-        {{ title }}
+        <span @click="clickHandler">{{ title }}</span>
       </div>
       <div class="module-slot">
         <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>
   defineProps<{ title: string; visible: boolean }>();
-  const emit = defineEmits(['close']);
+  const emit = defineEmits(['close', 'click']);
 
   function closeModel() {
     emit('close');
   }
+  function clickHandler() {
+    emit('click');
+  }
 </script>
 <style lang="less" scoped>
   .module-bottom {

+ 6 - 11
src/views/vent/home/configurable/components/enhanced/moduleLeft.vue

@@ -1,31 +1,26 @@
 <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>
-        {{ title }}
+        <span @click="clickHandler">{{ title }}</span>
       </div>
       <div class="module-slot">
         <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>
   defineProps<{ title: string; visible: boolean }>();
-  const emit = defineEmits(['close']);
+  const emit = defineEmits(['close', 'click']);
 
   function closeModel() {
     emit('close');
   }
+  function clickHandler() {
+    emit('click');
+  }
 </script>
 <style lang="less" scoped>
   .module-left {

+ 6 - 11
src/views/vent/home/configurable/components/enhanced/moduleRight.vue

@@ -1,31 +1,26 @@
 <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>
-        {{ title }}
+        <span @click="clickHandler">{{ title }}</span>
       </div>
       <div class="module-slot">
         <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>
   defineProps<{ title: string; visible: boolean }>();
-  const emit = defineEmits(['close']);
+  const emit = defineEmits(['close', 'click']);
 
   function closeModel() {
     emit('close');
   }
+  function clickHandler() {
+    emit('click');
+  }
 </script>
 <style lang="less" scoped>
   .module-right {

+ 16 - 6
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 }}
@@ -41,16 +43,24 @@
   import { MenuItem } from 'ant-design-vue';
 
   const props = defineProps<{
-    headerConfig: Config['moduleData']['header'];
+    moduleData: Config['moduleData'];
     deviceType: Config['deviceType'];
   }>();
 
+  const emit = defineEmits(['select']);
+
   const visible = ref(false);
+  const headerConfig = props.moduleData.header;
   const { selectedDeviceID, selectedDevice, selectedDeviceSlot, selectedDeviceLabel, options, fetchDevices } = useInitDevices(
     props.deviceType,
-    props.headerConfig
+    props.moduleData
   );
 
+  function selectHandler({ key }) {
+    selectedDeviceID.value = key;
+    emit('select', selectedDevice);
+  }
+
   onMounted(() => {
     fetchDevices();
   });

+ 52 - 62
src/views/vent/home/configurable/components/original/moduleBottom.vue

@@ -1,84 +1,74 @@
 <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>
-        {{ title }}
-      </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 }>();
-  const emit = defineEmits(['close']);
+  const emit = defineEmits(['close', 'click']);
 
   function closeModel() {
     emit('close');
   }
+  function clickHandler() {
+    emit('click');
+  }
 </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动画相关

+ 53 - 63
src/views/vent/home/configurable/components/original/moduleLeft.vue

@@ -1,85 +1,75 @@
 <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>
-        {{ title }}
-      </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 }>();
-  const emit = defineEmits(['close']);
+  const emit = defineEmits(['close', 'click']);
 
   function closeModel() {
     emit('close');
   }
+  function clickHandler() {
+    emit('click');
+  }
 </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';

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff