Преглед изворни кода

[Wip 0000] 可配置首页大改造

houzekong пре 8 месеци
родитељ
комит
5d2ac5f815
20 измењених фајлова са 400 додато и 59 уклоњено
  1. 89 7
      src/views/vent/deviceManager/configurationTable/types.ts
  2. 13 17
      src/views/vent/home/configurable/components/enhanced/moduleBottom.vue
  3. 6 11
      src/views/vent/home/configurable/components/enhanced/moduleLeft.vue
  4. 6 11
      src/views/vent/home/configurable/components/enhanced/moduleRight.vue
  5. 36 0
      src/views/vent/home/configurable/components/moduleEnhanced.vue
  6. 0 0
      src/views/vent/home/configurable/deprecated/AirVolumeMonitor.vue
  7. 0 0
      src/views/vent/home/configurable/deprecated/CostumeHeader.vue
  8. 0 0
      src/views/vent/home/configurable/deprecated/DeviceWarning.vue
  9. 0 0
      src/views/vent/home/configurable/deprecated/MiniBoard.vue
  10. 0 0
      src/views/vent/home/configurable/deprecated/MonitorCenter.vue
  11. 0 0
      src/views/vent/home/configurable/deprecated/SubVentilate.vue
  12. 0 0
      src/views/vent/home/configurable/deprecated/Ventilate copy.vue
  13. 38 0
      src/views/vent/home/configurable/deprecated/Ventilate.vue
  14. 0 0
      src/views/vent/home/configurable/deprecated/VentilateAnalysis.vue
  15. 0 0
      src/views/vent/home/configurable/deprecated/VentilateControl.vue
  16. 0 0
      src/views/vent/home/configurable/deprecated/WorkSurface.vue
  17. 0 0
      src/views/vent/home/configurable/deprecated/moduleBasic.vue
  18. 30 9
      src/views/vent/home/configurable/hooks/useInit.ts
  19. 99 0
      src/views/vent/home/configurable/index copy.vue
  20. 83 4
      src/views/vent/home/configurable/index.vue

+ 89 - 7
src/views/vent/deviceManager/configurationTable/types.ts

@@ -5,14 +5,96 @@ export interface Config {
   moduleData: ModuleData;
   showStyle: ShowStyle;
 }
+/**
+ * 模块的配置
+ *
+ * 该配置将描述本模块的基础样式,应该展示哪些内容,应该如何排布主要元素
+ *
+ * 配置中有几项常用的配置,以下是其说明:
+ *
+ * 假设模块依赖的数据为:`{ f1Val: 2555 }`
+ *
+ * `formatter`该配置是用于自定义展示文本的,应配合`prop`使用。
+ *
+ * 使用示例:formatter:`前缀${}后缀`; prop:`f1Val`。则对应的文本将是`前缀f1Val后缀`
+ *
+ */
 export interface ModuleData {
-  header?: Record<string, string>;
-  main?: Record<string, string>;
-  chart?: Record<string, string>;
+  header: {
+    show: boolean;
+    /** 是否展示左侧的选择框 */
+    showSelector: boolean;
+    /** 是否展示右侧插槽 */
+    showSlot: boolean;
+    /** 左侧选择框的配置 */
+    selector: {
+      /** 图标,具体支持的输入种类请联系技术人员 */
+      icon?: string;
+      formatter?: string;
+      prop: string;
+    };
+    /** 右侧插槽的配置 */
+    slot: {
+      /** 图标,具体支持的输入种类请联系技术人员 */
+      icon?: string;
+      formatter?: string;
+      prop: string;
+    };
+  };
+  background: {
+    show: boolean;
+    /** 背景资源的类型 */
+    type: 'image' | 'vedio';
+    /** 背景资源的链接 */
+    link: string;
+  };
+  /** 模块的布局,使用规定的枚举组合为一个数组,代表着从上到下所应展示的元素 */
+  layout: ('board' | 'list' | 'chart')[];
+  /** 展示牌元素 */
+  board?: {
+    /** 展示牌说明内容 */
+    label: string;
+    /** 展示牌预设的背景类型 */
+    type: 'A' | 'B' | 'C' | 'D';
+    /** 展示牌布局,决定是哪部分内容在上方 */
+    layout: 'value-top' | 'label-top';
+    formatter?: string;
+    prop: string;
+  }[];
+  /** 列表元素 */
+  list?: {
+    color: string;
+    /** 列表项说明内容 */
+    label: string;
+    formatter?: string;
+    prop: string;
+  }[];
+  /** 图表元素 */
+  chart?: {
+    /** 图表通用类型,一个类型对应一种图表预设 */
+    type: 'pie' | 'bar' | 'line';
+    /** 读取数据时的基础路径,例如如果图表依赖一个数组,那么该项应设置能读取到该数组的路径。例如:readData.history */
+    readFrom: string;
+    /** 排序依据,该项应配置为`readFrom`指向的数据中的可读项。例如:createTime */
+    sortBy?: string;
+    /** 排序规则,desc降序,asc升序 */
+    order?: 'desc' | 'asc';
+    /** 图表x轴配置(若有),例如:{ prop: 'strInstallPos' } */
+    xAxis?: {
+      formatter?: string;
+      prop: string;
+    }[];
+    /** 图表y轴配置(若有),例如:['风量', '风速'] */
+    yAxis?: string[];
+    /** 图表各系列配置,一个系列应对应一个数据维度,例如:[{ label: '风量', prop: 'f1Val' }] */
+    series: { label: string; prop: string }[];
+  }[];
 }
 export interface ShowStyle {
-  size?: string;
-  version?: string;
-  position?: string;
-  charttype?: string;
+  /** 模块的宽高 */
+  size: string;
+  /** 模块的版本,分新版及旧版,只要有一个模块指定为旧版,那么整个页面风格将变更为旧版 */
+  version: 'original' | 'enhanced';
+  /** 模块的位置,即定位 */
+  position: string;
 }

