Sfoglia il codice sorgente

Merge branch 'master' of http://39.97.59.228:8013/hrx/mky-vent-base

bobo04052021@163.com 1 mese fa
parent
commit
2562d90c9b
25 ha cambiato i file con 598 aggiunte e 363 eliminazioni
  1. 1 0
      build/script/buildTag.ts
  2. BIN
      src/assets/images/home-container/configurable/preset/syswind-border-blue.png
  3. BIN
      src/assets/images/home-container/configurable/preset/syswind-border-green.png
  4. BIN
      src/assets/images/home-container/configurable/preset/syswind-icon-blue.png
  5. BIN
      src/assets/images/home-container/configurable/preset/syswind-icon-green.png
  6. 9 0
      src/assets/images/home-container/configurable/preset/syswind-icon-spd.svg
  7. 11 0
      src/assets/images/home-container/configurable/preset/syswind-icon-vol.svg
  8. BIN
      src/assets/images/home-container/configurable/preset/syswind-module-title.png
  9. BIN
      src/assets/images/home-container/configurable/preset/syswind-module.png
  10. BIN
      src/assets/images/home-container/configurable/preset/syswind-space-blue.png
  11. BIN
      src/assets/images/home-container/configurable/preset/syswind-space-green.png
  12. BIN
      src/assets/images/home-container/configurable/preset/syswind-space-red.png
  13. 7 2
      src/layouts/default/header/components/user-dropdown/index.vue
  14. 1 0
      src/locales/lang/en/layout.ts
  15. 1 0
      src/locales/lang/zh-CN/layout.ts
  16. 1 0
      src/views/vent/deviceManager/configurationTable/types.ts
  17. 1 1
      src/views/vent/home/configurable/belt/components/ModuleCommon.vue
  18. 1 9
      src/views/vent/home/configurable/components/ModuleOriginal.vue
  19. 351 345
      src/views/vent/home/configurable/components/content.vue
  20. 1 1
      src/views/vent/home/configurable/components/original/moduleBottom.vue
  21. 1 1
      src/views/vent/home/configurable/components/original/moduleLeft.vue
  22. 1 1
      src/views/vent/home/configurable/components/original/moduleRight.vue
  23. 191 0
      src/views/vent/home/configurable/components/preset/SysWindCard.vue
  24. 19 2
      src/views/vent/home/configurable/configurable.data.ts
  25. 1 1
      src/views/vent/monitorManager/fanLocalVideo/index.vue

+ 1 - 0
build/script/buildTag.ts

