瀏覽代碼

[Feat 0000] 开发可配置首页新的Tabs模块

houzekong 1 周之前
父節點
當前提交
8012715d12

+ 24 - 0
src/views/vent/deviceManager/configurationTable/types.ts

@@ -87,6 +87,7 @@ export interface ModuleData {
         | 'gallery'
         | 'complex_list'
         | 'gallery_list'
+        | 'tabs'
         | 'blast_delta'
         | 'measure_detail'
         | 'qh_curve'
@@ -103,6 +104,7 @@ export interface ModuleData {
   gallery_list?: ModuleDataGalleryList[];
   chart?: ModuleDataChart[];
   table?: ModuleDataTable[];
+  tabs?: ModuleDataTabs[];
   preset?: ModuleDataPreset[];
   complex_list?: ModuleDataComplexList[];
   /** 如果目前没有数据可以对接,可使用模拟数据先行展示 */
@@ -303,3 +305,25 @@ export interface ModuleDataComplexList extends ReadFrom {
     >;
   }[];
 }
+
+export interface ModuleDataTabs extends ReadFrom {
+  /** 列表预设的背景类型 */
+  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K';
+  /** 是否需要根据数据来决定所展示的项目数量,需要确保 items 至少有一项,且 readFrom 指向数组 */
+  mapFromData?: boolean;
+  /** 核心配置,每个列表项对应一项 */
+  items: {
+    /** 列表项标题,formatter 格式 */
+    title: string;
+    /** 翻译依据,formatter 格式 */
+    trans?: Record<string, string>;
+    contents: Array<
+      {
+        /** 列表项指定颜色,根据类型不同会有各自的样式 */
+        color?: 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'white' | 'lightblue';
+        /** 针对列表项说明的额外信息,部分类型的列表项会使用 */
+        info?: string;
+      } & CommonItem
+    >;
+  }[];
+}

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

@@ -64,6 +64,9 @@
         <template v-if="config.name === 'table'">
           <CustomTable class="content__module text-center overflow-auto" :type="config.type" :columns="config.columns" :data="config.data" />
         </template>
+        <template v-if="config.name === 'tabs'">
+          <CustomTabs class="content__module" :type="config.type" :tab-config="config.items" :overflow="config.overflow" />
+        </template>
         <template v-if="config.name === 'blast_delta'">
           <BlastDelta class="content__module" :pos-monitor="config.data" :canvasSize="{ width: 250, height: 200 }" />
         </template>
@@ -120,6 +123,7 @@
   import BlastDelta from '../../../monitorManager/deviceMonitor/components/device/modal/blastDelta.vue';
   import QHCurve from './preset/QHCurve.vue';
   import MeasureDetail from './preset/MeasureDetail.vue';
+  import CustomTabs from './preset/CustomTabs.vue';
   import AIChat from '/@/components/AIChat/MiniChat.vue';
   import DeviceAlarm from './preset/DeviceAlarm.vue';
   // import FIreWarn from './preset/FIreWarn.vue';
@@ -166,6 +170,7 @@
     const gallery = clone(props.moduleData.gallery) || [];
     const complex_list = clone(props.moduleData.complex_list) || [];
     const gallery_list = clone(props.moduleData.gallery_list) || [];
+    const tabs = clone(props.moduleData.tabs) || [];
     const chart = clone(props.moduleData.chart) || [];
     const table = clone(props.moduleData.table) || [];
     const preset = clone(props.moduleData.preset) || [];
@@ -270,6 +275,51 @@
           });
           break;
         }
+        case 'tabs': {
+          const cfg = tabs.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
+
+          if (cfg.mapFromData) {
+            const firstListItem = cfg.items[0];
+            arr.push({
+              overflow: true,
+              ...item,
+              ...cfg,
+              items: (data || []).map((d) => {
+                return {
+                  title: getFormattedText(d, firstListItem.title, firstListItem.trans),
+                  contents: firstListItem.contents.map((e) => {
+                    return {
+                      ...e,
+                      label: getFormattedText(d, e.label, e.trans),
+                      value: getFormattedText(d, e.value, e.trans),
+                    };
+                  }),
+                };
+              }),
+            });
+          } else {
+            arr.push({
+              overflow: true,
+              ...item,
+              ...cfg,
+              items: cfg.items.map((i) => {
+                return {
+                  title: getFormattedText(data, i.title, i.trans),
+                  contents: i.contents.map((e) => {
+                    return {
+                      ...e,
+                      label: getFormattedText(data, e.label, e.trans),
+                      value: getFormattedText(data, e.value, e.trans),
+                    };
+                  }),
+                };
+              }),
+            });
+          }
+          break;
+        }
         case 'chart': {
           const cfg = chart.shift();
           if (!cfg) break;

+ 15 - 3
src/views/vent/home/configurable/components/detail/CustomList.vue

@@ -6,7 +6,7 @@
     <div :class="`list__image_${type}`"></div>
     <!-- 剩下的部分填充剩余宽度 -->
     <div class="flex-grow" :class="`list__wrapper_${type}`">
-      <div v-for="item in listConfig" :key="item.prop" class="flex items-center" :class="`list-item_${type}`">
+      <div v-for="(item, i) in listConfig" :key="`customlist${i}`" class="flex items-center" :class="`list-item_${type}`">
         <!-- 列表项前面的图标 -->
         <div :class="`list-item__icon_${type}`"></div>
         <!-- 列表项的具体内容填充剩余宽度 -->
@@ -26,7 +26,6 @@
         value: string;
         color: string;
         label: string;
-        prop: string;
         info: string;
       }[];
       /** A B C D E F G */
@@ -348,13 +347,26 @@
     background: unset;
     padding: 0 5px 0 10px;
   }
+  .list__wrapper_K {
+    height: 100%;
+  }
   .list-item__content_K {
     display: flex;
     justify-content: space-between;
     align-items: center;
-    padding: 4px;
+    padding: 5px;
     margin: 4px 0;
     background-image: var(--image-linear-gradient-3);
+
+    .list-item__value {
+      flex-basis: unset;
+    }
+    .list-item__label {
+      flex-basis: unset;
+    }
+    .list-item__info {
+      display: none;
+    }
   }
 
   .list-item__label {

+ 48 - 0
src/views/vent/home/configurable/components/preset/CustomTabs.vue

@@ -0,0 +1,48 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <!-- 基准的列表模块,通过不同的 type 展示不同的样式 -->
+  <div>
+    <BaseTab :tabs="tabs" v-model:id="actived" class="mb-5px" />
+    <CustomList :list-config="listConfig" :type="type" :style="{ height: 'calc(100% - 45px)', overflow: overflow ? 'auto' : 'none' }" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import BaseTab from '/@/views/vent/gas/components/tab/baseTab.vue';
+  import CustomList from '../detail/CustomList.vue';
+  import { computed, ref } from 'vue';
+  import { get } from 'lodash-es';
+
+  const props = withDefaults(
+    defineProps<{
+      tabConfig: {
+        title: string;
+        contents: {
+          value: string;
+          color: string;
+          label: string;
+          info: string;
+        }[];
+      }[];
+      type: string;
+      overflow: boolean;
+    }>(),
+    {
+      listConfig: () => [],
+      type: 'A',
+    }
+  );
+
+  const actived = ref(0);
+
+  const tabs = computed(() => {
+    return props.tabConfig.map((e, id) => {
+      return { name: e.title, id };
+    });
+  });
+
+  const listConfig = computed(() => {
+    return get(props.tabConfig, actived.value).contents;
+  });
+  //   defineEmits(['click']);
+</script>
+<style lang="less" scoped></style>