+ 13 - 17
src/views/vent/home/configurable/components/moduleBottom.vue → src/views/vent/home/configurable/components/enhanced/moduleBottom.vue

@@ -1,34 +1,30 @@
 <template>
-  <div class="module-bottom">
+  <Transition class="module-bottom">
     <!-- 正常展示模块时 -->
-    <div class="module-content">
+    <div v-if="visible" class="module-content">
       <div class="module-content__title__expand">
-        <span class="action-btn" :class="{ 'show-btn': !moduleShown }" @click="toggleModuleShown"></span>
+        <span class="action-btn close-btn" @click="closeModel"></span>
         {{ title }}
       </div>
-      <Transition>
-        <div v-if="moduleShown" class="module-slot">
-          <slot></slot>
-        </div>
-      </Transition>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
     </div>
     <!-- 隐藏模块时 -->
     <!-- <div v-else class="w-100%">
-      <div class="module-content__title__expand">
-        <span class="action-btn" @click="showModel"></span>
+      <div class="module-content__title">
+        <span class="action-btn show-btn" @click="showModel"></span>
         {{ title }}
       </div>
     </div> -->
-  </div>
+  </Transition>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
-
-  defineProps<{ title: string }>();
-  const moduleShown = ref(true);
+  defineProps<{ title: string; visible: boolean }>();
+  const emit = defineEmits(['update:visible']);
 