@@ -24,6 +24,7 @@ function createTag(params: CreateTagParams) {
       // last commit's SHA
       commit: execSync('git rev-parse --short HEAD').toString().replace('\n', ''),
       buildtime: dayjs().format('YYYY-MM-DD_HH:mm:ss'),
+      version: execSync('npm pkg get version').toString().replace('\n', ''),
     };
     // Ensure that the variable will not be modified
     const evalExp = `

BIN
src/assets/images/home-container/configurable/preset/syswind-border-blue.png


BIN
src/assets/images/home-container/configurable/preset/syswind-border-green.png


BIN
src/assets/images/home-container/configurable/preset/syswind-icon-blue.png


BIN
src/assets/images/home-container/configurable/preset/syswind-icon-green.png


+ 9 - 0
src/assets/images/home-container/configurable/preset/syswind-icon-spd.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="29.905" height="20.273" viewBox="0 0 29.905 20.273">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.295" x2="0.946" y2="0.843" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#83e4ff"/>
+      <stop offset="1" stop-color="#fff"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_57944" data-name="路径 57944" d="M54.586,213.407l.059.123,6.987,15.652a1.311,1.311,0,0,1-2.349,1.161l-.046-.092-1.994-4.469H47.234l-2,4.469a1.311,1.311,0,0,1-2.433-.974l.038-.1,6.987-15.652a2.636,2.636,0,0,1,4.755-.123Zm14.373,13.031a1.311,1.311,0,0,1,.1,2.62l-.1,0H65.025a1.311,1.311,0,0,1-.1-2.62l.1,0ZM52.233,214.592l-.007.007L48.4,223.158h7.667L52.25,214.6a.013.013,0,0,0-.017-.007ZM70.27,219.88a1.311,1.311,0,0,1,.1,2.62l-.1,0H62.4a1.311,1.311,0,0,1-.1-2.62l.1,0Zm-5.246-6.557a1.311,1.311,0,0,1,.1,2.62l-.1,0H59.779a1.311,1.311,0,0,1-.1-2.62l.1,0Z" transform="translate(-42.184 -211.32)" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 11 - 0
src/assets/images/home-container/configurable/preset/syswind-icon-vol.svg

@@ -0,0 +1,11 @@
+<svg id="组_16687" data-name="组 16687" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20.467" height="23.701" viewBox="0 0 20.467 23.701">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.295" x2="0.946" y2="0.843" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#fff"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_57940" data-name="路径 57940" d="M248.889,544m1.436,0h.359a1.269,1.269,0,0,1,1.436,1.436v7.9a1.27,1.27,0,0,1-1.436,1.436h-.359a1.27,1.27,0,0,1-1.436-1.436v-7.9A1.269,1.269,0,0,1,250.325,544Z" transform="translate(-248.889 -531.073)" fill="url(#linear-gradient)"/>
+  <path id="路径_57941" data-name="路径 57941" d="M504.889,288m1.436,0h.359a1.27,1.27,0,0,1,1.436,1.436v16.518a1.27,1.27,0,0,1-1.436,1.436h-.359a1.27,1.27,0,0,1-1.436-1.436V289.436A1.27,1.27,0,0,1,506.325,288Z" transform="translate(-496.271 -283.691)" fill="url(#linear-gradient)"/>
+  <path id="路径_57942" data-name="路径 57942" d="M760.889,160m1.436,0h.359a1.27,1.27,0,0,1,1.436,1.436v20.827a1.27,1.27,0,0,1-1.436,1.436h-.359a1.27,1.27,0,0,1-1.436-1.436V161.436A1.27,1.27,0,0,1,762.325,160Z" transform="translate(-743.654 -160)" fill="url(#linear-gradient)"/>
+</svg>

BIN
src/assets/images/home-container/configurable/preset/syswind-module-title.png


BIN
src/assets/images/home-container/configurable/preset/syswind-module.png


BIN
src/assets/images/home-container/configurable/preset/syswind-space-blue.png


BIN
src/assets/images/home-container/configurable/preset/syswind-space-green.png


BIN
src/assets/images/home-container/configurable/preset/syswind-space-red.png


+ 7 - 2
src/layouts/default/header/components/user-dropdown/index.vue

@@ -25,6 +25,7 @@
             :text="t('layout.header.tooltipLock')"
             icon="ion:lock-closed-outline"
         />-->
+        <MenuItem key="about" :text="t('layout.header.dropdownItemAbout')" icon="ion:information-outline" />
         <MenuItem key="logout" :text="t('layout.header.dropdownItemLoginOut')" icon="ion:power-outline" />
       </Menu>
     </template>
@@ -36,7 +37,7 @@
 </template>
 <script lang="ts">
   // components
-  import { Dropdown, Menu } from 'ant-design-vue';
+  import { Dropdown, Menu, message } from 'ant-design-vue';
 
   import { defineComponent, computed, ref } from 'vue';
 
@@ -60,8 +61,9 @@
   import { removeAuthCache, setAuthCache } from '/@/utils/auth/index';
   import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
   import { getRefPromise } from '/@/utils/index';
+  import { get } from 'lodash-es';
 
-  type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart' | 'modalCache' | 'switchTheme';
+  type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart' | 'modalCache' | 'switchTheme' | 'info';
   const { createMessage } = useMessage();
   export default defineComponent({
     name: 'UserDropdown',
@@ -173,6 +175,9 @@
       // update-end--author:liaozhiyang---date:20230901---for:【QQYUN-6333】空路由问题—首次访问资源太大
       function handleMenuClick(e: { key: MenuEvent }) {
         switch (e.key) {
+          case 'about':
+            message.info(`当前版本:${get(window, '__LAST_PRODUCTION_TAG__.version', '开发模式')}`);
+            break;
           case 'logout':
             handleLoginOut();
             break;

+ 1 - 0
src/locales/lang/en/layout.ts

@@ -3,6 +3,7 @@ export default {
   header: {
     // user dropdown
     dropdownItemDoc: 'Document',
+    dropdownItemAbout: 'About',
     dropdownItemLoginOut: 'Login Out',
     dropdownItemSwitchPassword: 'Password Change',
     dropdownItemSwitchDepart: 'Switch Department',

+ 1 - 0
src/locales/lang/zh-CN/layout.ts

@@ -3,6 +3,7 @@ export default {
   header: {
     // user dropdown
     // dropdownItemDoc: '官网',
+    dropdownItemAbout: '关于',
     dropdownItemLoginOut: '退出系统',
     dropdownItemSwitchPassword: '密码修改',
     // dropdownItemSwitchHome: '切换风格',

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

@@ -112,6 +112,7 @@ export interface ModuleData {
         | 'vehicle_co_analysis'
         | 'sprayCtrl'
         | 'cameraList'
+        | 'sys_wind_card'
         | 'CameraListTest';
       /** 分区大小 */
       basis: string;

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

@@ -142,4 +142,4 @@ watch(
   padding: 0 !important;
   width: 100% !important;
 }
-</style>
+</style>

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

@@ -1,14 +1,6 @@
 <template>
   <!-- 原版模块 -->
-  <component
-    :is="getModuleComponent(showStyle)"
-    :style="style"
-    :title="moduleName"
-    :visible="visible"
-    :class="{ 'cursor-pointer': !!moduleData.to }"
-    @close="$emit('close')"
-    @click="redirectTo"
-  >
+  <component :is="getModuleComponent(showStyle)" :style="style" :title="moduleName" :visible="visible" @close="$emit('close')" @click="redirectTo">
     <slot>
       <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="selectedData = $event" />
       <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />

+ 351 - 345
src/views/vent/home/configurable/components/content.vue

@@ -245,403 +245,409 @@
         <template v-if="config.name === 'person_position'">
           <PersonPositioning class="content__module" :list="config.config.list" :data="config.data" />
         </template>
+        <template v-if="config.name === 'sys_wind_card'">
+          <SysWindCard class="content__module" v-bind="config.config" :data="config.data" />
+        </template>
       </div>
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { computed, ref } from 'vue';
-import { CommonItem, Config } from '../../../deviceManager/configurationTable/types';
-import MiniBoard from './detail/MiniBoard.vue';
-import TimelineList from './detail/TimelineList.vue';
-import TimelineListNew from './detail/TimelineListNew.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 { clone } from 'lodash-es';
-import { getData, getFormattedText } from '../hooks/helper';
-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 SelectCs from './preset/SelectCs.vue';
-import MiniBoardNew from './detail/MiniBoard-New.vue';
-import Partition from './preset/partition.vue';
-import SelectorDualChart from './preset/selectorDualChart.vue';
-import RadioLabel from './preset/radioLabel.vue';
-import ButtonList from './preset/buttonList.vue';
-import NitrogenBtnList from './preset/nitrogenBtnList.vue';
-import cardList from './preset/cardList.vue';
-import generalList from './preset/generalList.vue';
-import GateBoard from '../belt/components/detail/gateBoard.vue';
-import fireGateBoard from '../belt/components/detail/fireGateBoard.vue';
-import PersonPositioning from './preset/PersonPositioning.vue';
-// ==================== 新增皮带巷火灾监测组件 ====================
-import SensorStatusPanel from './belt/SensorStatusPanel.vue';
-import FireSensorAnalysis from './belt/FireSensorAnalysis.vue';
-import WarningResultList from './belt/WarningResultList.vue';
-import VehicleCOAnalysis from './belt/VehicleCOAnalysis.vue';
-// 首页组件
-import CustomListBelt from './belt/CustomListBelt.vue';
-import ComplexListBelt from './belt/ComplexListBelt.vue';
-import ComplexList1Belt from './belt/ComplexList1Belt.vue';
-import CustomTableBelt from './belt/CustomTableBelt.vue';
-import SprayControl from './belt/SprayControl.vue';
-import CameraList from './belt/CameraList.vue';
-import CameraListTest from './belt/CameraListTest.vue';
-const props = defineProps<{
-  data: any;
-  moduleData: Config['moduleData'];
-  chartData: any;
-  activeId?: [String, Number];
-}>();
+  import { computed, defineAsyncComponent, ref } from 'vue';
+  import { CommonItem, Config } from '../../../deviceManager/configurationTable/types';
+  import MiniBoard from './detail/MiniBoard.vue';
+  import TimelineList from './detail/TimelineList.vue';
+  import TimelineListNew from './detail/TimelineListNew.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 { clone } from 'lodash-es';
+  import { getData, getFormattedText } from '../hooks/helper';
+  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 SelectCs from './preset/SelectCs.vue';
+  import MiniBoardNew from './detail/MiniBoard-New.vue';
+  import Partition from './preset/partition.vue';
+  import SelectorDualChart from './preset/selectorDualChart.vue';
+  import RadioLabel from './preset/radioLabel.vue';
+  import ButtonList from './preset/buttonList.vue';
+  import NitrogenBtnList from './preset/nitrogenBtnList.vue';
+  import cardList from './preset/cardList.vue';
+  import generalList from './preset/generalList.vue';
+  import GateBoard from '../belt/components/detail/gateBoard.vue';
+  import fireGateBoard from '../belt/components/detail/fireGateBoard.vue';
+  import PersonPositioning from './preset/PersonPositioning.vue';
+  // ==================== 新增皮带巷火灾监测组件 ====================
+  import SensorStatusPanel from './belt/SensorStatusPanel.vue';
+  import FireSensorAnalysis from './belt/FireSensorAnalysis.vue';
+  import WarningResultList from './belt/WarningResultList.vue';
+  import VehicleCOAnalysis from './belt/VehicleCOAnalysis.vue';
+  // 首页组件
+  import CustomListBelt from './belt/CustomListBelt.vue';
+  import ComplexListBelt from './belt/ComplexListBelt.vue';
+  import ComplexList1Belt from './belt/ComplexList1Belt.vue';
+  import CustomTableBelt from './belt/CustomTableBelt.vue';
+  import SprayControl from './belt/SprayControl.vue';
+  import CameraList from './belt/CameraList.vue';
+  import CameraListTest from './belt/CameraListTest.vue';
 
-const emit = defineEmits<{
-  (e: 'start-spray', data: any): void;
-  (e: 'clickItem', data: any): void;
-  (e: 'emergency-action', action: string, data: any): void;
-}>();
-const handleClickItem = (data: any) => {
-  emit('clickItem', data);
-};
-const { background, layout } = props.moduleData;
+  const SysWindCard = defineAsyncComponent(() => import('./preset/SysWindCard.vue'));
 
-// 获取当原始配置带 items 项时的最终 items 配置
-function getItems(raw: any, items: CommonItem[]) {
-  return items.map((i) => {
-    return {
-      ...i,
-      label: getFormattedText(raw, i.label, i.trans),
-      value: getFormattedText(raw, i.value, i.trans),
-    };
-  });
-}
+  const props = defineProps<{
+    data: any;
+    moduleData: Config['moduleData'];
+    chartData: any;
+    activeId?: [String, Number];
+  }>();
 
-// 获取当 List 组件配置带 items 项时的最终 items 配置
-function getListItems(raw: any, items: CommonItem[], mapFromData?: boolean) {
-  if (mapFromData && Array.isArray(raw)) {
-    return raw.map((data) => {
-      const item = items[0];
+  const emit = defineEmits<{
+    (e: 'start-spray', data: any): void;
+    (e: 'clickItem', data: any): void;
+    (e: 'emergency-action', action: string, data: any): void;
+  }>();
+  const handleClickItem = (data: any) => {
+    emit('clickItem', data);
+  };
+  const { background, layout } = props.moduleData;
+
+  // 获取当原始配置带 items 项时的最终 items 配置
+  function getItems(raw: any, items: CommonItem[]) {
+    return items.map((i) => {
       return {
-        ...item,
-        label: getFormattedText(data, item.label, item.trans),
-        value: getFormattedText(data, item.value, item.trans),
+        ...i,
+        label: getFormattedText(raw, i.label, i.trans),
+        value: getFormattedText(raw, i.value, i.trans),
       };
     });
   }
-  return getItems(raw, items);
-}
 
-/** 根据配置里的 layout 将配置格式化为带 key 的具体配置 */
-const layoutConfig = computed(() => {
-  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 tabs = clone(props.moduleData.tabs) || [];
-  const chart = clone(props.moduleData.chart) || [];
-  const table = clone(props.moduleData.table) || [];
-  const preset = clone(props.moduleData.preset) || [];
-  const partition = clone(props.moduleData.partition) || [];
+  // 获取当 List 组件配置带 items 项时的最终 items 配置
+  function getListItems(raw: any, items: CommonItem[], mapFromData?: boolean) {
+    if (mapFromData && Array.isArray(raw)) {
+      return raw.map((data) => {
+        const item = items[0];
+        return {
+          ...item,
+          label: getFormattedText(data, item.label, item.trans),
+          value: getFormattedText(data, item.value, item.trans),
+        };
+      });
+    }
+    return getItems(raw, items);
+  }
 
-  const mockData = clone(props.chartData) || [];
+  /** 根据配置里的 layout 将配置格式化为带 key 的具体配置 */
+  const layoutConfig = computed(() => {
+    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 tabs = clone(props.moduleData.tabs) || [];
+    const chart = clone(props.moduleData.chart) || [];
+    const table = clone(props.moduleData.table) || [];
+    const preset = clone(props.moduleData.preset) || [];
+    const partition = clone(props.moduleData.partition) || [];
 
-  return layout.items.reduce((arr: any[], item) => {
-    switch (item.name) {
-      case 'board': {
-        const cfg = board.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          overflow: true,
-          ...item,
-          ...cfg,
-          items: getItems(data, cfg.items),
-        });
-        break;
-      }
-      case 'list': {
-        const cfg = list.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          overflow: true,
-          ...item,
-          ...cfg,
-          items: getListItems(data, cfg.items, cfg.mapFromData),
-        });
-        break;
-      }
-      case 'gallery': {
-        const cfg = gallery.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          overflow: true,
-          ...item,
-          ...cfg,
-          items: getItems(data, cfg.items),
-        });
-        break;
-      }
-      case 'complex_list': {
-        const cfg = complex_list.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        if (cfg.mapFromData) {
-          const firstListItem = cfg.items[0];
+    const mockData = clone(props.chartData) || [];
+
+    return layout.items.reduce((arr: any[], item) => {
+      switch (item.name) {
+        case 'board': {
+          const cfg = board.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
           arr.push({
             overflow: true,
             ...item,
             ...cfg,
-            items: (data || []).map((d: any) => {
-              return {
-                title: getFormattedText(d, firstListItem.title, firstListItem.trans),
-                contents: firstListItem.contents.map((e: any) => {
-                  const contentItem = {
-                    ...e,
-                    label: getFormattedText(d, e.label, e.trans),
-                    value: getFormattedText(d, e.value, e.trans),
-                  };
-                  if (cfg.pagetype === 'complex_list1') {
-                    contentItem.id = getFormattedText(d, e.id, e.trans);
-                  }
-                  return contentItem;
-                }),
-              };
-            }),
+            items: getItems(data, cfg.items),
           });
-        } else {
+          break;
+        }
+        case 'list': {
+          const cfg = list.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
           arr.push({
             overflow: true,
             ...item,
             ...cfg,
-            items: cfg.items.map((i: any) => {
-              return {
-                title: getFormattedText(data, i.title, i.trans),
-                contents: i.contents.map((e: any) => {
-                  return {
-                    ...e,
-                    label: getFormattedText(data, e.label, e.trans),
-                    value: getFormattedText(data, e.value, e.trans),
-                  };
-                }),
-              };
-            }),
+            items: getListItems(data, cfg.items, cfg.mapFromData),
           });
+          break;
         }
-        break;
-      }
-      case 'gallery_list': {
-        const cfg = gallery_list.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          overflow: true,
-          ...item,
-          ...cfg,
-          items: getItems(data, cfg.items),
-          galleryItems: getItems(data, cfg.galleryItems),
-        });
-        break;
-      }
-      case 'tabs': {
-        const cfg = tabs.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        if (cfg.mapFromData) {
-          const firstListItem = cfg.items[0];
+        case 'gallery': {
+          const cfg = gallery.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
           arr.push({
             overflow: true,
             ...item,
             ...cfg,
-            items: (data || []).map((d: any) => {
-              return {
-                title: getFormattedText(d, firstListItem.title, firstListItem.trans),
-                contents: firstListItem.contents.map((e: any) => {
-                  return {
-                    ...e,
-                    label: getFormattedText(d, e.label, e.trans),
-                    value: getFormattedText(d, e.value, e.trans),
-                  };
-                }),
-              };
-            }),
+            items: getItems(data, cfg.items),
           });
-        } else {
+          break;
+        }
+        case 'complex_list': {
+          const cfg = complex_list.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
+          if (cfg.mapFromData) {
+            const firstListItem = cfg.items[0];
+            arr.push({
+              overflow: true,
+              ...item,
+              ...cfg,
+              items: (data || []).map((d: any) => {
+                return {
+                  title: getFormattedText(d, firstListItem.title, firstListItem.trans),
+                  contents: firstListItem.contents.map((e: any) => {
+                    const contentItem = {
+                      ...e,
+                      label: getFormattedText(d, e.label, e.trans),
+                      value: getFormattedText(d, e.value, e.trans),
+                    };
+                    if (cfg.pagetype === 'complex_list1') {
+                      contentItem.id = getFormattedText(d, e.id, e.trans);
+                    }
+                    return contentItem;
+                  }),
+                };
+              }),
+            });
+          } else {
+            arr.push({
+              overflow: true,
+              ...item,
+              ...cfg,
+              items: cfg.items.map((i: any) => {
+                return {
+                  title: getFormattedText(data, i.title, i.trans),
+                  contents: i.contents.map((e: any) => {
+                    return {
+                      ...e,
+                      label: getFormattedText(data, e.label, e.trans),
+                      value: getFormattedText(data, e.value, e.trans),
+                    };
+                  }),
+                };
+              }),
+            });
+          }
+          break;
+        }
+        case 'gallery_list': {
+          const cfg = gallery_list.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
           arr.push({
             overflow: true,
             ...item,
             ...cfg,
-            items: cfg.items.map((i: any) => {
-              return {
-                title: getFormattedText(data, i.title, i.trans),
-                contents: i.contents.map((e: any) => {
-                  return {
-                    ...e,
-                    label: getFormattedText(data, e.label, e.trans),
-                    value: getFormattedText(data, e.value, e.trans),
-                  };
-                }),
-              };
-            }),
+            items: getItems(data, cfg.items),
+            galleryItems: getItems(data, cfg.galleryItems),
           });
+          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: any) => {
+                return {
+                  title: getFormattedText(d, firstListItem.title, firstListItem.trans),
+                  contents: firstListItem.contents.map((e: any) => {
+                    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: any) => {
+                return {
+                  title: getFormattedText(data, i.title, i.trans),
+                  contents: i.contents.map((e: any) => {
+                    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;
+          const data = cfg?.type == 'scatter' ? getData(mockData, cfg.readFrom, cfg.parser) : getData(refData, cfg.readFrom, cfg.parser);
+          arr.push({
+            ...item,
+            config: cfg,
+            data,
+          });
+          break;
+        }
+        case 'table': {
+          const cfg = table.shift();
+          if (!cfg) break;
+          // const data = getData(refData, cfg.readFrom, cfg.parser);
+          arr.push({
+            ...cfg,
+            ...item,
+            columns: cfg.columns,
+            data: refData,
+          });
+          break;
+        }
+        case 'partition': {
+          const cfg = partition.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
+          arr.push({
+            overflow: true,
+            ...item,
+            data,
+            ...cfg,
+          });
+          break;
+        }
+        default: {
+          const cfg = preset.shift();
+          if (!cfg) break;
+          const data = getData(refData, cfg.readFrom, cfg.parser);
+          arr.push({
+            ...item,
+            data,
+            config: cfg,
+          });
+          break;
         }
-        break;
-      }
-      case 'chart': {
-        const cfg = chart.shift();
-        if (!cfg) break;
-        const data = cfg?.type == 'scatter' ? getData(mockData, cfg.readFrom, cfg.parser) : getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          ...item,
-          config: cfg,
-          data,
-        });
-        break;
-      }
-      case 'table': {
-        const cfg = table.shift();
-        if (!cfg) break;
-        // const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          ...cfg,
-          ...item,
-          columns: cfg.columns,
-          data: refData,
-        });
-        break;
-      }
-      case 'partition': {
-        const cfg = partition.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          overflow: true,
-          ...item,
-          data,
-          ...cfg,
-        });
-        break;
-      }
-      default: {
-        const cfg = preset.shift();
-        if (!cfg) break;
-        const data = getData(refData, cfg.readFrom, cfg.parser);
-        arr.push({
-          ...item,
-          data,
-          config: cfg,
-        });
-        break;
       }
-    }
-    return arr;
-  }, []);
-});
+      return arr;
+    }, []);
+  });
 </script>
 <style lang="less" scoped>
-@import '@/design/theme.less';
+  @import '@/design/theme.less';
 
-.content {
-  height: calc(100% - 30px);
-  position: relative;
-  display: flex;
-  flex-direction: column;
-  overflow-y: auto;
-  overflow-x: hidden;
-}
-.content__background {
-  width: 100%;
-  // height: 100%;
-  height: calc(100% - 65px);
-  position: absolute;
-  top: 65px;
-  left: 0;
-  z-index: 0;
-  object-fit: fill;
-  padding: 5px;
-  box-sizing: border-box;
-}
-.content__background_1 {
-  width: 100%;
-  height: 100%;
-  position: absolute;
-  top: 0px;
-  left: 0;
-  z-index: 0;
-  object-fit: fill;
-}
+  .content {
+    height: calc(100% - 30px);
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    overflow-y: auto;
+    overflow-x: hidden;
+  }
+  .content__background {
+    width: 100%;
+    // height: 100%;
+    height: calc(100% - 65px);
+    position: absolute;
+    top: 65px;
+    left: 0;
+    z-index: 0;
+    object-fit: fill;
+    padding: 5px;
+    box-sizing: border-box;
+  }
+  .content__background_1 {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0px;
+    left: 0;
+    z-index: 0;
+    object-fit: fill;
+  }
 
-.image__background {
-  width: 35%;
-  height: 61%;
-  left: 30%;
-}
+  .image__background {
+    width: 35%;
+    height: 61%;
+    left: 30%;
+  }
 
-.content__module {
-  width: 100%;
-  height: 100%;
-}
+  .content__module {
+    width: 100%;
+    height: 100%;
+  }
 
-.content__module1 {
-  background: url('@/assets/images/vent/homeNew/databg/4.png');
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-  height: 129px;
-  margin-top: 20%;
-}
+  .content__module1 {
+    background: url('@/assets/images/vent/homeNew/databg/4.png');
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    height: 129px;
+    margin-top: 20%;
+  }
 
-.content__moduleFire {
-  width: 100%;
-  height: 100%;
-  margin-left: -24% !important;
-}
+  .content__moduleFire {
+    width: 100%;
+    height: 100%;
+    margin-left: -24% !important;
+  }
 
-.content__module_dust {
-  background: url('@/assets/images/vent/homeNew/bottomBg.png');
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-  width: 100%;
-  height: 100%;
-}
+  .content__module_dust {
+    background: url('@/assets/images/vent/homeNew/bottomBg.png');
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    width: 100%;
+    height: 100%;
+  }
 
-::-webkit-scrollbar {
-  width: 5px !important;
-}
+  ::-webkit-scrollbar {
+    width: 5px !important;
+  }
 
-::-webkit-scrollbar-thumb {
-  width: 5px !important;
-}
+  ::-webkit-scrollbar-thumb {
+    width: 5px !important;
+  }
 
-:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-  color: #fff;
-}
+  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+    color: #fff;
+  }
 
-:deep(.zxm-select-arrow) {
-  color: #fff;
-}
+  :deep(.zxm-select-arrow) {
+    color: #fff;
+  }
 
-:deep(.zxm-select-selection-item) {
-  color: #fff !important;
-}
+  :deep(.zxm-select-selection-item) {
+    color: #fff !important;
+  }
 
-:deep(.zxm-select-selection-placeholder) {
-  color: #fff !important;
-}
+  :deep(.zxm-select-selection-placeholder) {
+    color: #fff !important;
+  }
 
-:deep(.dialog-overlay) {
-  width: 100%;
-  height: 100%;
-  position: unset;
-  box-shadow: unset;
-}
+  :deep(.dialog-overlay) {
+    width: 100%;
+    height: 100%;
+    position: unset;
+    box-shadow: unset;
+  }
 </style>

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

@@ -1,7 +1,7 @@
 <template>
   <Transition>
     <div v-if="visible" class="module-content">
-      <div v-if="title" class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand cursor-pointer">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>

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

@@ -1,7 +1,7 @@
 <template>
   <Transition>
     <div v-if="visible" class="module-content">
-      <div v-if="title" class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand cursor-pointer">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>

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

@@ -1,7 +1,7 @@
 <template>
   <Transition>
     <div v-if="visible" class="module-content">
-      <div v-if="title" class="module-content__title__expand">
+      <div v-if="title" class="module-content__title__expand cursor-pointer">
         <span class="action-btn close-btn" @click="closeModel"></span>
         <span @click="clickHandler">{{ title }}</span>
       </div>

+ 191 - 0
src/views/vent/home/configurable/components/preset/SysWindCard.vue

@@ -0,0 +1,191 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <!-- 基准的画廊模块,通过不同的 type 展示不同的样式 -->
+  <a-space ref="container" class="syswind__container w-full h-full" wrap :size="30">
+    <div v-for="item in data" :key="item.deviceID" class="syswind__card">
+      <!-- 画廊项的具体内容填充剩余宽度 -->
+      <div class="syswind__card__title font-bold" :title="getFormattedText(item, config.title)">{{ getFormattedText(item, config.title) }}</div>
+      <div class="flex items-center justify-between syswind__card__vol_wrapper">
+        <div class="syswind__card__vol_image"></div>
+        <div>
+          <div
+            v-for="(ctx, idx) in config.volumns"
+            :key="`v${idx}`"
+            class="flex justify-between pl-20px pr-10px syswind__card__vol_space"
+            :class="{ overlimit: isOverLimit(getFormattedText(item, ctx.value), getFormattedText(item, ctx.lowerLimit)) }"
+          >
+            <span>{{ getFormattedText(item, ctx.label) }}</span>
+            <span class="font-bold">{{ getFormattedText(item, ctx.value) }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="flex items-center justify-between syswind__card__spd_wrapper">
+        <div class="syswind__card__spd_image"></div>
+        <div>
+          <div
+            v-for="(ctx, idx) in config.speeds"
+            :key="`s${idx}`"
+            class="flex justify-between pl-20px pr-10px syswind__card__spd_space"
+            :class="{
+              overlimit: isOverLimit(
+                getFormattedText(item, ctx.value),
+                getFormattedText(item, ctx.lowerLimit),
+                getFormattedText(item, ctx.upperLimit)
+              ),
+            }"
+          >
+            <span>{{ getFormattedText(item, ctx.label) }}</span>
+            <span class=".font-bold">{{ getFormattedText(item, ctx.value) }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </a-space>
+</template>
+<script lang="ts" setup>
+  import { inRange } from 'lodash-es';
+  import { getFormattedText } from '../../hooks/helper';
+  import { useEventListener, useScroll } from '@vueuse/core';
+  import { ref } from 'vue';
+
+  // import { get } from 'lodash-es';
+  // import { computed } from 'vue';
+
+  defineProps<{
+    config: {
+      title: string;
+      volumns: { value: string; label: string; lowerLimit: string }[];
+      speeds: { value: string; label: string; lowerLimit: string; upperLimit: string }[];
+      prop: string;
+    };
+    data: any[];
+  }>();
+  //   defineEmits(['click']);
+
+  // 判断val是否在low、high指定的范围内
+  function isOverLimit(val: string, low?: string, high?: string) {
+    const l = low ? parseFloat(low) : -Infinity;
+    const h = high ? parseFloat(high) : Infinity;
+    return !inRange(parseFloat(val), l, h);
+  }
+
+  const container = ref<HTMLElement>();
+  // const { y, directions } = useScroll(container); // 当前滚动位置(响应式)
+
+  // const STEP = 234;
+
+  // useEventListener(
+  //   container,
+  //   'click',
+  //   (event) => {
+  //     console.log('debug rr', event);
+  //     event.preventDefault();
+  //     event.stopPropagation(); // 防止冒泡到外层
+
+  //     const direction = directions.top ? -1 : 1;
+  //     const targetY = y.value + direction * STEP;
+
+  //     container.value?.scrollTo({
+  //       top: targetY,
+  //       behavior: 'smooth',
+  //     });
+  //   },
+  //   { passive: false }
+  // );
+</script>
+<style lang="less" scoped>
+  @import '@/design/theme.less';
+  @import '@/design/theme.less';
+  @{theme-green} {
+    .gallery {
+      --image-gallery_I_2: url(/@/assets/images/themify/deepblue/home-container/configurable/dusthome/gallery_I_2.png);
+      --image-gallery_I_1: url(/@/assets/images/themify/green/home-container/configurable/dusthome/gallery_I_1.png);
+    }
+  }
+  .syswind__container {
+    padding: 10px 30px;
+    // display: flex;
+    // flex-wrap: wrap;
+  }
+
+  .syswind__card {
+    --image-syswind-space-red: url(/@/assets/images/home-container/configurable/preset/syswind-space-red.png);
+    --image-syswind-space-blue: url(/@/assets/images/home-container/configurable/preset/syswind-space-blue.png);
+    --image-syswind-space-green: url(/@/assets/images/home-container/configurable/preset/syswind-space-green.png);
+    --image-syswind-border-blue: url(/@/assets/images/home-container/configurable/preset/syswind-border-blue.png);
+    --image-syswind-border-green: url(/@/assets/images/home-container/configurable/preset/syswind-border-green.png);
+    --image-syswind-module-title: url(/@/assets/images/home-container/configurable/preset/syswind-module-title.png);
+    --image-syswind-module: url(/@/assets/images/home-container/configurable/preset/syswind-module.png);
+    --image-syswind-icon-blue: url(/@/assets/images/home-container/configurable/preset/syswind-icon-blue.png);
+    --image-syswind-icon-green: url(/@/assets/images/home-container/configurable/preset/syswind-icon-green.png);
+    --image-syswind-icon-vol: url(/@/assets/images/home-container/configurable/preset/syswind-icon-vol.svg);
+    --image-syswind-icon-spd: url(/@/assets/images/home-container/configurable/preset/syswind-icon-spd.svg);
+
+    background-image: var(--image-syswind-module);
+    background-repeat: no-repeat;
+    width: 320px;
+    // width: 320px;
+    height: 234px;
+
+    .syswind__card__title {
+      background-image: var(--image-syswind-module-title);
+      width: 250px;
+      height: 24px;
+      padding-left: 10px;
+      padding-right: 20px;
+      font-size: 16px;
+      background-size: 100% 100%;
+      overflow: hidden; /* 隐藏溢出内容 */
+      white-space: nowrap; /* 强制文本不换行 */
+      text-overflow: ellipsis; /* 显示省略号 */
+    }
+
+    .syswind__card__vol_image {
+      background-image: var(--image-syswind-icon-green), var(--image-syswind-icon-vol);
+      background-position: center, center;
+      background-repeat: no-repeat;
+      width: 76px;
+      height: 70px;
+    }
+    .syswind__card__spd_image {
+      background-image: var(--image-syswind-icon-blue), var(--image-syswind-icon-spd);
+      background-position: center, center;
+      background-repeat: no-repeat;
+      width: 76px;
+      height: 70px;
+    }
+    .syswind__card__vol_space {
+      background-image: var(--image-syswind-space-green);
+      background-repeat: no-repeat;
+      background-position: bottom left;
+      width: 208px;
+      height: 30px;
+    }
+    .syswind__card__spd_space {
+      background-image: var(--image-syswind-space-blue);
+      background-repeat: no-repeat;
+      background-position: bottom left;
+      width: 208px;
+      height: 30px;
+    }
+    .syswind__card__vol_wrapper {
+      background-image: var(--image-syswind-border-green);
+      height: 72px;
+      background-position: right center;
+      background-repeat: no-repeat;
+      margin: 10px;
+      padding-right: 10px;
+    }
+    .syswind__card__spd_wrapper {
+      background-image: var(--image-syswind-border-blue);
+      height: 100px;
+      background-position: right center;
+      background-repeat: no-repeat;
+      margin: 10px;
+      padding-right: 10px;
+    }
+    .overlimit {
+      background-image: var(--image-syswind-space-red);
+    }
+  }
+</style>

+ 19 - 2
src/views/vent/home/configurable/configurable.data.ts

@@ -6542,7 +6542,7 @@ export const testConfigVent182: Config[] = [
         direction: 'row',
         items: [
           {
-            name: 'chart',
+            name: 'sys_wind_card',
             basis: '100%',
           },
         ],
@@ -6550,7 +6550,24 @@ export const testConfigVent182: Config[] = [
       board: [],
       list: [],
       table: [],
-      preset: [],
+      preset: [
+        {
+          readFrom: 'sys_wind',
+          config: {
+            title: '${strinstallpos}',
+            volumns: [
+              { label: '风量', value: '${readData.m3}', lowerLimit: '100' },
+              { label: '需风量', value: '100' },
+            ],
+            speeds: [
+              { label: '风速', value: '${readData.va}', lowerLimit: '2', upperLimit: '100' },
+              { label: '规程最大值', value: '100' },
+              { label: '规程最小值', value: '2' },
+            ],
+            prop: 'string',
+          },
+        },
+      ],
       gallery: [],
       complex_list: [],
       gallery_list: [],

+ 1 - 1
src/views/vent/monitorManager/fanLocalVideo/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div></div>
 </template>
-<!-- <!-- <template>
+<!-- <template>
   <div class="screen-container">
     <div class="top-section">
       <div class="system-title">局部风机无人值守演示系统</div>