-  function toggleModuleShown() {
-    moduleShown.value = !moduleShown.value;
+  function closeModel() {
+    emit('update:visible', false);
   }
 </script>
 <style lang="less" scoped>

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

@@ -1,7 +1,7 @@
 <template>
   <Transition class="module-left">
     <!-- 正常展示模块时 -->
-    <div v-if="moduleShown" class="module-content">
+    <div v-if="visible" class="module-content">
       <div class="module-content__title__expand">
         <span class="action-btn close-btn" @click="closeModel"></span>
         {{ title }}
@@ -11,25 +11,20 @@
       </div>
     </div>
     <!-- 隐藏模块时 -->
-    <div v-else class="w-100%">
+    <!-- <div v-else class="w-100%">
       <div class="module-content__title">
         <span class="action-btn show-btn" @click="showModel"></span>
         {{ title }}
       </div>
-    </div>
+    </div> -->
   </Transition>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
-
-  defineProps<{ title: string }>();
-  const moduleShown = ref(true);
+  defineProps<{ title: string; visible: boolean }>();
+  const emit = defineEmits(['update:visible']);
 
   function closeModel() {
-    moduleShown.value = false;
-  }
-  function showModel() {
-    moduleShown.value = true;
+    emit('update:visible', false);
   }
 </script>
 <style lang="less" scoped>

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

@@ -1,7 +1,7 @@
 <template>
   <Transition class="module-right">
     <!-- 正常展示模块时 -->
-    <div v-if="moduleShown" class="module-content">
+    <div v-if="visible" class="module-content">
       <div class="module-content__title__expand">
         <span class="action-btn close-btn" @click="closeModel"></span>
         {{ title }}
@@ -11,25 +11,20 @@
       </div>
     </div>
     <!-- 隐藏模块时 -->
-    <div v-else class="w-100%">
+    <!-- <div v-else class="w-100%">
       <div class="module-content__title">
         <span class="action-btn show-btn" @click="showModel"></span>
         {{ title }}
       </div>
-    </div>
+    </div> -->
   </Transition>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
-
-  defineProps<{ title: string }>();
-  const moduleShown = ref(true);
+  defineProps<{ title: string; visible: boolean }>();
+  const emit = defineEmits(['update:visible']);
 
   function closeModel() {
-    moduleShown.value = false;
-  }
-  function showModel() {
-    moduleShown.value = true;
+    emit('update:visible', false);
   }
 </script>
 <style lang="less" scoped>

+ 36 - 0
src/views/vent/home/configurable/components/moduleEnhanced.vue

@@ -0,0 +1,36 @@
+<template>
+  <component :is="getModuleComponent(showStyle.position)" :style="style" :title="moduleName" @="">
+    <slot></slot>
+  </component>
+</template>
+<script lang="ts" setup>
+  import ModuleLeft from './enhanced/moduleLeft.vue';
+  import ModuleRight from './enhanced/moduleRight.vue';
+  import ModuleBottom from './enhanced/moduleBottom.vue';
+  import { computed } from 'vue';
+  import { ModuleData, ShowStyle } from '../../../deviceManager/configurationTable/types';
+
+  const props = defineProps<{
+    showStyle: ShowStyle;
+    moduleData: ModuleData;
+    moduleName: string;
+  }>();
+
+  const style = computed(() => {
+    return props.showStyle.size + props.showStyle.position;
+  });
+
+  // 根据配置里的定位判断应该使用哪个module组件
+  function getModuleComponent(position) {
+    if (position.includes('left:0')) {
+      return ModuleLeft;
+    }
+    if (position.includes('right:0')) {
+      return ModuleRight;
+    }
+    if (position.includes('bottom:0')) {
+      return ModuleBottom;
+    }
+    return ModuleLeft; // TODO:改为返回旧版的module组件
+  }
+</script>

+ 0 - 0
src/views/vent/home/configurable/components/AirVolumeMonitor.vue → src/views/vent/home/configurable/deprecated/AirVolumeMonitor.vue


+ 0 - 0
src/views/vent/home/configurable/components/CostumeHeader.vue → src/views/vent/home/configurable/deprecated/CostumeHeader.vue


+ 0 - 0
src/views/vent/home/configurable/components/DeviceWarning.vue → src/views/vent/home/configurable/deprecated/DeviceWarning.vue


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


+ 0 - 0
src/views/vent/home/configurable/components/MonitorCenter.vue → src/views/vent/home/configurable/deprecated/MonitorCenter.vue


+ 0 - 0
src/views/vent/home/configurable/components/SubVentilate.vue → src/views/vent/home/configurable/deprecated/SubVentilate.vue


+ 0 - 0
src/views/vent/home/configurable/components/Ventilate.vue → src/views/vent/home/configurable/deprecated/Ventilate copy.vue


+ 38 - 0
src/views/vent/home/configurable/deprecated/Ventilate.vue

@@ -0,0 +1,38 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <ModuleBasic :title="config.moduleName" :version="config.showStyle?.version" :size="config.showStyle?.size" :position="config.showStyle?.position">
+    <CostumeHeader v-model:value="selectedDeviceID" :options="options">
+      <div class="w-200px flex flex-items-center">
+        <RightCircleOutlined class="w-30px" />
+        <div class="flex-grow-1">
+          {{ selectedDevice.strinstallpos }}
+        </div>
+      </div>
+    </CostumeHeader>
+    <div class="flex justify-around mt-10px">
+      <MiniBoard v-for="(label, prop) in config.moduleData?.main" :key="`vhccv-${prop}`" :label="label" :value="get(selectedDevice, prop)" type="C" />
+    </div>
+  </ModuleBasic>
+</template>
+<script lang="ts" setup>
+  import { onMounted } from 'vue';
+  import ModuleBasic from './moduleBasic.vue';
+  import CostumeHeader from './CostumeHeader.vue';
+  import { RightCircleOutlined } from '@ant-design/icons-vue';
+  import MiniBoard from './MiniBoard.vue';
+  import { useInitConfig, useInitDevices } from '../hooks/useInit';
+  import { get } from '../../billboard/utils';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  // 设备类别,是个枚举 TODO: 将手动换为自动获取类别
+  const devicekind = 'fanmain';
+
+  const { config, fetchConfig } = useInitConfig(devicekind);
+  const { options, selectedDevice, selectedDeviceID, fetchDevices } = useInitDevices(devicekind);
+
+  onMounted(() => {
+    fetchConfig();
+    fetchDevices();
+  });
+</script>
+<style scoped></style>

+ 0 - 0
src/views/vent/home/configurable/components/VentilateAnalysis.vue → src/views/vent/home/configurable/deprecated/VentilateAnalysis.vue


+ 0 - 0
src/views/vent/home/configurable/components/VentilateControl.vue → src/views/vent/home/configurable/deprecated/VentilateControl.vue


+ 0 - 0
src/views/vent/home/configurable/components/WorkSurface.vue → src/views/vent/home/configurable/deprecated/WorkSurface.vue


+ 0 - 0
src/views/vent/home/configurable/components/moduleBasic.vue → src/views/vent/home/configurable/deprecated/moduleBasic.vue


+ 30 - 9
src/views/vent/home/configurable/hooks/useInit.ts

@@ -5,19 +5,40 @@ import { Config } from '@/views/vent/deviceManager/configurationTable/types';
 import { getHomeData } from '../configurable.api';
 // import mapComponent from './components/3Dmap/index.vue';
 
-export function useInitConfig(deviceType: string) {
-  function fetchConfig() {
-    cfgList({
-      deviceType,
-    }).then(({ records }) => {
-      config.value = records[0];
+// export function useInitConfig(deviceType: string) {
+//   function fetchConfig() {
+//     cfgList({
+//       deviceType,
+//     }).then(({ records }) => {
+//       config.value = records[0];
+//     });
+//   }
+//   const config = ref<Partial<Config>>({});
+
+//   return {
+//     fetchConfig,
+//     config,
+//   };
+// }
+
+export function useInitConfigs() {
+  const configs = ref<Config[]>([]);
+  const isOriginal = computed(() => {
+    return configs.value.some((c) => {
+      return c.showStyle.version === 'original';
+    });
+  });
+
+  function fetchConfigs() {
+    cfgList({}).then(({ records }) => {
+      configs.value = records;
     });
   }
-  const config = ref<Partial<Config>>({});
 
   return {
-    fetchConfig,
-    config,
+    fetchConfigs,
+    configs,
+    isOriginal,
   };
 }
 

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

@@ -0,0 +1,99 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <div class="company-home">
+    <div class="top-bg">
+      <div class="main-title">{{ mainTitle }}</div>
+    </div>
+    <a-dropdown class="module-dropdown" :trigger="['click']" placement="bottomRight">
+      <a class="ant-dropdown-link" @click.prevent>
+        全矿井通风检测
+        <CaretDownOutlined />
+      </a>
+      <template #overlay>
+        <MonitorCenter />
+      </template>
+    </a-dropdown>
+    <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
+    <SubVentilate />
+    <Ventilate />
+    <VentilateControl />
+    <AirVolumeMonitor />
+    <VentilateAnalysis />
+    <WorkSurface />
+    <DeviceWarning />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue';
+  import SubVentilate from './components/SubVentilate.vue';
+  import Ventilate from './components/Ventilate.vue';
+  import { CaretDownOutlined } from '@ant-design/icons-vue';
+  import VentilateControl from './components/VentilateControl.vue';
+  import AirVolumeMonitor from './components/AirVolumeMonitor.vue';
+  import VentilateAnalysis from './components/VentilateAnalysis.vue';
+  import WorkSurface from './components/WorkSurface.vue';
+  import DeviceWarning from './components/DeviceWarning.vue';
+  import MonitorCenter from './components/MonitorCenter.vue';
+  // import mapComponent from './components/3Dmap/index.vue';
+
+  const mainTitle = ref('智能通风管控系统');
+
+  const moduleCodes = ['fanlocal', 'fanmain', 'vc', 'ar', 'va', 'ws', 'dw'];
+</script>
+<style lang="less" scoped>
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
+
+  .company-home {
+    width: 100%;
+    height: 100%;
+    color: @white;
+    position: relative;
+
+    .top-bg {
+      width: 100%;
+      height: 56px;
+      background: url('@/assets/images/home-container/configurable/main_title_bg.png') no-repeat center;
+      position: absolute;
+      z-index: 1;
+      .main-title {
+        height: 56px;
+        font-family: 'douyuFont';
+        font-size: 20px;
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+
+    .module-left {
+      position: absolute;
+      width: 450px;
+      height: 280px;
+      left: 0;
+    }
+    .module-right {
+      position: absolute;
+      width: 450px;
+      height: 280px;
+      right: 0;
+    }
+    .module-bottom {
+      position: absolute;
+      width: 1000px;
+      height: 280px;
+    }
+    .module-dropdown {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
+  }
+</style>

+ 83 - 4
src/views/vent/home/configurable/index.vue

@@ -4,7 +4,7 @@
     <div class="top-bg">
       <div class="main-title">{{ mainTitle }}</div>
     </div>
-    <a-dropdown class="module-dropdown" :trigger="['click']" placement="bottomRight">
+    <a-dropdown class="module-dropdown" :class="{ 'module-dropdown-original': isOriginal }" :trigger="['click']" placement="bottomRight">
       <a class="ant-dropdown-link" @click.prevent>
         全矿井通风检测
         <CaretDownOutlined />
@@ -14,17 +14,18 @@
       </template>
     </a-dropdown>
     <!-- 采用定位方式以避免出现各个模块隐藏时其他模块下移的问题 -->
-    <SubVentilate />
+
+    <!-- <SubVentilate />
     <Ventilate />
     <VentilateControl />
     <AirVolumeMonitor />
     <VentilateAnalysis />
     <WorkSurface />
-    <DeviceWarning />
+    <DeviceWarning /> -->
   </div>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
+  import { onMounted, ref } from 'vue';
   import SubVentilate from './components/SubVentilate.vue';
   import Ventilate from './components/Ventilate.vue';
   import { CaretDownOutlined } from '@ant-design/icons-vue';
@@ -34,9 +35,78 @@
   import WorkSurface from './components/WorkSurface.vue';
   import DeviceWarning from './components/DeviceWarning.vue';
   import MonitorCenter from './components/MonitorCenter.vue';
+  import { useInitConfigs } from './hooks/useInit';
+  import { Config } from '../../deviceManager/configurationTable/types';
   // import mapComponent from './components/3Dmap/index.vue';
 
   const mainTitle = ref('智能通风管控系统');
+
+  const moduleCodes = ['fanlocal', 'fanmain' /** 'vc', 'ar', 'va', 'ws', 'dw' */];
+
+  const configs = ref<Config[]>([
+    {
+      deviceType: 'fanlocal',
+      moduleName: '测试局扇',
+      pageType: '',
+      moduleData: {
+        header: {
+          show: true,
+          showSelector: true,
+          showSlot: true,
+          selector: {
+            icon: 'SwapOutlined',
+            prop: 'strInstallPos',
+          },
+          slot: {
+            icon: 'SwapOutlined',
+            prop: 'strInstallPos',
+          },
+        },
+        background: {
+          show: false,
+          type: 'vedio',
+          link: '',
+        },
+        layout: ['board', 'chart'],
+        board: [
+          {
+            label: '风量',
+            type: 'A',
+            layout: 'value-top',
+            prop: 'f1Val',
+          },
+          {
+            label: '风速',
+            type: 'A',
+            layout: 'value-top',
+            prop: 'f2Val',
+          },
+        ],
+        chart: [
+          {
+            type: 'line',
+            readFrom: 'readData.history',
+            xAxis: [{ prop: 'strInstallPos' }],
+            yAxis: ['风量', '风速'],
+            series: [
+              { label: '风量', prop: 'f1Val' },
+              { label: '风速', prop: 'f2Val' },
+            ],
+          },
+        ],
+      },
+      showStyle: {
+        size: 'width:450px;height:280px;',
+        version: 'enhanced',
+        position: 'top:60px;left:0;',
+      },
+    },
+  ]);
+  // const { configs, isOriginal, fetchConfigs } = useInitConfigs();
+
+  onMounted(() => {
+    fetchConfigs();
+  });
 </script>
 <style lang="less" scoped>
   @font-face {
@@ -93,5 +163,14 @@
       top: 70px;
       right: 460px;
     }
+    .module-dropdown-original {
+      padding: 10px;
+      background-image: linear-gradient(to bottom, #036886, #072a40);
+      border-bottom: 2px solid #3df6ff;
+      color: #fff;
+      position: absolute;
+      top: 70px;
+      right: 460px;
+    }
   }
 </style>